blob: af33a00c1fedf12439477fc7b4040048c4016dcd [file] [log] [blame]
murgatroid9930b7d4e2015-04-24 10:36:43 -07001/*
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
murgatroid9930b7d4e2015-04-24 10:36:43 -070034#import "GRPCWrappedCall.h"
murgatroid9969927d62015-04-24 13:32:48 -070035#import <Foundation/Foundation.h>
36#include <grpc/grpc.h>
37#include <grpc/byte_buffer.h>
38#include <grpc/support/alloc.h>
murgatroid9930b7d4e2015-04-24 10:36:43 -070039#import "GRPCCompletionQueue.h"
40#import "NSDictionary+GRPC.h"
41#import "NSData+GRPC.h"
42#import "NSError+GRPC.h"
murgatroid9930b7d4e2015-04-24 10:36:43 -070043
murgatroid9954e93d42015-04-27 09:29:49 -070044@implementation GRPCOpSendMetadata{
45 void(^_handler)(void);
46 grpc_metadata *_send_metadata;
47 size_t _count;
48}
49
50- (instancetype)init {
51 return [self initWithMetadata:nil handler:nil];
52}
53
54- (instancetype)initWithMetadata:(NSDictionary *)metadata handler:(void (^)(void))handler {
55 if (self = [super init]) {
56 if (metadata) {
57 [metadata grpc_getMetadataArray:&_send_metadata];
58 _count = metadata.count;
59 } else {
60 _send_metadata = NULL;
61 _count = 0;
62 }
63 _handler = handler;
64 }
65 return self;
66}
67
68- (void)getOp:(grpc_op *)op {
69 op->op = GRPC_OP_SEND_INITIAL_METADATA;
70 op->data.send_initial_metadata.count = _count;
71}
72
73- (void (^)(void))opProcessor {
74 return ^{
75 gpr_free(_send_metadata);
76 if (_handler) {
77 _handler();
78 }
79 };
80}
81
82@end
83
84@implementation GRPCOpSendMessage{
85 void(^_handler)(void);
86 grpc_byte_buffer *_byte_buffer;
87}
88
89- (instancetype)init {
90 return [self initWithMessage:nil handler:nil];
91}
92
93- (instancetype)initWithMessage:(NSData *)message handler:(void (^)(void))handler {
94 if (!message) {
95 [NSException raise:NSInvalidArgumentException format:@"message cannot be null"];
96 }
97 if (self = [super init]) {
98 _byte_buffer = [message grpc_byteBuffer];
99 _handler = handler;
100 }
101 return self;
102}
103
104- (void)getOp:(grpc_op *)op {
105 op->op = GRPC_OP_SEND_MESSAGE;
106 op->data.send_message = _byte_buffer;
107}
108
109- (void (^)(void))opProcessor {
110 return ^{
111 gpr_free(_byte_buffer);
112 if (_handler) {
113 _handler();
114 }
115 };
116}
117
118@end
119
120@implementation GRPCOpSendClose{
121 void(^_handler)(void);
122}
123
124- (instancetype)init {
125 return [self initWithHandler:nil];
126}
127
128- (instancetype)initWithHandler:(void (^)(void))handler {
129 if (self = [super init]) {
130 _handler = handler;
131 }
132 return self;
133}
134
135- (void)getOp:(grpc_op *)op {
136 op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
137}
138
139- (void (^)(void))opProcessor {
140 return ^{
141 if (_handler) {
142 _handler();
143 }
144 };
145}
146
147@end
148
149@implementation GRPCOpRecvMetadata{
150 void(^_handler)(NSDictionary *);
151 grpc_metadata_array *_recv_initial_metadata;
152}
153
154- (instancetype) init {
155 return [self initWithHandler:nil];
156}
157
158- (instancetype) initWithHandler:(void (^)(NSDictionary *))handler {
159 if (self = [super init]) {
160 _handler = handler;
161 _recv_initial_metadata = gpr_malloc(sizeof(grpc_metadata_array));
162 grpc_metadata_array_init(_recv_initial_metadata);
163 }
164 return self;
165}
166
167- (void)getOp:(grpc_op *)op {
168 op->op = GRPC_OP_RECV_INITIAL_METADATA;
169 op->data.recv_initial_metadata = _recv_initial_metadata;
170}
171
172- (void (^)(void))opProcessor {
173 return ^{
174 NSDictionary *metadata = [NSDictionary grpc_dictionaryFromMetadata:_recv_initial_metadata->metadata count:_recv_initial_metadata->count];
175 grpc_metadata_array_destroy(_recv_initial_metadata);
176 if (_handler) {
177 _handler(metadata);
178 }
179 };
180}
181
182@end
183
184@implementation GRPCOpRecvMessage{
185 void(^_handler)(NSData *);
186 grpc_byte_buffer **_recv_message;
187}
188
189- (instancetype)init {
190 return [self initWithHandler:nil];
191}
192
193- (instancetype)initWithHandler:(void (^)(NSData *))handler {
194 if (self = [super init]) {
195 _handler = handler;
196 _recv_message = gpr_malloc(sizeof(grpc_byte_buffer*));
197 }
198 return self;
199}
200
201- (void)getOp:(grpc_op *)op {
202 op->op = GRPC_OP_RECV_MESSAGE;
203 op->data.recv_message = _recv_message;
204}
205
206- (void (^)(void))opProcessor {
207 return ^{
208 NSData *message = [NSData grpc_dataWithByteBuffer:*_recv_message];
209 grpc_byte_buffer_destroy(*_recv_message);
210 gpr_free(_recv_message);
211 if (_handler) {
212 _handler(message);
213 }
214 };
215}
216
217@end
218
219@implementation GRPCOpRecvStatus{
220 void(^_handler)(NSError *);
221 grpc_status_code *_code;
222 char **_details;
223 size_t *_details_capacity;
224 grpc_metadata_array *_recv_trailing_metadata;
225}
226
227- (instancetype) init {
228 return [self initWithHandler:nil];
229}
230
231- (instancetype) initWithHandler:(void (^)(NSError *))handler {
232 if (self = [super init]) {
233 _handler = handler;
234 _code = gpr_malloc(sizeof(grpc_status_code));
235 _details = gpr_malloc(sizeof(char*));
236 _details_capacity = gpr_malloc(sizeof(size_t));
237 *_details_capacity = 0;
238 _recv_trailing_metadata = gpr_malloc(sizeof(grpc_metadata_array));
239 }
240 return self;
241}
242
243- (void)getOp:(grpc_op *)op {
244 op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
245 op->data.recv_status_on_client.status = _code;
246 op->data.recv_status_on_client.status_details = _details;
247 op->data.recv_status_on_client.status_details_capacity = _details_capacity;
248 op->data.recv_status_on_client.trailing_metadata = _recv_trailing_metadata;
249}
250
251- (void (^)(void))opProcessor {
252 return ^{
253 grpc_status status;
254 status.status = *_code;
255 status.details = *_details;
256 status.metadata = _recv_trailing_metadata;
257 gpr_free(_code);
258 gpr_free(_details);
259 gpr_free(_details_capacity);
260 if (_handler) {
261 _handler([NSError grpc_errorFromStatus:&status]);
262 }
263 };
264}
265
266@end
267
murgatroid9930b7d4e2015-04-24 10:36:43 -0700268@implementation GRPCWrappedCall{
murgatroid9969927d62015-04-24 13:32:48 -0700269 grpc_call *_call;
270 GRPCCompletionQueue *_queue;
murgatroid9930b7d4e2015-04-24 10:36:43 -0700271}
272
273- (instancetype)init {
murgatroid99463a7a82015-04-24 11:41:43 -0700274 return [self initWithChannel:nil method:nil host:nil];
murgatroid9930b7d4e2015-04-24 10:36:43 -0700275}
276
277- (instancetype)initWithChannel:(GRPCChannel *)channel method:(NSString *)method host:(NSString *)host {
278 if (!channel || !method || !host) {
279 [NSException raise:NSInvalidArgumentException format:@"channel, method, and host cannot be nil."];
280 }
281
282 if (self = [super init]) {
283 static dispatch_once_t initialization;
284 dispatch_once(&initialization, ^{
285 grpc_init();
286 });
287
murgatroid9969927d62015-04-24 13:32:48 -0700288 _queue = [GRPCCompletionQueue completionQueue];
289 _call = grpc_channel_create_call(channel.unmanagedChannel, _queue.unmanagedQueue, method.UTF8String, host.UTF8String, gpr_inf_future);
290 if (_call == NULL) {
murgatroid9930b7d4e2015-04-24 10:36:43 -0700291 return nil;
292 }
293 }
294 return self;
295}
296
murgatroid9954e93d42015-04-27 09:29:49 -0700297- (void)startBatchWithOperations:(NSArray *)operations {
298 [self startBatchWithOperations:operations errorHandler:nil];
murgatroid9969927d62015-04-24 13:32:48 -0700299}
300
murgatroid9954e93d42015-04-27 09:29:49 -0700301- (void)startBatchWithOperations:(NSArray *)operations errorHandler:(void (^)())errorHandler {
302 NSMutableArray *opProcessors = [NSMutableArray array];
murgatroid9969927d62015-04-24 13:32:48 -0700303 size_t nops = operations.count;
murgatroid9930b7d4e2015-04-24 10:36:43 -0700304 grpc_op *ops_array = gpr_malloc(nops * sizeof(grpc_op));
murgatroid9954e93d42015-04-27 09:29:49 -0700305 size_t i = 0;
306 for (id op in operations) {
307 [op getOp:&ops_array[i]];
308 [opProcessors addObject:[op opProcessor]];
murgatroid9930b7d4e2015-04-24 10:36:43 -0700309 }
murgatroid9969927d62015-04-24 13:32:48 -0700310 grpc_call_error error = grpc_call_start_batch(_call, ops_array, nops, (__bridge_retained void *)(^(grpc_op_error error){
murgatroid9930b7d4e2015-04-24 10:36:43 -0700311 if (error != GRPC_OP_OK) {
murgatroid9969927d62015-04-24 13:32:48 -0700312 if (errorHandler) {
313 errorHandler();
314 } else {
315 [NSException raise:@"Operation Exception" format:@"The batch failed with an unknown error"];
316 }
murgatroid9930b7d4e2015-04-24 10:36:43 -0700317 }
murgatroid9954e93d42015-04-27 09:29:49 -0700318 for (void(^processor)(void) in opProcessors) {
319 processor();
murgatroid9969927d62015-04-24 13:32:48 -0700320 }
murgatroid9930b7d4e2015-04-24 10:36:43 -0700321 }));
murgatroid9954e93d42015-04-27 09:29:49 -0700322
murgatroid9930b7d4e2015-04-24 10:36:43 -0700323 if (error != GRPC_CALL_OK) {
324 [NSException raise:NSInvalidArgumentException format:@"The batch did not start successfully"];
325 }
326}
327
328- (void)cancel {
murgatroid9969927d62015-04-24 13:32:48 -0700329 grpc_call_cancel(_call);
murgatroid9930b7d4e2015-04-24 10:36:43 -0700330}
331
332- (void)dealloc {
murgatroid9969927d62015-04-24 13:32:48 -0700333 grpc_call_destroy(_call);
murgatroid9930b7d4e2015-04-24 10:36:43 -0700334}
335
336@end