1/* 2 * 3 * Copyright 2019 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19#import "ProtoRPCLegacy.h" 20 21#import "ProtoMethod.h" 22 23#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 24#import <Protobuf/GPBProtocolBuffers.h> 25#else 26#import <GPBProtocolBuffers.h> 27#endif 28#import <GRPCClient/GRPCCall.h> 29#import <RxLibrary/GRXWriteable.h> 30#import <RxLibrary/GRXWriter+Transformations.h> 31 32#pragma clang diagnostic push 33#pragma clang diagnostic ignored "-Wdeprecated-implementations" 34@implementation ProtoRPC { 35#pragma clang diagnostic pop 36 id<GRXWriteable> _responseWriteable; 37} 38 39#pragma clang diagnostic push 40#pragma clang diagnostic ignored "-Wobjc-designated-initializers" 41- (instancetype)initWithHost:(NSString *)host 42 path:(NSString *)path 43 requestsWriter:(GRXWriter *)requestsWriter { 44 [NSException raise:NSInvalidArgumentException 45 format:@"Please use ProtoRPC's designated initializer instead."]; 46 return nil; 47} 48#pragma clang diagnostic pop 49 50// Designated initializer 51- (instancetype)initWithHost:(NSString *)host 52 method:(GRPCProtoMethod *)method 53 requestsWriter:(GRXWriter *)requestsWriter 54 responseClass:(Class)responseClass 55 responsesWriteable:(id<GRXWriteable>)responsesWriteable { 56 // Because we can't tell the type system to constrain the class, we need to check at runtime: 57 if (![responseClass respondsToSelector:@selector(parseFromData:error:)]) { 58 [NSException raise:NSInvalidArgumentException 59 format:@"A protobuf class to parse the responses must be provided."]; 60 } 61 // A writer that serializes the proto messages to send. 62 GRXWriter *bytesWriter = [requestsWriter map:^id(GPBMessage *proto) { 63 if (![proto isKindOfClass:[GPBMessage class]]) { 64 [NSException raise:NSInvalidArgumentException 65 format:@"Request must be a proto message: %@", proto]; 66 } 67 return [proto data]; 68 }]; 69 if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) { 70 __weak ProtoRPC *weakSelf = self; 71 72 // A writeable that parses the proto messages received. 73 _responseWriteable = [[GRXWriteable alloc] 74 initWithValueHandler:^(NSData *value) { 75 // TODO(jcanizales): This is done in the main thread, and needs to happen in another 76 // thread. 77 NSError *error = nil; 78 id parsed = [responseClass parseFromData:value error:&error]; 79 if (parsed) { 80 [responsesWriteable writeValue:parsed]; 81 } else { 82 [weakSelf finishWithError:ErrorForBadProto(value, responseClass, error)]; 83 } 84 } 85 completionHandler:^(NSError *errorOrNil) { 86 [responsesWriteable writesFinishedWithError:errorOrNil]; 87 }]; 88 } 89 return self; 90} 91 92- (void)start { 93 [self startWithWriteable:_responseWriteable]; 94} 95 96- (void)startWithWriteable:(id<GRXWriteable>)writeable { 97 [super startWithWriteable:writeable]; 98 // Break retain cycles. 99 _responseWriteable = nil; 100} 101@end 102 103@implementation GRPCProtoCall 104 105@end 106