|
|
|
@ -40,10 +40,14 @@ NSString * const kGRPCHeadersKey = @"io.grpc.HeadersKey"; |
|
|
|
|
NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey"; |
|
|
|
|
static NSMutableDictionary *callFlags; |
|
|
|
|
|
|
|
|
|
static NSString * const kAuthorizationHeader = @"authorization"; |
|
|
|
|
static NSString * const kBearerPrefix = @"Bearer "; |
|
|
|
|
|
|
|
|
|
@interface GRPCCall () <GRXWriteable> |
|
|
|
|
// Make them read-write. |
|
|
|
|
@property(atomic, strong) NSDictionary *responseHeaders; |
|
|
|
|
@property(atomic, strong) NSDictionary *responseTrailers; |
|
|
|
|
@property(atomic) BOOL isWaitingForToken; |
|
|
|
|
@end |
|
|
|
|
|
|
|
|
|
// The following methods of a C gRPC call object aren't reentrant, and thus |
|
|
|
@ -211,7 +215,11 @@ static NSMutableDictionary *callFlags; |
|
|
|
|
[self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain |
|
|
|
|
code:GRPCErrorCodeCancelled |
|
|
|
|
userInfo:@{NSLocalizedDescriptionKey: @"Canceled by app"}]]; |
|
|
|
|
[self cancelCall]; |
|
|
|
|
if (!self.isWaitingForToken) { |
|
|
|
|
[self cancelCall]; |
|
|
|
|
} else { |
|
|
|
|
self.isWaitingForToken = NO; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
- (void)dealloc { |
|
|
|
@ -422,33 +430,55 @@ static NSMutableDictionary *callFlags; |
|
|
|
|
// that the life of the instance is determined by this retain cycle. |
|
|
|
|
_retainSelf = self; |
|
|
|
|
|
|
|
|
|
_responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable |
|
|
|
|
dispatchQueue:_responseQueue]; |
|
|
|
|
|
|
|
|
|
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host serverName:_serverName path:_path]; |
|
|
|
|
NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?"); |
|
|
|
|
|
|
|
|
|
[self sendHeaders:_requestHeaders]; |
|
|
|
|
[self invokeCall]; |
|
|
|
|
|
|
|
|
|
// TODO(jcanizales): Extract this logic somewhere common. |
|
|
|
|
NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:_host]].host; |
|
|
|
|
if (!host) { |
|
|
|
|
// TODO(jcanizales): Check this on init. |
|
|
|
|
[NSException raise:NSInvalidArgumentException format:@"host of %@ is nil", _host]; |
|
|
|
|
} |
|
|
|
|
__weak typeof(self) weakSelf = self; |
|
|
|
|
_connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host]; |
|
|
|
|
void (^handler)() = ^{ |
|
|
|
|
void (^performCall)() = ^{ |
|
|
|
|
typeof(self) strongSelf = weakSelf; |
|
|
|
|
if (strongSelf) { |
|
|
|
|
[strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain |
|
|
|
|
code:GRPCErrorCodeUnavailable |
|
|
|
|
userInfo:@{ NSLocalizedDescriptionKey : @"Connectivity lost." }]]; |
|
|
|
|
strongSelf->_responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable |
|
|
|
|
dispatchQueue:strongSelf->_responseQueue]; |
|
|
|
|
|
|
|
|
|
strongSelf->_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:strongSelf->_host |
|
|
|
|
serverName:strongSelf->_serverName |
|
|
|
|
path:strongSelf->_path]; |
|
|
|
|
NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?"); |
|
|
|
|
|
|
|
|
|
[strongSelf sendHeaders:_requestHeaders]; |
|
|
|
|
[strongSelf invokeCall]; |
|
|
|
|
|
|
|
|
|
// TODO(jcanizales): Extract this logic somewhere common. |
|
|
|
|
NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:strongSelf->_host]].host; |
|
|
|
|
if (!host) { |
|
|
|
|
// TODO(jcanizales): Check this on init. |
|
|
|
|
[NSException raise:NSInvalidArgumentException format:@"host of %@ is nil", strongSelf->_host]; |
|
|
|
|
} |
|
|
|
|
strongSelf->_connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host]; |
|
|
|
|
void (^handler)() = ^{ |
|
|
|
|
typeof(self) strongSelf = weakSelf; |
|
|
|
|
[strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain |
|
|
|
|
code:GRPCErrorCodeUnavailable |
|
|
|
|
userInfo:@{ NSLocalizedDescriptionKey : @"Connectivity lost." }]]; |
|
|
|
|
}; |
|
|
|
|
[_connectivityMonitor handleLossWithHandler:handler |
|
|
|
|
wifiStatusChangeHandler:nil]; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
[_connectivityMonitor handleLossWithHandler:handler |
|
|
|
|
wifiStatusChangeHandler:nil]; |
|
|
|
|
|
|
|
|
|
if (self.oauthToken != nil) { |
|
|
|
|
self.isWaitingForToken = YES; |
|
|
|
|
[self.oauthToken getTokenWithHandler:^(NSString *token){ |
|
|
|
|
typeof(self) strongSelf = weakSelf; |
|
|
|
|
if (strongSelf && strongSelf.isWaitingForToken) { |
|
|
|
|
if (token) { |
|
|
|
|
NSString *t = [kBearerPrefix stringByAppendingString:token]; |
|
|
|
|
strongSelf.requestHeaders[kAuthorizationHeader] = t; |
|
|
|
|
} |
|
|
|
|
performCall(); |
|
|
|
|
strongSelf.isWaitingForToken = NO; |
|
|
|
|
} |
|
|
|
|
}]; |
|
|
|
|
} else { |
|
|
|
|
performCall(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
- (void)setState:(GRXWriterState)newState { |
|
|
|
|