|
|
|
@ -105,6 +105,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
dispatch_queue_t _dispatchQueue; |
|
|
|
|
/** Flags whether call has started. */ |
|
|
|
|
BOOL _started; |
|
|
|
|
/** Flags whether call has been canceled. */ |
|
|
|
|
BOOL _canceled; |
|
|
|
|
/** Flags whether call has been finished. */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
- (instancetype)initWithRequestOptions:(GRPCRequestOptions *)requestOptions |
|
|
|
@ -140,6 +143,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
} |
|
|
|
|
dispatch_set_target_queue(responseHandler.dispatchQueue, _dispatchQueue); |
|
|
|
|
_started = NO; |
|
|
|
|
_canceled = NO; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return self; |
|
|
|
@ -153,9 +157,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
|
|
|
|
|
- (void)start { |
|
|
|
|
dispatch_async(_dispatchQueue, ^{ |
|
|
|
|
if (self->_started) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
NSAssert(!self->_started, @"Call already started."); |
|
|
|
|
NSAssert(!self->_canceled, @"Call already canceled."); |
|
|
|
|
self->_started = YES; |
|
|
|
|
if (!self->_callOptions) { |
|
|
|
|
self->_callOptions = [[GRPCCallOptions alloc] init]; |
|
|
|
@ -184,13 +187,6 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
} |
|
|
|
|
completionHandler:^(NSError *errorOrNil) { |
|
|
|
|
dispatch_async(self->_dispatchQueue, ^{ |
|
|
|
|
if (self->_call) { |
|
|
|
|
// Clean up the request writers. This should have no effect to _call since its |
|
|
|
|
// response writeable is already nullified. |
|
|
|
|
[self->_pipe writesFinishedWithError:nil]; |
|
|
|
|
self->_call = nil; |
|
|
|
|
self->_pipe = nil; |
|
|
|
|
} |
|
|
|
|
if (self->_handler) { |
|
|
|
|
if (!self->_initialMetadataPublished) { |
|
|
|
|
self->_initialMetadataPublished = YES; |
|
|
|
@ -201,6 +197,15 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
// Clean up _handler so that no more responses are reported to the handler. |
|
|
|
|
self->_handler = nil; |
|
|
|
|
} |
|
|
|
|
// Clearing _call must happen *after* dispatching close in order to get trailing |
|
|
|
|
// metadata from _call. |
|
|
|
|
if (self->_call) { |
|
|
|
|
// Clean up the request writers. This should have no effect to _call since its |
|
|
|
|
// response writeable is already nullified. |
|
|
|
|
[self->_pipe writesFinishedWithError:nil]; |
|
|
|
|
self->_call = nil; |
|
|
|
|
self->_pipe = nil; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}]; |
|
|
|
|
[self->_call startWithWriteable:responseWriteable]; |
|
|
|
@ -209,7 +214,7 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
|
|
|
|
|
- (void)cancel { |
|
|
|
|
dispatch_async(_dispatchQueue, ^{ |
|
|
|
|
self->_started = YES; |
|
|
|
|
NSAssert(!self->_canceled, @"Call already canceled."); |
|
|
|
|
if (self->_call) { |
|
|
|
|
[self->_call cancel]; |
|
|
|
|
self->_call = nil; |
|
|
|
@ -237,6 +242,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
|
|
|
|
|
- (void)writeData:(NSData *)data { |
|
|
|
|
dispatch_async(_dispatchQueue, ^{ |
|
|
|
|
NSAssert(!self->_canceled, @"Call arleady canceled."); |
|
|
|
|
NSAssert(!self->_finished, @"Call is half-closed before sending data."); |
|
|
|
|
if (self->_call) { |
|
|
|
|
[self->_pipe writeValue:data]; |
|
|
|
|
} |
|
|
|
@ -245,6 +252,9 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
|
|
|
|
|
- (void)finish { |
|
|
|
|
dispatch_async(_dispatchQueue, ^{ |
|
|
|
|
NSAssert(self->started, @"Call not started."); |
|
|
|
|
NSAssert(!self->_canceled, @"Call arleady canceled."); |
|
|
|
|
NSAssert(!self->_finished, @"Call already half-closed."); |
|
|
|
|
if (self->_call) { |
|
|
|
|
[self->_pipe writesFinishedWithError:nil]; |
|
|
|
|
} |
|
|
|
@ -265,9 +275,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
- (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { |
|
|
|
|
NSDictionary *trailers = _call.responseTrailers; |
|
|
|
|
if ([_handler respondsToSelector:@selector(closedWithTrailingMetadata:error:)]) { |
|
|
|
|
[_handler closedWithTrailingMetadata:trailers error:error]; |
|
|
|
|
[_handler closedWithTrailingMetadata:_call.responseTrailers error:error]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -464,11 +473,8 @@ const char *kCFStreamVarName = "grpc_cfstream"; |
|
|
|
|
|
|
|
|
|
- (void)cancel { |
|
|
|
|
@synchronized(self) { |
|
|
|
|
if (!self.isWaitingForToken) { |
|
|
|
|
[self cancelCall]; |
|
|
|
|
} else { |
|
|
|
|
self.isWaitingForToken = NO; |
|
|
|
|
} |
|
|
|
|
[self cancelCall]; |
|
|
|
|
self.isWaitingForToken = NO; |
|
|
|
|
} |
|
|
|
|
[self |
|
|
|
|
maybeFinishWithError:[NSError |
|
|
|
|