|
|
|
@ -49,11 +49,11 @@ |
|
|
|
|
#include <stdbool.h> |
|
|
|
|
|
|
|
|
|
#include "grpc/support/log.h" |
|
|
|
|
#include "grpc/support/alloc.h" |
|
|
|
|
#include "grpc/grpc.h" |
|
|
|
|
|
|
|
|
|
#include "timeval.h" |
|
|
|
|
#include "channel.h" |
|
|
|
|
#include "completion_queue.h" |
|
|
|
|
#include "byte_buffer.h" |
|
|
|
|
|
|
|
|
|
zend_class_entry *grpc_ce_call; |
|
|
|
@ -61,7 +61,19 @@ zend_class_entry *grpc_ce_call; |
|
|
|
|
/* Frees and destroys an instance of wrapped_grpc_call */ |
|
|
|
|
void free_wrapped_grpc_call(void *object TSRMLS_DC) { |
|
|
|
|
wrapped_grpc_call *call = (wrapped_grpc_call *)object; |
|
|
|
|
grpc_event *event; |
|
|
|
|
if (call->owned && call->wrapped != NULL) { |
|
|
|
|
if (call->queue != NULL) { |
|
|
|
|
grpc_completion_queue_shutdown(call->queue); |
|
|
|
|
event = grpc_completion_queue_next(call->queue, gpr_inf_future); |
|
|
|
|
while (event != NULL) { |
|
|
|
|
if (event->type == GRPC_QUEUE_SHUTDOWN) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
event = grpc_completion_queue_next(call->queue, gpr_inf_future); |
|
|
|
|
} |
|
|
|
|
grpc_completion_queue_destroy(call->queue); |
|
|
|
|
} |
|
|
|
|
grpc_call_destroy(call->wrapped); |
|
|
|
|
} |
|
|
|
|
efree(call); |
|
|
|
@ -88,17 +100,23 @@ zend_object_value create_wrapped_grpc_call(zend_class_entry *class_type |
|
|
|
|
|
|
|
|
|
/* Wraps a grpc_call struct in a PHP object. Owned indicates whether the struct
|
|
|
|
|
should be destroyed at the end of the object's lifecycle */ |
|
|
|
|
zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned) { |
|
|
|
|
zval *grpc_php_wrap_call(grpc_call *wrapped, grpc_completion_queue *queue, |
|
|
|
|
bool owned) { |
|
|
|
|
zval *call_object; |
|
|
|
|
MAKE_STD_ZVAL(call_object); |
|
|
|
|
object_init_ex(call_object, grpc_ce_call); |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(call_object TSRMLS_CC); |
|
|
|
|
call->wrapped = wrapped; |
|
|
|
|
call->queue = queue; |
|
|
|
|
return call_object; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) { |
|
|
|
|
/* Creates and returns a PHP array object with the data in a
|
|
|
|
|
* grpc_metadata_array. Returns NULL on failure */ |
|
|
|
|
zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array) { |
|
|
|
|
int count = metadata_array->count; |
|
|
|
|
grpc_metadata *elements = metadata_array->metadata; |
|
|
|
|
int i; |
|
|
|
|
zval *array; |
|
|
|
|
zval **data = NULL; |
|
|
|
@ -139,6 +157,64 @@ zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) { |
|
|
|
|
return array; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Populates a grpc_metadata_array with the data in a PHP array object.
|
|
|
|
|
Returns true on success and false on failure */ |
|
|
|
|
bool create_metadata_array(zval *array, grpc_metadata_array *metadata) { |
|
|
|
|
zval **inner_array; |
|
|
|
|
zval **value; |
|
|
|
|
HashTable *array_hash; |
|
|
|
|
HashPosition array_pointer; |
|
|
|
|
HashTable *inner_array_hash; |
|
|
|
|
HashPosition inner_array_pointer; |
|
|
|
|
char *key; |
|
|
|
|
uint key_len; |
|
|
|
|
ulong index; |
|
|
|
|
if (Z_TYPE_P(array) != IS_ARRAY) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
grpc_metadata_array_init(metadata); |
|
|
|
|
array_hash = Z_ARRVAL_P(array); |
|
|
|
|
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer); |
|
|
|
|
zend_hash_get_current_data_ex(array_hash, (void**)&inner_array, |
|
|
|
|
&array_pointer) == SUCCESS; |
|
|
|
|
zend_hash_move_forward_ex(array_hash, &array_pointer)) { |
|
|
|
|
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0, |
|
|
|
|
&array_pointer) != HASH_KEY_IS_STRING) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (Z_TYPE_P(*inner_array) != IS_ARRAY) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
inner_array_hash = Z_ARRVAL_P(*inner_array); |
|
|
|
|
metadata->capacity += zend_hash_num_elements(inner_array_hash); |
|
|
|
|
} |
|
|
|
|
metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata)); |
|
|
|
|
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer); |
|
|
|
|
zend_hash_get_current_data_ex(array_hash, (void**)&inner_array, |
|
|
|
|
&array_pointer) == SUCCESS; |
|
|
|
|
zend_hash_move_forward_ex(array_hash, &array_pointer)) { |
|
|
|
|
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0, |
|
|
|
|
&array_pointer) != HASH_KEY_IS_STRING) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
inner_array_hash = Z_ARRVAL_P(*inner_array); |
|
|
|
|
for (zend_hash_internal_pointer_reset_ex(inner_array_hash, |
|
|
|
|
&inner_array_pointer); |
|
|
|
|
zend_hash_get_current_data_ex(inner_array_hash, (void**)&value, |
|
|
|
|
&inner_array_pointer) == SUCCESS; |
|
|
|
|
zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) { |
|
|
|
|
if (Z_TYPE_P(*value) != IS_STRING) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
metadata->metadata[metadata->count].key = key; |
|
|
|
|
metadata->metadata[metadata->count].value = Z_STRVAL_P(*value); |
|
|
|
|
metadata->metadata[metadata->count].value_length = Z_STRLEN_P(*value); |
|
|
|
|
metadata->count += 1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructs a new instance of the Call class. |
|
|
|
|
* @param Channel $channel The channel to associate the call with. Must not be |
|
|
|
@ -157,9 +233,10 @@ PHP_METHOD(Call, __construct) { |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO", &channel_obj, |
|
|
|
|
grpc_ce_channel, &method, &method_len, |
|
|
|
|
&deadline_obj, grpc_ce_timeval) == FAILURE) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"Call expects a Channel, a String, and a Timeval", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
zend_throw_exception( |
|
|
|
|
spl_ce_InvalidArgumentException, |
|
|
|
|
"Call expects a Channel, a String, and a Timeval", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
wrapped_grpc_channel *channel = |
|
|
|
@ -175,289 +252,235 @@ PHP_METHOD(Call, __construct) { |
|
|
|
|
wrapped_grpc_timeval *deadline = |
|
|
|
|
(wrapped_grpc_timeval *)zend_object_store_get_object( |
|
|
|
|
deadline_obj TSRMLS_CC); |
|
|
|
|
call->wrapped = grpc_channel_create_call_old( |
|
|
|
|
channel->wrapped, method, channel->target, deadline->wrapped); |
|
|
|
|
call->queue = grpc_completion_queue_create(); |
|
|
|
|
call->wrapped = grpc_channel_create_call( |
|
|
|
|
channel->wrapped, call->queue, method, channel->target, |
|
|
|
|
deadline->wrapped); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add metadata to the call. All array keys must be strings. If the value is a |
|
|
|
|
* string, it is added as a key/value pair. If it is an array, each value is |
|
|
|
|
* added paired with the same string |
|
|
|
|
* @param array $metadata The metadata to add |
|
|
|
|
* @param long $flags A bitwise combination of the Grpc\WRITE_* constants |
|
|
|
|
* (optional) |
|
|
|
|
* @return Void |
|
|
|
|
* Start a batch of RPC actions. |
|
|
|
|
* @param array batch Array of actions to take |
|
|
|
|
* @return object Object with results of all actions |
|
|
|
|
*/ |
|
|
|
|
PHP_METHOD(Call, add_metadata) { |
|
|
|
|
PHP_METHOD(Call, start_batch) { |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); |
|
|
|
|
grpc_metadata metadata; |
|
|
|
|
grpc_call_error error_code; |
|
|
|
|
grpc_op ops[8]; |
|
|
|
|
size_t op_num = 0; |
|
|
|
|
zval *array; |
|
|
|
|
zval **inner_array; |
|
|
|
|
zval **value; |
|
|
|
|
zval **inner_value; |
|
|
|
|
HashTable *array_hash; |
|
|
|
|
HashPosition array_pointer; |
|
|
|
|
HashTable *inner_array_hash; |
|
|
|
|
HashPosition inner_array_pointer; |
|
|
|
|
HashTable *status_hash; |
|
|
|
|
char *key; |
|
|
|
|
uint key_len; |
|
|
|
|
ulong index; |
|
|
|
|
long flags = 0; |
|
|
|
|
/* "a|l" == 1 array, 1 optional long */ |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &flags) == |
|
|
|
|
grpc_metadata_array metadata; |
|
|
|
|
grpc_metadata_array trailing_metadata; |
|
|
|
|
grpc_metadata_array recv_metadata; |
|
|
|
|
grpc_metadata_array recv_trailing_metadata; |
|
|
|
|
grpc_status_code status; |
|
|
|
|
char *status_details = NULL; |
|
|
|
|
size_t status_details_capacity = 0; |
|
|
|
|
grpc_byte_buffer *message; |
|
|
|
|
int cancelled; |
|
|
|
|
grpc_call_error error; |
|
|
|
|
grpc_event *event; |
|
|
|
|
zval *result; |
|
|
|
|
char *message_str; |
|
|
|
|
size_t message_len; |
|
|
|
|
zval *recv_status; |
|
|
|
|
grpc_metadata_array_init(&metadata); |
|
|
|
|
grpc_metadata_array_init(&trailing_metadata); |
|
|
|
|
grpc_metadata_array_init(&recv_metadata); |
|
|
|
|
grpc_metadata_array_init(&recv_trailing_metadata); |
|
|
|
|
MAKE_STD_ZVAL(result); |
|
|
|
|
object_init(result); |
|
|
|
|
/* "a" == 1 array */ |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == |
|
|
|
|
FAILURE) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"add_metadata expects an array and an optional long", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
"start_batch expects an array", 1 TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
array_hash = Z_ARRVAL_P(array); |
|
|
|
|
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer); |
|
|
|
|
zend_hash_get_current_data_ex(array_hash, (void**)&inner_array, |
|
|
|
|
zend_hash_get_current_data_ex(array_hash, (void**)&value, |
|
|
|
|
&array_pointer) == SUCCESS; |
|
|
|
|
zend_hash_move_forward_ex(array_hash, &array_pointer)) { |
|
|
|
|
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0, |
|
|
|
|
&array_pointer) != HASH_KEY_IS_STRING) { |
|
|
|
|
&array_pointer) != HASH_KEY_IS_LONG) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"metadata keys must be strings", 1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
"batch keys must be integers", 1 TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
if (Z_TYPE_P(*inner_array) != IS_ARRAY) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"metadata values must be arrays", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
inner_array_hash = Z_ARRVAL_P(*inner_array); |
|
|
|
|
for (zend_hash_internal_pointer_reset_ex(inner_array_hash, |
|
|
|
|
&inner_array_pointer); |
|
|
|
|
zend_hash_get_current_data_ex(inner_array_hash, (void**)&value, |
|
|
|
|
&inner_array_pointer) == SUCCESS; |
|
|
|
|
zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) { |
|
|
|
|
if (Z_TYPE_P(*value) != IS_STRING) { |
|
|
|
|
switch(index) { |
|
|
|
|
case GRPC_OP_SEND_INITIAL_METADATA: |
|
|
|
|
if (!create_metadata_array(*value, &metadata)) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"Bad metadata value given", 1 TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
ops[op_num].data.send_initial_metadata.count = |
|
|
|
|
metadata.count; |
|
|
|
|
ops[op_num].data.send_initial_metadata.metadata = |
|
|
|
|
metadata.metadata; |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_SEND_MESSAGE: |
|
|
|
|
if (Z_TYPE_PP(value) != IS_STRING) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"Expected a string for send message", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
} |
|
|
|
|
ops[op_num].data.send_message = |
|
|
|
|
string_to_byte_buffer(Z_STRVAL_PP(value), Z_STRLEN_PP(value)); |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_SEND_CLOSE_FROM_CLIENT: |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_SEND_STATUS_FROM_SERVER: |
|
|
|
|
status_hash = Z_ARRVAL_PP(value); |
|
|
|
|
if (zend_hash_find(status_hash, "metadata", sizeof("metadata"), |
|
|
|
|
(void **)&inner_value) == SUCCESS) { |
|
|
|
|
if (!create_metadata_array(*inner_value, &trailing_metadata)) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"Bad trailing metadata value given", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
ops[op_num].data.send_status_from_server.trailing_metadata = |
|
|
|
|
trailing_metadata.metadata; |
|
|
|
|
ops[op_num].data.send_status_from_server.trailing_metadata_count = |
|
|
|
|
trailing_metadata.count; |
|
|
|
|
} |
|
|
|
|
if (zend_hash_find(status_hash, "code", sizeof("code"), |
|
|
|
|
(void**)&inner_value) == SUCCESS) { |
|
|
|
|
if (Z_TYPE_PP(inner_value) != IS_LONG) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"Status code must be an integer", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
ops[op_num].data.send_status_from_server.status = |
|
|
|
|
Z_LVAL_PP(inner_value); |
|
|
|
|
} else { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"Integer status code is required", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
if (zend_hash_find(status_hash, "details", sizeof("details"), |
|
|
|
|
(void**)&inner_value) == SUCCESS) { |
|
|
|
|
if (Z_TYPE_PP(inner_value) != IS_STRING) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"Status details must be a string", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
ops[op_num].data.send_status_from_server.status_details = |
|
|
|
|
Z_STRVAL_PP(inner_value); |
|
|
|
|
} else { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"String status details is required", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_RECV_INITIAL_METADATA: |
|
|
|
|
ops[op_num].data.recv_initial_metadata = &recv_metadata; |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_RECV_MESSAGE: |
|
|
|
|
ops[op_num].data.recv_message = &message; |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_RECV_STATUS_ON_CLIENT: |
|
|
|
|
ops[op_num].data.recv_status_on_client.trailing_metadata = |
|
|
|
|
&recv_trailing_metadata; |
|
|
|
|
ops[op_num].data.recv_status_on_client.status = &status; |
|
|
|
|
ops[op_num].data.recv_status_on_client.status_details = |
|
|
|
|
&status_details; |
|
|
|
|
ops[op_num].data.recv_status_on_client.status_details_capacity = |
|
|
|
|
&status_details_capacity; |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_RECV_CLOSE_ON_SERVER: |
|
|
|
|
ops[op_num].data.recv_close_on_server.cancelled = &cancelled; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"metadata values must be arrays of strings", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
metadata.key = key; |
|
|
|
|
metadata.value = Z_STRVAL_P(*value); |
|
|
|
|
metadata.value_length = Z_STRLEN_P(*value); |
|
|
|
|
error_code = grpc_call_add_metadata_old(call->wrapped, &metadata, 0u); |
|
|
|
|
MAYBE_THROW_CALL_ERROR(add_metadata, error_code); |
|
|
|
|
"Unrecognized key in batch", 1 TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
ops[op_num].op = (grpc_op_type)index; |
|
|
|
|
op_num++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Invoke the RPC. Starts sending metadata and request headers over the wire |
|
|
|
|
* @param CompletionQueue $queue The completion queue to use with this call |
|
|
|
|
* @param long $metadata_tag The tag to associate with returned metadata |
|
|
|
|
* @param long $finished_tag The tag to associate with the finished event |
|
|
|
|
* @param long $flags A bitwise combination of the Grpc\WRITE_* constants |
|
|
|
|
* (optional) |
|
|
|
|
* @return Void |
|
|
|
|
*/ |
|
|
|
|
PHP_METHOD(Call, invoke) { |
|
|
|
|
grpc_call_error error_code; |
|
|
|
|
long tag1; |
|
|
|
|
long tag2; |
|
|
|
|
zval *queue_obj; |
|
|
|
|
long flags = 0; |
|
|
|
|
/* "Oll|l" == 1 Object, 3 mandatory longs, 1 optional long */ |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oll|l", &queue_obj, |
|
|
|
|
grpc_ce_completion_queue, &tag1, &tag2, |
|
|
|
|
&flags) == FAILURE) { |
|
|
|
|
zend_throw_exception( |
|
|
|
|
spl_ce_InvalidArgumentException, |
|
|
|
|
"invoke needs a CompletionQueue, 2 longs, and an optional long", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
add_property_zval(getThis(), "completion_queue", queue_obj); |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); |
|
|
|
|
wrapped_grpc_completion_queue *queue = |
|
|
|
|
(wrapped_grpc_completion_queue *)zend_object_store_get_object( |
|
|
|
|
queue_obj TSRMLS_CC); |
|
|
|
|
error_code = grpc_call_invoke_old(call->wrapped, queue->wrapped, (void *)tag1, |
|
|
|
|
(void *)tag2, (gpr_uint32)flags); |
|
|
|
|
MAYBE_THROW_CALL_ERROR(invoke, error_code); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Accept an incoming RPC, binding a completion queue to it. To be called after |
|
|
|
|
* adding metadata to the call, but before sending messages. Can only be called |
|
|
|
|
* on the server |
|
|
|
|
* @param CompletionQueue $queue The completion queue to use with this call |
|
|
|
|
* @param long $finished_tag The tag to associate with the finished event |
|
|
|
|
* @param long $flags A bitwise combination of the Grpc\WRITE_* constants |
|
|
|
|
* (optional) |
|
|
|
|
* @return Void |
|
|
|
|
*/ |
|
|
|
|
PHP_METHOD(Call, server_accept) { |
|
|
|
|
long tag; |
|
|
|
|
zval *queue_obj; |
|
|
|
|
grpc_call_error error_code; |
|
|
|
|
/* "Ol|l" == 1 Object, 1 long */ |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &queue_obj, |
|
|
|
|
grpc_ce_completion_queue, &tag) == FAILURE) { |
|
|
|
|
zend_throw_exception( |
|
|
|
|
spl_ce_InvalidArgumentException, |
|
|
|
|
"server_accept expects a CompletionQueue, a long, and an optional long", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped); |
|
|
|
|
if (error != GRPC_CALL_OK) { |
|
|
|
|
zend_throw_exception(spl_ce_LogicException, |
|
|
|
|
"start_batch was called incorrectly", |
|
|
|
|
(long)error TSRMLS_CC); |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
add_property_zval(getThis(), "completion_queue", queue_obj); |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); |
|
|
|
|
wrapped_grpc_completion_queue *queue = |
|
|
|
|
(wrapped_grpc_completion_queue *)zend_object_store_get_object( |
|
|
|
|
queue_obj TSRMLS_CC); |
|
|
|
|
error_code = |
|
|
|
|
grpc_call_server_accept_old(call->wrapped, queue->wrapped, (void *)tag); |
|
|
|
|
MAYBE_THROW_CALL_ERROR(server_accept, error_code); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PHP_METHOD(Call, server_end_initial_metadata) { |
|
|
|
|
grpc_call_error error_code; |
|
|
|
|
long flags = 0; |
|
|
|
|
/* "|l" == 1 optional long */ |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == |
|
|
|
|
FAILURE) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"server_end_initial_metadata expects an optional long", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
} |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); |
|
|
|
|
error_code = grpc_call_server_end_initial_metadata_old(call->wrapped, flags); |
|
|
|
|
MAYBE_THROW_CALL_ERROR(server_end_initial_metadata, error_code); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called by clients to cancel an RPC on the server. |
|
|
|
|
* @return Void |
|
|
|
|
*/ |
|
|
|
|
PHP_METHOD(Call, cancel) { |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); |
|
|
|
|
grpc_call_error error_code = grpc_call_cancel(call->wrapped); |
|
|
|
|
MAYBE_THROW_CALL_ERROR(cancel, error_code); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Queue a byte buffer for writing |
|
|
|
|
* @param string $buffer The buffer to queue for writing |
|
|
|
|
* @param long $tag The tag to associate with this write |
|
|
|
|
* @param long $flags A bitwise combination of the Grpc\WRITE_* constants |
|
|
|
|
* (optional) |
|
|
|
|
* @return Void |
|
|
|
|
*/ |
|
|
|
|
PHP_METHOD(Call, start_write) { |
|
|
|
|
grpc_call_error error_code; |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); |
|
|
|
|
char *buffer; |
|
|
|
|
int buffer_len; |
|
|
|
|
long tag; |
|
|
|
|
long flags = 0; |
|
|
|
|
/* "Ol|l" == 1 Object, 1 mandatory long, 1 optional long */ |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &buffer, |
|
|
|
|
&buffer_len, &tag, &flags) == FAILURE) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"start_write expects a string and an optional long", |
|
|
|
|
event = grpc_completion_queue_pluck(call->queue, call->wrapped, |
|
|
|
|
gpr_inf_future); |
|
|
|
|
if (event->data.op_complete != GRPC_OP_OK) { |
|
|
|
|
zend_throw_exception(spl_ce_LogicException, |
|
|
|
|
"The batch failed for some reason", |
|
|
|
|
1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
error_code = grpc_call_start_write_old( |
|
|
|
|
call->wrapped, string_to_byte_buffer(buffer, buffer_len), (void *)tag, |
|
|
|
|
(gpr_uint32)flags); |
|
|
|
|
MAYBE_THROW_CALL_ERROR(start_write, error_code); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Queue a status for writing |
|
|
|
|
* @param long $status_code The status code to send |
|
|
|
|
* @param string $status_details The status details to send |
|
|
|
|
* @param long $tag The tag to associate with this status |
|
|
|
|
* @return Void |
|
|
|
|
*/ |
|
|
|
|
PHP_METHOD(Call, start_write_status) { |
|
|
|
|
grpc_call_error error_code; |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); |
|
|
|
|
long status_code; |
|
|
|
|
int status_details_length; |
|
|
|
|
long tag; |
|
|
|
|
char *status_details; |
|
|
|
|
/* "lsl" == 1 long, 1 string, 1 long */ |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &status_code, |
|
|
|
|
&status_details, &status_details_length, |
|
|
|
|
&tag) == FAILURE) { |
|
|
|
|
zend_throw_exception( |
|
|
|
|
spl_ce_InvalidArgumentException, |
|
|
|
|
"start_write_status expects a long, a string, and a long", 1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
goto cleanup; |
|
|
|
|
} |
|
|
|
|
error_code = grpc_call_start_write_status_old(call->wrapped, |
|
|
|
|
(grpc_status_code)status_code, |
|
|
|
|
status_details, (void *)tag); |
|
|
|
|
MAYBE_THROW_CALL_ERROR(start_write_status, error_code); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Indicate that there are no more messages to send |
|
|
|
|
* @return Void |
|
|
|
|
*/ |
|
|
|
|
PHP_METHOD(Call, writes_done) { |
|
|
|
|
grpc_call_error error_code; |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); |
|
|
|
|
long tag; |
|
|
|
|
/* "l" == 1 long */ |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"writes_done expects a long", 1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
for (int i = 0; i < op_num; i++) { |
|
|
|
|
switch(ops[i].op) { |
|
|
|
|
case GRPC_OP_SEND_INITIAL_METADATA: |
|
|
|
|
add_property_bool(result, "send_metadata", true); |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_SEND_MESSAGE: |
|
|
|
|
add_property_bool(result, "send_message", true); |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_SEND_CLOSE_FROM_CLIENT: |
|
|
|
|
add_property_bool(result, "send_close", true); |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_SEND_STATUS_FROM_SERVER: |
|
|
|
|
add_property_bool(result, "send_status", true); |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_RECV_INITIAL_METADATA: |
|
|
|
|
add_property_zval(result, "metadata", |
|
|
|
|
grpc_parse_metadata_array(&recv_metadata)); |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_RECV_MESSAGE: |
|
|
|
|
byte_buffer_to_string(message, &message_str, &message_len); |
|
|
|
|
add_property_stringl(result, "message", message_str, message_len, |
|
|
|
|
false); |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_RECV_STATUS_ON_CLIENT: |
|
|
|
|
MAKE_STD_ZVAL(recv_status); |
|
|
|
|
object_init(recv_status); |
|
|
|
|
add_property_zval(recv_status, "metadata", |
|
|
|
|
grpc_parse_metadata_array(&recv_trailing_metadata)); |
|
|
|
|
add_property_long(recv_status, "code", status); |
|
|
|
|
add_property_string(recv_status, "details", status_details, true); |
|
|
|
|
add_property_zval(result, "status", recv_status); |
|
|
|
|
break; |
|
|
|
|
case GRPC_OP_RECV_CLOSE_ON_SERVER: |
|
|
|
|
add_property_bool(result, "cancelled", cancelled); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
error_code = grpc_call_writes_done_old(call->wrapped, (void *)tag); |
|
|
|
|
MAYBE_THROW_CALL_ERROR(writes_done, error_code); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initiate a read on a call. Output event contains a byte buffer with the |
|
|
|
|
* result of the read |
|
|
|
|
* @param long $tag The tag to associate with this read |
|
|
|
|
* @return Void |
|
|
|
|
*/ |
|
|
|
|
PHP_METHOD(Call, start_read) { |
|
|
|
|
grpc_call_error error_code; |
|
|
|
|
wrapped_grpc_call *call = |
|
|
|
|
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); |
|
|
|
|
long tag; |
|
|
|
|
/* "l" == 1 long */ |
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) { |
|
|
|
|
zend_throw_exception(spl_ce_InvalidArgumentException, |
|
|
|
|
"start_read expects a long", 1 TSRMLS_CC); |
|
|
|
|
return; |
|
|
|
|
cleanup: |
|
|
|
|
grpc_metadata_array_destroy(&metadata); |
|
|
|
|
grpc_metadata_array_destroy(&trailing_metadata); |
|
|
|
|
grpc_metadata_array_destroy(&recv_metadata); |
|
|
|
|
grpc_metadata_array_destroy(&recv_trailing_metadata); |
|
|
|
|
if (status_details != NULL) { |
|
|
|
|
gpr_free(status_details); |
|
|
|
|
} |
|
|
|
|
error_code = grpc_call_start_read_old(call->wrapped, (void *)tag); |
|
|
|
|
MAYBE_THROW_CALL_ERROR(start_read, error_code); |
|
|
|
|
RETURN_DESTROY_ZVAL(result); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static zend_function_entry call_methods[] = { |
|
|
|
|
PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) |
|
|
|
|
PHP_ME(Call, server_accept, NULL, ZEND_ACC_PUBLIC) |
|
|
|
|
PHP_ME(Call, server_end_initial_metadata, NULL, ZEND_ACC_PUBLIC) |
|
|
|
|
PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC) |
|
|
|
|
PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) |
|
|
|
|
PHP_ME(Call, invoke, NULL, ZEND_ACC_PUBLIC) |
|
|
|
|
PHP_ME(Call, start_read, NULL, ZEND_ACC_PUBLIC) |
|
|
|
|
PHP_ME(Call, start_write, NULL, ZEND_ACC_PUBLIC) |
|
|
|
|
PHP_ME(Call, start_write_status, NULL, ZEND_ACC_PUBLIC) |
|
|
|
|
PHP_ME(Call, writes_done, NULL, ZEND_ACC_PUBLIC) PHP_FE_END}; |
|
|
|
|
PHP_ME(Call, start_batch, NULL, ZEND_ACC_PUBLIC) PHP_FE_END}; |
|
|
|
|
|
|
|
|
|
void grpc_init_call(TSRMLS_D) { |
|
|
|
|
zend_class_entry ce; |
|
|
|
|