|  | @@ -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 {
 |