GRPCWrappedCall.m 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. *
  3. * Copyright 2015, Google Inc.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are
  8. * met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above
  13. * copyright notice, this list of conditions and the following disclaimer
  14. * in the documentation and/or other materials provided with the
  15. * distribution.
  16. * * Neither the name of Google Inc. nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. */
  33. #import "GRPCWrappedCall.h"
  34. #import <Foundation/Foundation.h>
  35. #include <grpc/byte_buffer.h>
  36. #include <grpc/grpc.h>
  37. #include <grpc/support/alloc.h>
  38. #import "GRPCCompletionQueue.h"
  39. #import "GRPCHost.h"
  40. #import "NSData+GRPC.h"
  41. #import "NSDictionary+GRPC.h"
  42. #import "NSError+GRPC.h"
  43. @implementation GRPCOperation {
  44. @protected
  45. // Most operation subclasses don't set any flags in the grpc_op, and rely on
  46. // the flag member being initialized to zero.
  47. grpc_op _op;
  48. void (^_handler)();
  49. }
  50. - (void)finish {
  51. if (_handler) {
  52. void (^handler)() = _handler;
  53. _handler = nil;
  54. handler();
  55. }
  56. }
  57. @end
  58. @implementation GRPCOpSendMetadata
  59. - (instancetype)init {
  60. return [self initWithMetadata:nil flags:0 handler:nil];
  61. }
  62. - (instancetype)initWithMetadata:(NSDictionary *)metadata
  63. handler:(void (^)())handler {
  64. return [self initWithMetadata:metadata flags:0 handler:handler];
  65. }
  66. - (instancetype)initWithMetadata:(NSDictionary *)metadata
  67. flags:(uint32_t)flags
  68. handler:(void (^)())handler {
  69. if (self = [super init]) {
  70. _op.op = GRPC_OP_SEND_INITIAL_METADATA;
  71. _op.data.send_initial_metadata.count = metadata.count;
  72. _op.data.send_initial_metadata.metadata = metadata.grpc_metadataArray;
  73. _op.data.send_initial_metadata.maybe_compression_level.is_set = false;
  74. _op.data.send_initial_metadata.maybe_compression_level.level = 0;
  75. _op.flags = flags;
  76. _handler = handler;
  77. }
  78. return self;
  79. }
  80. - (void)dealloc {
  81. gpr_free(_op.data.send_initial_metadata.metadata);
  82. }
  83. @end
  84. @implementation GRPCOpSendMessage
  85. - (instancetype)init {
  86. return [self initWithMessage:nil handler:nil];
  87. }
  88. - (instancetype)initWithMessage:(NSData *)message handler:(void (^)())handler {
  89. if (!message) {
  90. [NSException raise:NSInvalidArgumentException
  91. format:@"message cannot be nil"];
  92. }
  93. if (self = [super init]) {
  94. _op.op = GRPC_OP_SEND_MESSAGE;
  95. _op.data.send_message = message.grpc_byteBuffer;
  96. _handler = handler;
  97. }
  98. return self;
  99. }
  100. - (void)dealloc {
  101. gpr_free(_op.data.send_message);
  102. }
  103. @end
  104. @implementation GRPCOpSendClose
  105. - (instancetype)init {
  106. return [self initWithHandler:nil];
  107. }
  108. - (instancetype)initWithHandler:(void (^)())handler {
  109. if (self = [super init]) {
  110. _op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
  111. _handler = handler;
  112. }
  113. return self;
  114. }
  115. @end
  116. @implementation GRPCOpRecvMetadata {
  117. grpc_metadata_array _headers;
  118. }
  119. - (instancetype)init {
  120. return [self initWithHandler:nil];
  121. }
  122. - (instancetype)initWithHandler:(void (^)(NSDictionary *))handler {
  123. if (self = [super init]) {
  124. _op.op = GRPC_OP_RECV_INITIAL_METADATA;
  125. grpc_metadata_array_init(&_headers);
  126. _op.data.recv_initial_metadata = &_headers;
  127. if (handler) {
  128. // Prevent reference cycle with _handler
  129. __weak typeof(self) weakSelf = self;
  130. _handler = ^{
  131. __strong typeof(self) strongSelf = weakSelf;
  132. NSDictionary *metadata = [NSDictionary
  133. grpc_dictionaryFromMetadataArray:strongSelf->_headers];
  134. handler(metadata);
  135. };
  136. }
  137. }
  138. return self;
  139. }
  140. - (void)dealloc {
  141. grpc_metadata_array_destroy(&_headers);
  142. }
  143. @end
  144. @implementation GRPCOpRecvMessage {
  145. grpc_byte_buffer *_receivedMessage;
  146. }
  147. - (instancetype)init {
  148. return [self initWithHandler:nil];
  149. }
  150. - (instancetype)initWithHandler:(void (^)(grpc_byte_buffer *))handler {
  151. if (self = [super init]) {
  152. _op.op = GRPC_OP_RECV_MESSAGE;
  153. _op.data.recv_message = &_receivedMessage;
  154. if (handler) {
  155. // Prevent reference cycle with _handler
  156. __weak typeof(self) weakSelf = self;
  157. _handler = ^{
  158. __strong typeof(self) strongSelf = weakSelf;
  159. handler(strongSelf->_receivedMessage);
  160. };
  161. }
  162. }
  163. return self;
  164. }
  165. @end
  166. @implementation GRPCOpRecvStatus {
  167. grpc_status_code _statusCode;
  168. char *_details;
  169. size_t _detailsCapacity;
  170. grpc_metadata_array _trailers;
  171. }
  172. - (instancetype)init {
  173. return [self initWithHandler:nil];
  174. }
  175. - (instancetype)initWithHandler:(void (^)(NSError *, NSDictionary *))handler {
  176. if (self = [super init]) {
  177. _op.op = GRPC_OP_RECV_STATUS_ON_CLIENT;
  178. _op.data.recv_status_on_client.status = &_statusCode;
  179. _op.data.recv_status_on_client.status_details = &_details;
  180. _op.data.recv_status_on_client.status_details_capacity = &_detailsCapacity;
  181. grpc_metadata_array_init(&_trailers);
  182. _op.data.recv_status_on_client.trailing_metadata = &_trailers;
  183. if (handler) {
  184. // Prevent reference cycle with _handler
  185. __weak typeof(self) weakSelf = self;
  186. _handler = ^{
  187. __strong typeof(self) strongSelf = weakSelf;
  188. NSError *error =
  189. [NSError grpc_errorFromStatusCode:strongSelf->_statusCode
  190. details:strongSelf->_details];
  191. NSDictionary *trailers = [NSDictionary
  192. grpc_dictionaryFromMetadataArray:strongSelf->_trailers];
  193. handler(error, trailers);
  194. };
  195. }
  196. }
  197. return self;
  198. }
  199. - (void)dealloc {
  200. grpc_metadata_array_destroy(&_trailers);
  201. gpr_free(_details);
  202. }
  203. @end
  204. #pragma mark GRPCWrappedCall
  205. @implementation GRPCWrappedCall {
  206. GRPCCompletionQueue *_queue;
  207. grpc_call *_call;
  208. }
  209. - (instancetype)init {
  210. return [self initWithHost:nil path:nil];
  211. }
  212. - (instancetype)initWithHost:(NSString *)host path:(NSString *)path {
  213. if (!path || !host) {
  214. [NSException raise:NSInvalidArgumentException
  215. format:@"path and host cannot be nil."];
  216. }
  217. if (self = [super init]) {
  218. // Each completion queue consumes one thread. There's a trade to be made
  219. // between creating and consuming too many threads and having contention of
  220. // multiple calls in a single completion queue. Currently we use a singleton
  221. // queue.
  222. _queue = [GRPCCompletionQueue completionQueue];
  223. _call = [[GRPCHost hostWithAddress:host] unmanagedCallWithPath:path
  224. completionQueue:_queue];
  225. if (_call == NULL) {
  226. return nil;
  227. }
  228. }
  229. return self;
  230. }
  231. - (void)startBatchWithOperations:(NSArray *)operations {
  232. [self startBatchWithOperations:operations errorHandler:nil];
  233. }
  234. - (void)startBatchWithOperations:(NSArray *)operations
  235. errorHandler:(void (^)())errorHandler {
  236. size_t nops = operations.count;
  237. grpc_op *ops_array = gpr_malloc(nops * sizeof(grpc_op));
  238. size_t i = 0;
  239. for (GRPCOperation *operation in operations) {
  240. ops_array[i++] = operation.op;
  241. }
  242. grpc_call_error error = grpc_call_start_batch(
  243. _call, ops_array, nops, (__bridge_retained void *)(^(bool success) {
  244. if (!success) {
  245. if (errorHandler) {
  246. errorHandler();
  247. } else {
  248. return;
  249. }
  250. }
  251. for (GRPCOperation *operation in operations) {
  252. [operation finish];
  253. }
  254. }),
  255. NULL);
  256. gpr_free(ops_array);
  257. if (error != GRPC_CALL_OK) {
  258. [NSException raise:NSInternalInconsistencyException
  259. format:@"A precondition for calling grpc_call_start_batch "
  260. @"wasn't met. Error %i",
  261. error];
  262. }
  263. }
  264. - (void)cancel {
  265. grpc_call_cancel(_call, NULL);
  266. }
  267. - (void)dealloc {
  268. grpc_call_destroy(_call);
  269. }
  270. @end