Skip to content
Snippets Groups Projects
Commit 30b7d4e6 authored by murgatroid99's avatar murgatroid99
Browse files

Migrated Objective C library to C batch API

parent ea67c96a
No related branches found
No related tags found
No related merge requests found
Showing
with 7033 additions and 22330 deletions
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#import "private/GRPCCompletionQueue.h" #import "private/GRPCCompletionQueue.h"
#import "private/GRPCDelegateWrapper.h" #import "private/GRPCDelegateWrapper.h"
#import "private/GRPCMethodName+HTTP2Encoding.h" #import "private/GRPCMethodName+HTTP2Encoding.h"
#import "GRPCWrappedCall.h"
#import "private/NSData+GRPC.h" #import "private/NSData+GRPC.h"
#import "private/NSDictionary+GRPC.h" #import "private/NSDictionary+GRPC.h"
#import "private/NSError+GRPC.h" #import "private/NSError+GRPC.h"
...@@ -92,7 +93,7 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -92,7 +93,7 @@ static void AssertNoErrorInCall(grpc_call_error error) {
@implementation GRPCCall { @implementation GRPCCall {
dispatch_queue_t _callQueue; dispatch_queue_t _callQueue;
grpc_call *_gRPCCall; GRPCWrappedCall *_wrappedCall;
dispatch_once_t _callAlreadyInvoked; dispatch_once_t _callAlreadyInvoked;
GRPCChannel *_channel; GRPCChannel *_channel;
...@@ -129,10 +130,8 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -129,10 +130,8 @@ static void AssertNoErrorInCall(grpc_call_error error) {
_completionQueue = [GRPCCompletionQueue completionQueue]; _completionQueue = [GRPCCompletionQueue completionQueue];
_channel = [GRPCChannel channelToHost:host]; _channel = [GRPCChannel channelToHost:host];
_gRPCCall = grpc_channel_create_call_old(_channel.unmanagedChannel,
method.HTTP2Path.UTF8String, _wrappedCall = [[GRPCWrappedCall alloc] initWithChannel:_channel method:method.HTTP2Path host:host];
host.UTF8String,
gpr_inf_future);
// Serial queue to invoke the non-reentrant methods of the grpc_call object. // Serial queue to invoke the non-reentrant methods of the grpc_call object.
_callQueue = dispatch_queue_create("org.grpc.call", NULL); _callQueue = dispatch_queue_create("org.grpc.call", NULL);
...@@ -156,7 +155,7 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -156,7 +155,7 @@ static void AssertNoErrorInCall(grpc_call_error error) {
- (void)cancelCall { - (void)cancelCall {
// Can be called from any thread, any number of times. // Can be called from any thread, any number of times.
AssertNoErrorInCall(grpc_call_cancel(_gRPCCall)); [_wrappedCall cancel];
} }
- (void)cancel { - (void)cancel {
...@@ -167,9 +166,8 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -167,9 +166,8 @@ static void AssertNoErrorInCall(grpc_call_error error) {
} }
- (void)dealloc { - (void)dealloc {
grpc_call *gRPCCall = _gRPCCall;
dispatch_async(_callQueue, ^{ dispatch_async(_callQueue, ^{
grpc_call_destroy(gRPCCall); _wrappedCall = nil;
}); });
} }
...@@ -177,8 +175,8 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -177,8 +175,8 @@ static void AssertNoErrorInCall(grpc_call_error error) {
// Only called from the call queue. // Only called from the call queue.
// The handler will be called from the network queue. // The handler will be called from the network queue.
- (void)startReadWithHandler:(GRPCEventHandler)handler { - (void)startReadWithHandler:(GRPCCompletionHandler)handler {
AssertNoErrorInCall(grpc_call_start_read_old(_gRPCCall, (__bridge_retained void *)handler)); [_wrappedCall startBatch:@{@(GRPC_OP_RECV_MESSAGE): @YES} handleCompletion:handler];
} }
// Called initially from the network queue once response headers are received, // Called initially from the network queue once response headers are received,
...@@ -193,14 +191,17 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -193,14 +191,17 @@ static void AssertNoErrorInCall(grpc_call_error error) {
} }
__weak GRPCCall *weakSelf = self; __weak GRPCCall *weakSelf = self;
__weak GRPCDelegateWrapper *weakWriteable = _responseWriteable; __weak GRPCDelegateWrapper *weakWriteable = _responseWriteable;
dispatch_async(_callQueue, ^{ dispatch_async(_callQueue, ^{
[weakSelf startReadWithHandler:^(grpc_event *event) { [weakSelf startReadWithHandler:^(NSDictionary *event) {
if (!event->data.read) { NSData *data = event[[NSNumber numberWithInt:GRPC_OP_RECV_MESSAGE]];
// No more responses from the server. if (data == [NSNull null]) {
data = nil;
}
if (data == nil) {
// No more responses from the server
return; return;
} }
NSData *data = [NSData grpc_dataWithByteBuffer:event->data.read];
if (!data) { if (!data) {
// The app doesn't have enough memory to hold the server response. We // The app doesn't have enough memory to hold the server response. We
// don't want to throw, because the app shouldn't crash for a behavior // don't want to throw, because the app shouldn't crash for a behavior
...@@ -225,35 +226,11 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -225,35 +226,11 @@ static void AssertNoErrorInCall(grpc_call_error error) {
#pragma mark Send headers #pragma mark Send headers
- (void)addHeaderWithName:(NSString *)name binaryValue:(NSData *)value {
grpc_metadata metadata;
// Safe to discard const qualifiers; we're not going to modify the contents.
metadata.key = (char *)name.UTF8String;
metadata.value = (char *)value.bytes;
metadata.value_length = value.length;
grpc_call_add_metadata_old(_gRPCCall, &metadata, 0);
}
- (void)addHeaderWithName:(NSString *)name ASCIIValue:(NSString *)value {
grpc_metadata metadata;
// Safe to discard const qualifiers; we're not going to modify the contents.
metadata.key = (char *)name.UTF8String;
metadata.value = (char *)value.UTF8String;
// The trailing \0 isn't encoded in HTTP2.
metadata.value_length = value.length;
grpc_call_add_metadata_old(_gRPCCall, &metadata, 0);
}
// TODO(jcanizales): Rename to commitHeaders.
- (void)sendHeaders:(NSDictionary *)metadata { - (void)sendHeaders:(NSDictionary *)metadata {
for (NSString *name in metadata) { if (metadata == nil) {
id value = metadata[name]; metadata = @{};
if ([value isKindOfClass:[NSData class]]) {
[self addHeaderWithName:name binaryValue:value];
} else if ([value isKindOfClass:[NSString class]]) {
[self addHeaderWithName:name ASCIIValue:value];
}
} }
[_wrappedCall startBatch:@{@(GRPC_OP_SEND_INITIAL_METADATA): metadata} handleCompletion:^(NSDictionary * dict){}];
} }
#pragma mark GRXWriteable implementation #pragma mark GRXWriteable implementation
...@@ -263,10 +240,7 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -263,10 +240,7 @@ static void AssertNoErrorInCall(grpc_call_error error) {
- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)())errorHandler { - (void)writeMessage:(NSData *)message withErrorHandler:(void (^)())errorHandler {
__weak GRPCCall *weakSelf = self; __weak GRPCCall *weakSelf = self;
GRPCEventHandler resumingHandler = ^(grpc_event *event) { GRPCCompletionHandler resumingHandler = ^(NSDictionary *event) {
if (event->data.write_accepted != GRPC_OP_OK) {
errorHandler();
}
// Resume the request writer (even in the case of error). // Resume the request writer (even in the case of error).
// TODO(jcanizales): No need to do it in the case of errors anymore? // TODO(jcanizales): No need to do it in the case of errors anymore?
GRPCCall *strongSelf = weakSelf; GRPCCall *strongSelf = weakSelf;
...@@ -274,13 +248,7 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -274,13 +248,7 @@ static void AssertNoErrorInCall(grpc_call_error error) {
strongSelf->_requestWriter.state = GRXWriterStateStarted; strongSelf->_requestWriter.state = GRXWriterStateStarted;
} }
}; };
[_wrappedCall startBatch:@{@(GRPC_OP_SEND_MESSAGE): message} handleCompletion:resumingHandler];
grpc_byte_buffer *buffer = message.grpc_byteBuffer;
AssertNoErrorInCall(grpc_call_start_write_old(_gRPCCall,
buffer,
(__bridge_retained void *)resumingHandler,
0));
grpc_byte_buffer_destroy(buffer);
} }
- (void)didReceiveValue:(id)value { - (void)didReceiveValue:(id)value {
...@@ -303,12 +271,7 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -303,12 +271,7 @@ static void AssertNoErrorInCall(grpc_call_error error) {
// Only called from the call queue. The error handler will be called from the // Only called from the call queue. The error handler will be called from the
// network queue if the requests stream couldn't be closed successfully. // network queue if the requests stream couldn't be closed successfully.
- (void)finishRequestWithErrorHandler:(void (^)())errorHandler { - (void)finishRequestWithErrorHandler:(void (^)())errorHandler {
GRPCEventHandler handler = ^(grpc_event *event) { [_wrappedCall startBatch:@{@(GRPC_OP_SEND_CLOSE_FROM_CLIENT): @YES} handleCompletion:^(NSDictionary *event){}];
if (event->data.finish_accepted != GRPC_OP_OK) {
errorHandler();
}
};
AssertNoErrorInCall(grpc_call_writes_done_old(_gRPCCall, (__bridge_retained void *)handler));
} }
- (void)didFinishWithError:(NSError *)errorOrNil { - (void)didFinishWithError:(NSError *)errorOrNil {
...@@ -332,32 +295,28 @@ static void AssertNoErrorInCall(grpc_call_error error) { ...@@ -332,32 +295,28 @@ static void AssertNoErrorInCall(grpc_call_error error) {
// after this. // after this.
// The first one (metadataHandler), when the response headers are received. // The first one (metadataHandler), when the response headers are received.
// The second one (completionHandler), whenever the RPC finishes for any reason. // The second one (completionHandler), whenever the RPC finishes for any reason.
- (void)invokeCallWithMetadataHandler:(GRPCEventHandler)metadataHandler - (void)invokeCallWithMetadataHandler:(GRPCCompletionHandler)metadataHandler
completionHandler:(GRPCEventHandler)completionHandler { completionHandler:(GRPCCompletionHandler)completionHandler {
AssertNoErrorInCall(grpc_call_invoke_old(_gRPCCall, [_wrappedCall startBatch:@{@(GRPC_OP_RECV_INITIAL_METADATA): @YES} handleCompletion:metadataHandler];
_completionQueue.unmanagedQueue, [_wrappedCall startBatch:@{@(GRPC_OP_RECV_STATUS_ON_CLIENT): @YES} handleCompletion:completionHandler];
(__bridge_retained void *)metadataHandler,
(__bridge_retained void *)completionHandler,
0));
} }
- (void)invokeCall { - (void)invokeCall {
__weak GRPCCall *weakSelf = self; __weak GRPCCall *weakSelf = self;
[self invokeCallWithMetadataHandler:^(grpc_event *event) { [self invokeCallWithMetadataHandler:^(NSDictionary *event) {
// Response metadata received. // Response metadata received.
// TODO(jcanizales): Name the type of event->data.client_metadata_read
// in the C library so one can actually pass the object to a method.
grpc_metadata *entries = event->data.client_metadata_read.elements;
size_t count = event->data.client_metadata_read.count;
GRPCCall *strongSelf = weakSelf; GRPCCall *strongSelf = weakSelf;
if (strongSelf) { if (strongSelf) {
strongSelf.responseMetadata = [NSDictionary grpc_dictionaryFromMetadata:entries strongSelf.responseMetadata = event[@(GRPC_OP_RECV_INITIAL_METADATA)];
count:count];
[strongSelf startNextRead]; [strongSelf startNextRead];
} }
} completionHandler:^(grpc_event *event) { } completionHandler:^(NSDictionary *event) {
// TODO(jcanizales): Merge HTTP2 trailers into response metadata. // TODO(jcanizales): Merge HTTP2 trailers into response metadata.
[weakSelf finishWithError:[NSError grpc_errorFromStatus:&event->data.finished]]; id error = event[@(GRPC_OP_RECV_STATUS_ON_CLIENT)];
if (error == [NSNull null]) {
error = nil;
}
[weakSelf finishWithError:error];
}]; }];
// Now that the RPC has been initiated, request writes can start. // Now that the RPC has been initiated, request writes can start.
[_requestWriter startWithWriteable:self]; [_requestWriter startWithWriteable:self];
......
...@@ -32,11 +32,11 @@ ...@@ -32,11 +32,11 @@
*/ */
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include <grpc/grpc.h>
struct grpc_completion_queue; struct grpc_completion_queue;
struct grpc_event;
typedef void(^GRPCEventHandler)(struct grpc_event *event); typedef void(^GRPCQueueCompletionHandler)(grpc_op_error error);
// This class lets one more easily use grpc_completion_queue. To use it, pass // This class lets one more easily use grpc_completion_queue. To use it, pass
// the value of the unmanagedQueue property of an instance of this class to // the value of the unmanagedQueue property of an instance of this class to
......
...@@ -66,30 +66,17 @@ ...@@ -66,30 +66,17 @@
while (YES) { while (YES) {
// The following call blocks until an event is available. // The following call blocks until an event is available.
grpc_event *event = grpc_completion_queue_next(unmanagedQueue, gpr_inf_future); grpc_event *event = grpc_completion_queue_next(unmanagedQueue, gpr_inf_future);
GRPCQueueCompletionHandler handler;
switch (event->type) { switch (event->type) {
case GRPC_WRITE_ACCEPTED: case GRPC_OP_COMPLETE:
case GRPC_FINISH_ACCEPTED: handler = (__bridge_transfer GRPCQueueCompletionHandler)event->tag;
case GRPC_CLIENT_METADATA_READ: handler(event->data.op_complete);
case GRPC_READ: break;
case GRPC_FINISHED:
if (event->tag) {
GRPCEventHandler handler = (__bridge_transfer GRPCEventHandler) event->tag;
handler(event);
}
grpc_event_finish(event);
continue;
case GRPC_QUEUE_SHUTDOWN: case GRPC_QUEUE_SHUTDOWN:
grpc_completion_queue_destroy(unmanagedQueue);
grpc_event_finish(event);
return; return;
case GRPC_SERVER_RPC_NEW: default:
NSAssert(NO, @"C gRPC library produced a server-only event."); [NSException raise:@"Unrecognized completion type" format:@""];
continue;
} }
// This means the C gRPC library produced an event that wasn't known
// when this library was written. To preserve evolvability, ignore the
// unknown event on release builds.
NSAssert(NO, @"C gRPC library produced an unknown event.");
}; };
}); });
} }
......
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef Pods_GRPCWrappedCall_h
#define Pods_GRPCWrappedCall_h
#import <Foundation/Foundation.h>
#import "GRPCChannel.h"
typedef void(^GRPCCompletionHandler)(NSDictionary *);
@interface GRPCWrappedCall:NSObject;
- (instancetype)initWithChannel:(GRPCChannel *)channel method:(NSString *)method host:(NSString *)host;
- (void)startBatch:(NSDictionary *)ops handleCompletion:(GRPCCompletionHandler)handleCompletion;
- (void)cancel;
@end
#endif
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#import <Foundation/Foundation.h>
#import "GRPCWrappedCall.h"
#import "GRPCCompletionQueue.h"
#import "NSDictionary+GRPC.h"
#import "NSData+GRPC.h"
#import "NSError+GRPC.h"
#include <grpc/grpc.h>
#include <grpc/byte_buffer.h>
#include <grpc/support/alloc.h>
@implementation GRPCWrappedCall{
grpc_call *call;
GRPCCompletionQueue *queue;
}
- (instancetype)init {
return [self initWithChannel:nil method:nil host:nil];
}
- (instancetype)initWithChannel:(GRPCChannel *)channel method:(NSString *)method host:(NSString *)host {
if (!channel || !method || !host) {
[NSException raise:NSInvalidArgumentException format:@"channel, method, and host cannot be nil."];
}
if (self = [super init]) {
static dispatch_once_t initialization;
dispatch_once(&initialization, ^{
grpc_init();
});
const char *method_str = [method UTF8String];
const char *host_str = [host UTF8String];
queue = [GRPCCompletionQueue completionQueue];
call = grpc_channel_create_call(channel.unmanagedChannel, queue.unmanagedQueue, method_str, host_str, gpr_inf_future);
if (call == NULL) {
return nil;
}
}
return self;
}
- (void)startBatch:(NSDictionary *)ops handleCompletion:(GRPCCompletionHandler)handleCompletion {
size_t nops = ops.count;
grpc_op *ops_array = gpr_malloc(nops * sizeof(grpc_op));
size_t index = 0;
NSMutableDictionary * __block opProcessors = [NSMutableDictionary new];
grpc_metadata *send_metadata = NULL;
grpc_metadata_array *recv_initial_metadata;
grpc_metadata_array *recv_trailing_metadata;
grpc_byte_buffer *send_message;
grpc_byte_buffer **recv_message = NULL;
grpc_status_code *status_code;
char **status_details;
size_t *status_details_capacity;
for (id key in ops) {
id (^opBlock)(void);
grpc_op *current = &ops_array[index];
switch ([key intValue]) {
case GRPC_OP_SEND_INITIAL_METADATA:
current->data.send_initial_metadata.count = [ops[key] grpc_toMetadataArray:&send_metadata];
current->data.send_initial_metadata.metadata = send_metadata;
opBlock = ^{
gpr_free(send_metadata);
return @YES;
};
break;
case GRPC_OP_SEND_MESSAGE:
send_message = [ops[key] grpc_byteBuffer];
current->data.send_message = send_message;
opBlock = ^{
grpc_byte_buffer_destroy(send_message);
return @YES;
};
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
opBlock = ^{
return @YES;
};
break;
case GRPC_OP_RECV_INITIAL_METADATA:
recv_initial_metadata = gpr_malloc(sizeof(grpc_metadata_array));
grpc_metadata_array_init(recv_initial_metadata);
current->data.recv_initial_metadata = recv_initial_metadata;
opBlock = ^{
NSDictionary *metadata = [NSDictionary grpc_dictionaryFromMetadata:recv_initial_metadata->metadata count:recv_initial_metadata->count];
grpc_metadata_array_destroy(recv_initial_metadata);
return metadata;
};
break;
case GRPC_OP_RECV_MESSAGE:
recv_message = gpr_malloc(sizeof(grpc_byte_buffer*));
current->data.recv_message = recv_message;
opBlock = ^{
NSData *data = [NSData grpc_dataWithByteBuffer:*recv_message];
grpc_byte_buffer_destroy(*recv_message);
gpr_free(recv_message);
return data;
};
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
status_code = gpr_malloc(sizeof(status_code));
current->data.recv_status_on_client.status = status_code;
status_details = gpr_malloc(sizeof(char*));
*status_details = NULL;
current->data.recv_status_on_client.status_details = status_details;
status_details_capacity = gpr_malloc(sizeof(grpc_status_code));
*status_details_capacity = 0;
current->data.recv_status_on_client.status_details_capacity = status_details_capacity;
recv_trailing_metadata = gpr_malloc(sizeof(grpc_metadata_array));
grpc_metadata_array_init(recv_trailing_metadata);
current->data.recv_status_on_client.trailing_metadata = recv_trailing_metadata;
opBlock = ^{
grpc_status status;
status.status = *status_code;
status.details = *status_details;
status.metadata = recv_trailing_metadata;
gpr_free(status_code);
gpr_free(status_details);
gpr_free(status_details_capacity);
return [NSError grpc_errorFromStatus:&status];
};
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
[NSException raise:NSInvalidArgumentException format:@"Not a server: cannot send status"];
default:
[NSException raise:NSInvalidArgumentException format:@"Unrecognized dictionary key"];
}
current->op = [key intValue];
[opProcessors setObject:opBlock forKey:key];
}
grpc_call_error error = grpc_call_start_batch(call, ops_array, nops, (__bridge_retained void *)(^(grpc_op_error error){
if (error != GRPC_OP_OK) {
[NSException raise:@"Operation Exception" format:@"The batch failed with an unknown error"];
}
NSMutableDictionary *result = [NSMutableDictionary new];
for (id key in opProcessors) {
id(^block)(void) = opProcessors[key];
id value = block();
if (value == nil) {
value = [NSNull null];
}
[result setObject:value forKey:key];
}
handleCompletion(result);
}));
if (error != GRPC_CALL_OK) {
[NSException raise:NSInvalidArgumentException format:@"The batch did not start successfully"];
}
}
- (void)cancel {
grpc_call_cancel(call);
}
- (void)dealloc {
grpc_call_destroy(call);
}
@end
\ No newline at end of file
...@@ -59,6 +59,9 @@ static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array, size_t ...@@ -59,6 +59,9 @@ static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array, size_t
@implementation NSData (GRPC) @implementation NSData (GRPC)
+ (instancetype)grpc_dataWithByteBuffer:(grpc_byte_buffer *)buffer { + (instancetype)grpc_dataWithByteBuffer:(grpc_byte_buffer *)buffer {
if (buffer == NULL) {
return nil;
}
NSUInteger length = grpc_byte_buffer_length(buffer); NSUInteger length = grpc_byte_buffer_length(buffer);
char *array = malloc(length * sizeof(*array)); char *array = malloc(length * sizeof(*array));
if (!array) { if (!array) {
......
...@@ -32,9 +32,9 @@ ...@@ -32,9 +32,9 @@
*/ */
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include <grpc/grpc.h>
struct grpc_metadata;
@interface NSDictionary (GRPC) @interface NSDictionary (GRPC)
+ (instancetype)grpc_dictionaryFromMetadata:(struct grpc_metadata *)entries count:(size_t)count; + (instancetype)grpc_dictionaryFromMetadata:(struct grpc_metadata *)entries count:(size_t)count;
- (size_t)grpc_toMetadataArray:(grpc_metadata **)metadata;
@end @end
...@@ -33,7 +33,8 @@ ...@@ -33,7 +33,8 @@
#import "NSDictionary+GRPC.h" #import "NSDictionary+GRPC.h"
#include <grpc.h> #include <grpc/grpc.h>
#include <grpc/support/alloc.h>
@implementation NSDictionary (GRPC) @implementation NSDictionary (GRPC)
+ (instancetype)grpc_dictionaryFromMetadata:(grpc_metadata *)entries count:(size_t)count { + (instancetype)grpc_dictionaryFromMetadata:(grpc_metadata *)entries count:(size_t)count {
...@@ -53,4 +54,24 @@ ...@@ -53,4 +54,24 @@
} }
return metadata; return metadata;
} }
- (size_t)grpc_toMetadataArray:(grpc_metadata **)metadata {
size_t count = 0;
size_t capacity = 0;
for (id key in self) {
capacity += [self[key] count];
}
*metadata = gpr_malloc(capacity * sizeof(grpc_metadata));
for (id key in self) {
id value_array = self[key];
for (id value in value_array) {
grpc_metadata *current = &(*metadata)[count];
current->key = [key UTF8String];
current->value = [value UTF8String];
current->value_length = [value length];
count += 1;
}
}
return count;
}
@end @end
...@@ -58,14 +58,12 @@ typedef NS_ENUM(NSInteger, GRPCErrorCode) { ...@@ -58,14 +58,12 @@ typedef NS_ENUM(NSInteger, GRPCErrorCode) {
// TODO(jcanizales): This is conflating trailing metadata with Status details. Fix it once there's // TODO(jcanizales): This is conflating trailing metadata with Status details. Fix it once there's
// a decision on how to codify Status. // a decision on how to codify Status.
#include <grpc/status.h> #include <grpc/grpc.h>
struct grpc_metadata; typedef struct grpc_status {
struct grpc_status {
grpc_status_code status; grpc_status_code status;
const char *details; const char *details;
size_t metadata_count; grpc_metadata_array *metadata;
struct grpc_metadata *metadata_elements; } grpc_status;
};
@interface NSError (GRPC) @interface NSError (GRPC)
// Returns nil if the status is OK. Otherwise, a NSError whose code is one of // Returns nil if the status is OK. Otherwise, a NSError whose code is one of
......
PODS: PODS:
- GRPCClient (0.0.1): - gRPC (0.0.1):
- RxLibrary (~> 0.0) - gRPC/C-Core (= 0.0.1)
- RxLibrary (0.0.1) - gRPC/RxLibrary (= 0.0.1)
- gRPC/C-Core (0.0.1):
- OpenSSL (~> 1.0.200)
- gRPC/RxLibrary (0.0.1)
- OpenSSL (1.0.201)
- ProtocolBuffers (1.9.8)
- RemoteTest (0.0.1):
- ProtocolBuffers (~> 1.9)
- Route_guide (0.0.1):
- ProtocolBuffers (~> 1.9)
DEPENDENCIES: DEPENDENCIES:
- GRPCClient (from `../../GRPCClient`) - gRPC (from `../../../..`)
- RxLibrary (from `../../RxLibrary`) - RemoteTest (from `RemoteTestClient`)
- Route_guide (from `RouteGuideClient`)
EXTERNAL SOURCES: EXTERNAL SOURCES:
GRPCClient: gRPC:
:path: ../../GRPCClient :path: ../../../..
RxLibrary: RemoteTest:
:path: ../../RxLibrary :path: RemoteTestClient
Route_guide:
:path: RouteGuideClient
SPEC CHECKSUMS: SPEC CHECKSUMS:
GRPCClient: 05c58faab99661384178bb7c5f93b60c2bfc89f8 gRPC: 70fefb183437c880dbe8f9a477ff0d409e81e390
RxLibrary: 70cfcf1573ec16a375b4fe61d976a3188aab9303 OpenSSL: 4e990d04b14015c49c800c400b86ae44a4818a5c
ProtocolBuffers: 9a4a171c0c7cc8f21dd29aeca4f9ac775d84a880
RemoteTest: d7bbf2e0646a886ea9502375f0f79e8fe551aa71
Route_guide: a277da8eef182774abb050d7b81109f5878f8652
COCOAPODS: 0.35.0 COCOAPODS: 0.36.4
PODS: PODS:
- GRPCClient (0.0.1): - gRPC (0.0.1):
- RxLibrary (~> 0.0) - gRPC/C-Core (= 0.0.1)
- RxLibrary (0.0.1) - gRPC/RxLibrary (= 0.0.1)
- gRPC/C-Core (0.0.1):
- OpenSSL (~> 1.0.200)
- gRPC/RxLibrary (0.0.1)
- OpenSSL (1.0.201)
- ProtocolBuffers (1.9.8)
- RemoteTest (0.0.1):
- ProtocolBuffers (~> 1.9)
- Route_guide (0.0.1):
- ProtocolBuffers (~> 1.9)
DEPENDENCIES: DEPENDENCIES:
- GRPCClient (from `../../GRPCClient`) - gRPC (from `../../../..`)
- RxLibrary (from `../../RxLibrary`) - RemoteTest (from `RemoteTestClient`)
- Route_guide (from `RouteGuideClient`)
EXTERNAL SOURCES: EXTERNAL SOURCES:
GRPCClient: gRPC:
:path: ../../GRPCClient :path: ../../../..
RxLibrary: RemoteTest:
:path: ../../RxLibrary :path: RemoteTestClient
Route_guide:
:path: RouteGuideClient
SPEC CHECKSUMS: SPEC CHECKSUMS:
GRPCClient: 05c58faab99661384178bb7c5f93b60c2bfc89f8 gRPC: 70fefb183437c880dbe8f9a477ff0d409e81e390
RxLibrary: 70cfcf1573ec16a375b4fe61d976a3188aab9303 OpenSSL: 4e990d04b14015c49c800c400b86ae44a4818a5c
ProtocolBuffers: 9a4a171c0c7cc8f21dd29aeca4f9ac775d84a880
RemoteTest: d7bbf2e0646a886ea9502375f0f79e8fe551aa71
Route_guide: a277da8eef182774abb050d7b81109f5878f8652
COCOAPODS: 0.35.0 COCOAPODS: 0.36.4
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment