Merge pull request #5893 from nicolasnoble/objc-finish-handler

For GRPCOperation's, ensure finish _handler can only be called once
pull/5918/head
makdharma 9 years ago
commit a814c7dd9c
  1. 48
      src/objective-c/GRPCClient/GRPCCall.m
  2. 6
      src/objective-c/GRPCClient/private/GRPCWrappedCall.m

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -308,37 +308,30 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
}
- (void)invokeCall {
__weak GRPCCall *weakSelf = self;
[self invokeCallWithHeadersHandler:^(NSDictionary *headers) {
// Response headers received.
GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf.responseHeaders = headers;
[strongSelf startNextRead];
}
self.responseHeaders = headers;
[self startNextRead];
} completionHandler:^(NSError *error, NSDictionary *trailers) {
GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf.responseTrailers = trailers;
if (error) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
if (error.userInfo) {
[userInfo addEntriesFromDictionary:error.userInfo];
}
userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers;
// TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
// called before this one, so an error might end up with trailers but no headers. We
// shouldn't call finishWithError until ater both blocks are called. It is also when this is
// done that we can provide a merged view of response headers and trailers in a thread-safe
// way.
if (strongSelf.responseHeaders) {
userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders;
}
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
self.responseTrailers = trailers;
if (error) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
if (error.userInfo) {
[userInfo addEntriesFromDictionary:error.userInfo];
}
userInfo[kGRPCTrailersKey] = self.responseTrailers;
// TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
// called before this one, so an error might end up with trailers but no headers. We
// shouldn't call finishWithError until ater both blocks are called. It is also when this is
// done that we can provide a merged view of response headers and trailers in a thread-safe
// way.
if (self.responseHeaders) {
userInfo[kGRPCHeadersKey] = self.responseHeaders;
}
[strongSelf finishWithError:error];
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
}
[self finishWithError:error];
}];
// Now that the RPC has been initiated, request writes can start.
@synchronized(_requestWriter) {
@ -377,7 +370,6 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
[strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable
userInfo:@{NSLocalizedDescriptionKey: @"Connectivity lost."}]];
[[GRPCHost hostWithAddress:strongSelf->_host] disconnect];
}
}];
}

@ -1,6 +1,6 @@
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -54,7 +54,9 @@
- (void)finish {
if (_handler) {
_handler();
void(^handler)() = _handler;
_handler = nil;
handler();
}
}
@end

Loading…
Cancel
Save