Add protocol and corresponding changes in GRPCClient

pull/11832/head
Muxi Yan 7 years ago
parent f2e15655bc
commit 34949db47f
  1. 15
      src/objective-c/GRPCClient/GRPCCall.h
  2. 52
      src/objective-c/GRPCClient/GRPCCall.m
  3. 1
      src/objective-c/GRPCClient/private/GRPCRequestHeaders.m

@ -139,6 +139,13 @@ typedef NS_ENUM(NSUInteger, GRPCErrorCode) {
GRPCErrorCodeDataLoss = 15, GRPCErrorCodeDataLoss = 15,
}; };
/**
* The protocol of an OAuth2 token object from which GRPCCall can acquire a token.
*/
@protocol GRPCAuthorizationProtocol
- (void)getTokenWithHandler:(void (^)(NSString *token))hander;
@end
/** /**
* Safety remark of a gRPC method as defined in RFC 2616 Section 9.1 * Safety remark of a gRPC method as defined in RFC 2616 Section 9.1
*/ */
@ -215,6 +222,14 @@ extern id const kGRPCTrailersKey;
*/ */
@property(atomic, readonly) NSDictionary *responseTrailers; @property(atomic, readonly) NSDictionary *responseTrailers;
/**
* The authorization token object to be used when starting the call. If the value is set to nil, no
* oauth authentication will be used.
*
* Not compatible with property oauth2AccessToken in GRPCCall (OAuth2). Do not use both at the same time.
*/
@property(atomic, strong) id<GRPCAuthorizationProtocol> oauthToken;
/** /**
* The request writer has to write NSData objects into the provided Writeable. The server will * The request writer has to write NSData objects into the provided Writeable. The server will
* receive each of those separately and in order as distinct messages. * receive each of those separately and in order as distinct messages.

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

@ -103,7 +103,6 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
} }
- (void)setObject:(id)obj forKey:(NSString *)key { - (void)setObject:(id)obj forKey:(NSString *)key {
[self checkCallIsNotStarted];
CheckIsNonNilASCII(@"Header name", key); CheckIsNonNilASCII(@"Header name", key);
key = key.lowercaseString; key = key.lowercaseString;
CheckKeyValuePairIsValid(key, obj); CheckKeyValuePairIsValid(key, obj);

Loading…
Cancel
Save