|
|
@ -37,6 +37,22 @@ |
|
|
|
#import <RxLibrary/GRXWriteable.h> |
|
|
|
#import <RxLibrary/GRXWriteable.h> |
|
|
|
#import <RxLibrary/GRXWriter+Transformations.h> |
|
|
|
#import <RxLibrary/GRXWriter+Transformations.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) { |
|
|
|
|
|
|
|
NSDictionary *info = @{ |
|
|
|
|
|
|
|
NSLocalizedDescriptionKey: @"Unable to parse response from the server", |
|
|
|
|
|
|
|
NSLocalizedRecoverySuggestionErrorKey: @"If this RPC is idempotent, retry " |
|
|
|
|
|
|
|
@"with exponential backoff. Otherwise, query the server status before " |
|
|
|
|
|
|
|
@"retrying.", |
|
|
|
|
|
|
|
NSUnderlyingErrorKey: parsingError, |
|
|
|
|
|
|
|
@"Expected class": expectedClass, |
|
|
|
|
|
|
|
@"Received value": proto, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
// TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public. |
|
|
|
|
|
|
|
return [NSError errorWithDomain:@"io.grpc" |
|
|
|
|
|
|
|
code:13 |
|
|
|
|
|
|
|
userInfo:info]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@implementation ProtoRPC { |
|
|
|
@implementation ProtoRPC { |
|
|
|
id<GRXWriteable> _responseWriteable; |
|
|
|
id<GRXWriteable> _responseWriteable; |
|
|
|
} |
|
|
|
} |
|
|
@ -65,14 +81,25 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
// A writer that serializes the proto messages to send. |
|
|
|
// A writer that serializes the proto messages to send. |
|
|
|
GRXWriter *bytesWriter = [requestsWriter map:^id(GPBMessage *proto) { |
|
|
|
GRXWriter *bytesWriter = [requestsWriter map:^id(GPBMessage *proto) { |
|
|
|
// TODO(jcanizales): Fail with an understandable error message if the requestsWriter isn't |
|
|
|
if (![proto isKindOfClass:GPBMessage.class]) { |
|
|
|
// sending GPBMessages. |
|
|
|
[NSException raise:NSInvalidArgumentException |
|
|
|
|
|
|
|
format:@"Request must be a proto message: %@", proto]; |
|
|
|
|
|
|
|
} |
|
|
|
return [proto data]; |
|
|
|
return [proto data]; |
|
|
|
}]; |
|
|
|
}]; |
|
|
|
if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) { |
|
|
|
if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) { |
|
|
|
|
|
|
|
__weak ProtoRPC *weakSelf = self; |
|
|
|
|
|
|
|
|
|
|
|
// A writeable that parses the proto messages received. |
|
|
|
// A writeable that parses the proto messages received. |
|
|
|
_responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { |
|
|
|
_responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { |
|
|
|
[responsesWriteable writeValue:[responseClass parseFromData:value error:NULL]]; |
|
|
|
// TODO(jcanizales): This is done in the main thread, and needs to happen in another thread. |
|
|
|
|
|
|
|
NSError *error = nil; |
|
|
|
|
|
|
|
id parsed = [responseClass parseFromData:value error:&error]; |
|
|
|
|
|
|
|
if (parsed) { |
|
|
|
|
|
|
|
[responsesWriteable writeValue:parsed]; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
[weakSelf finishWithError:ErrorForBadProto(value, responseClass, error)]; |
|
|
|
|
|
|
|
} |
|
|
|
} completionHandler:^(NSError *errorOrNil) { |
|
|
|
} completionHandler:^(NSError *errorOrNil) { |
|
|
|
[responsesWriteable writesFinishedWithError:errorOrNil]; |
|
|
|
[responsesWriteable writesFinishedWithError:errorOrNil]; |
|
|
|
}]; |
|
|
|
}]; |
|
|
|