Change on 2014/12/09 by mlumish <mlumish@google.com> ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=81727766pull/1/merge
parent
275b3ac04d
commit
b892a27e67
40 changed files with 5233 additions and 0 deletions
@ -0,0 +1,18 @@ |
||||
.libs/ |
||||
build/ |
||||
modules/ |
||||
autom4te.cache/ |
||||
*.lo |
||||
*.la |
||||
.deps |
||||
acinclude.m4 |
||||
aclocal.m4 |
||||
config.* |
||||
configure* |
||||
Makefile* |
||||
run-tests.php |
||||
|
||||
install-sh |
||||
libtool |
||||
missing |
||||
mkinstalldirs |
@ -0,0 +1,56 @@ |
||||
# PHP wrapper for the GRPC interfaces. |
||||
|
||||
## LAYOUT |
||||
|
||||
Directory structure is as generated by the PHP utility |
||||
[ext_skel](http://php.net/manual/en/internals2.buildsys.skeleton.php) |
||||
|
||||
## ENVIRONMENT |
||||
|
||||
To build a PHP environment that works with this extension, download and extract |
||||
PHP 5.5 (5.6 may also work), configure it, and install it: |
||||
|
||||
```bash |
||||
apt-get install libxml2 libxml2-dev |
||||
curl http://php.net/get/php-5.5.16.tar.gz |
||||
tar -xf php-5.5.16.tar.gz |
||||
cd php-5.5.16 |
||||
./configure --with-zlib=/usr --with-libxml-dir=ext/libxml --with-openssl=/usr/local/ssl |
||||
make |
||||
make install |
||||
``` |
||||
|
||||
To also download and install the patched protoc and PHP code generator: |
||||
|
||||
```bash |
||||
apt-get install -y procps |
||||
curl -sSL https://get.rvm.io | sudo bash -s stable --ruby |
||||
git clone sso://team/one-platform-grpc-team/protobuf |
||||
cd protobuf |
||||
./configure |
||||
make |
||||
make install |
||||
git clone sso://team/one-platform-grpc-team/grpc-php-protobuf-php |
||||
cd grpc-php-protobuf-php |
||||
rake pear:package version=1.0 |
||||
pear install Protobuf-1.0.tgz |
||||
``` |
||||
|
||||
## BUILDING |
||||
|
||||
1. In ./ext/grpc, run the command `phpize` (distributed with PHP) |
||||
2. Run `./ext/grpc/configure` |
||||
3. In ./ext/grpc, run `make` and `sudo make install` |
||||
4. In your php.ini file, add the line `extension=grpc.so` to load the |
||||
extension at PHP startup. |
||||
|
||||
## PHPUnit |
||||
|
||||
This repo now has PHPUnit tests, which can by run by executing |
||||
`./bin/run_tests.sh` after building. |
||||
|
||||
There is also a generated code test (`./bin/run_gen_code_test.sh`), which tests |
||||
the stub `./tests/generated_code/math.php` against a running localhost server |
||||
serving the math service. That stub is generated from |
||||
`./tests/generated_code/math.proto` with the head of the repo |
||||
`sso://team/one-platform-grpc-team/grpc-php-protobuf-php`. |
@ -0,0 +1,5 @@ |
||||
# Runs the generated code test against the ruby server |
||||
cd $(dirname $0) |
||||
GRPC_TEST_HOST=localhost:7070 php -d extension_dir=../ext/grpc/modules/ \ |
||||
-d extension=grpc.so /usr/local/bin/phpunit -v --debug --strict \ |
||||
../tests/generated_code/GeneratedCodeTest.php |
@ -0,0 +1,5 @@ |
||||
# Loads the local shared library, and runs all of the test cases in tests/ |
||||
# against it |
||||
cd $(dirname $0) |
||||
php -d extension_dir=../ext/grpc/modules/ -d extension=grpc.so \ |
||||
/usr/local/bin/phpunit -v --debug --strict ../tests/unit_tests |
@ -0,0 +1,38 @@ |
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "ext/spl/spl_exceptions.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "byte_buffer.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
#include "grpc/support/slice.h" |
||||
|
||||
grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length) { |
||||
gpr_slice slice = gpr_slice_malloc(length); |
||||
memcpy(GPR_SLICE_START_PTR(slice), string, length); |
||||
return grpc_byte_buffer_create(&slice, 1); |
||||
} |
||||
|
||||
void byte_buffer_to_string(grpc_byte_buffer *buffer, |
||||
char **out_string, |
||||
size_t *out_length) { |
||||
size_t length = grpc_byte_buffer_length(buffer); |
||||
char *string = ecalloc(length+1, sizeof(char)); |
||||
size_t offset = 0; |
||||
grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer); |
||||
gpr_slice next; |
||||
while(grpc_byte_buffer_reader_next(reader, &next) != 0) { |
||||
memcpy(string+offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next)); |
||||
offset += GPR_SLICE_LENGTH(next); |
||||
} |
||||
*out_string = string; |
||||
*out_length = length; |
||||
} |
@ -0,0 +1,12 @@ |
||||
#ifndef NET_GRPC_PHP_GRPC_BYTE_BUFFER_H_ |
||||
#define NET_GRPC_PHP_GRPC_BYTE_BUFFER_H_ |
||||
|
||||
#include "grpc/grpc.h" |
||||
|
||||
grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length); |
||||
|
||||
void byte_buffer_to_string(grpc_byte_buffer *buffer, |
||||
char **out_string, |
||||
size_t *out_length); |
||||
|
||||
#endif /* NET_GRPC_PHP_GRPC_BYTE_BUFFER_H_ */ |
@ -0,0 +1,454 @@ |
||||
#include "call.h" |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "ext/spl/spl_exceptions.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "zend_exceptions.h" |
||||
#include "zend_hash.h" |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "grpc/support/log.h" |
||||
#include "grpc/grpc.h" |
||||
|
||||
#include "timeval.h" |
||||
#include "channel.h" |
||||
#include "completion_queue.h" |
||||
#include "byte_buffer.h" |
||||
|
||||
/* 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; |
||||
if(call->wrapped != NULL){ |
||||
grpc_call_destroy(call->wrapped); |
||||
} |
||||
efree(call); |
||||
} |
||||
|
||||
/* Initializes an instance of wrapped_grpc_call to be associated with an object
|
||||
* of a class specified by class_type */ |
||||
zend_object_value create_wrapped_grpc_call( |
||||
zend_class_entry *class_type TSRMLS_DC){ |
||||
zend_object_value retval; |
||||
wrapped_grpc_call *intern; |
||||
|
||||
intern = (wrapped_grpc_call*)emalloc(sizeof(wrapped_grpc_call)); |
||||
memset(intern, 0, sizeof(wrapped_grpc_call)); |
||||
|
||||
zend_object_std_init(&intern->std, class_type TSRMLS_CC); |
||||
object_properties_init(&intern->std, class_type); |
||||
retval.handle = zend_objects_store_put( |
||||
intern, |
||||
(zend_objects_store_dtor_t) zend_objects_destroy_object, |
||||
free_wrapped_grpc_call, |
||||
NULL TSRMLS_CC); |
||||
retval.handlers = zend_get_std_object_handlers(); |
||||
return retval; |
||||
} |
||||
|
||||
zval *grpc_php_wrap_call(grpc_call *wrapped){ |
||||
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; |
||||
return call_object; |
||||
} |
||||
|
||||
zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements){ |
||||
int i; |
||||
zval *array; |
||||
zval **data = NULL; |
||||
HashTable *array_hash; |
||||
zval *inner_array; |
||||
char *str_key; |
||||
char *str_val; |
||||
size_t key_len; |
||||
MAKE_STD_ZVAL(array); |
||||
array_init(array); |
||||
array_hash = Z_ARRVAL_P(array); |
||||
grpc_metadata *elem; |
||||
for(i=0; i<count; i++){ |
||||
elem = &elements[i]; |
||||
key_len = strlen(elem->key); |
||||
str_key = ecalloc(key_len+1, sizeof(char)); |
||||
memcpy(str_key, elem->key, key_len); |
||||
str_val = ecalloc(elem->value_length+1, sizeof(char)); |
||||
memcpy(str_val, elem->value, elem->value_length); |
||||
if(zend_hash_find(array_hash, |
||||
str_key, |
||||
key_len, |
||||
(void**)data) == SUCCESS){ |
||||
switch(Z_TYPE_P(*data)){ |
||||
case IS_STRING: |
||||
MAKE_STD_ZVAL(inner_array); |
||||
array_init(inner_array); |
||||
add_next_index_zval(inner_array, *data); |
||||
add_assoc_zval(array, str_key, inner_array); |
||||
break; |
||||
case IS_ARRAY: |
||||
inner_array = *data; |
||||
break; |
||||
default: |
||||
zend_throw_exception(zend_exception_get_default(), |
||||
"Metadata hash somehow contains wrong types.", |
||||
1 TSRMLS_CC); |
||||
efree(str_key); |
||||
efree(str_val); |
||||
return NULL; |
||||
} |
||||
add_next_index_stringl(inner_array, |
||||
str_val, |
||||
elem->value_length, |
||||
false); |
||||
} else { |
||||
add_assoc_stringl(array, |
||||
str_key, |
||||
str_val, |
||||
elem->value_length, |
||||
false); |
||||
} |
||||
} |
||||
return array; |
||||
} |
||||
|
||||
int php_grpc_call_add_metadata_array_walk(void *elem TSRMLS_DC, |
||||
int num_args, |
||||
va_list args, |
||||
zend_hash_key *hash_key){ |
||||
zval **data = (zval**)elem; |
||||
grpc_metadata metadata; |
||||
grpc_call *call = va_arg(args, grpc_call*); |
||||
gpr_uint32 flags = va_arg(args, gpr_uint32); |
||||
const char *key; |
||||
HashTable *inner_hash; |
||||
/* We assume that either two args were passed, and we are in the recursive
|
||||
case (and the second argument is the key), or one arg was passed and |
||||
hash_key is the string key. */ |
||||
if(num_args > 2){ |
||||
key = va_arg(args, const char*); |
||||
} else { |
||||
/* TODO(mlumish): If possible, check that hash_key is a string */ |
||||
key = hash_key->arKey; |
||||
} |
||||
switch(Z_TYPE_P(*data)){ |
||||
case IS_STRING: |
||||
metadata.key = (char*)key; |
||||
metadata.value = Z_STRVAL_P(*data); |
||||
metadata.value_length = Z_STRLEN_P(*data); |
||||
grpc_call_add_metadata(call, &metadata, 0u); |
||||
break; |
||||
case IS_ARRAY: |
||||
inner_hash = Z_ARRVAL_P(*data); |
||||
zend_hash_apply_with_arguments(inner_hash TSRMLS_CC, |
||||
php_grpc_call_add_metadata_array_walk, |
||||
3, |
||||
call, |
||||
flags, |
||||
key); |
||||
break; |
||||
default: |
||||
zend_throw_exception(zend_exception_get_default(), |
||||
"Metadata hash somehow contains wrong types.", |
||||
1 TSRMLS_CC); |
||||
} |
||||
return ZEND_HASH_APPLY_KEEP; |
||||
} |
||||
|
||||
/**
|
||||
* Constructs a new instance of the Call class. |
||||
* @param Channel $channel The channel to associate the call with. Must not be |
||||
* closed. |
||||
* @param string $method The method to call |
||||
* @param Timeval $absolute_deadline The deadline for completing the call |
||||
*/ |
||||
PHP_METHOD(Call, __construct){ |
||||
wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
zval *channel_obj; |
||||
char *method; |
||||
int method_len; |
||||
zval *deadline_obj; |
||||
/* "OsO" == 1 Object, 1 string, 1 Object */ |
||||
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); |
||||
return; |
||||
} |
||||
wrapped_grpc_channel *channel = |
||||
(wrapped_grpc_channel*)zend_object_store_get_object(channel_obj TSRMLS_CC); |
||||
if(channel->wrapped == NULL) { |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"Call cannot be constructed from a closed Channel", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
add_property_zval(getThis(), "channel", channel_obj); |
||||
wrapped_grpc_timeval *deadline = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(deadline_obj TSRMLS_CC); |
||||
call->wrapped = grpc_channel_create_call(channel->wrapped, |
||||
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 |
||||
*/ |
||||
PHP_METHOD(Call, add_metadata){ |
||||
wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
zval *array; |
||||
HashTable *array_hash; |
||||
long flags = 0; |
||||
/* "a|l" == 1 array, 1 optional long */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"a|l", |
||||
&array, |
||||
&flags) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"add_metadata expects an array and an optional long", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
array_hash = Z_ARRVAL_P(array); |
||||
zend_hash_apply_with_arguments(array_hash TSRMLS_CC, |
||||
php_grpc_call_add_metadata_array_walk, |
||||
2, |
||||
call->wrapped, |
||||
(gpr_uint32)flags); |
||||
} |
||||
|
||||
/**
|
||||
* 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 $invoke_accepted_tag The tag to associate with this invocation |
||||
* @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 long Error code |
||||
*/ |
||||
PHP_METHOD(Call, start_invoke){ |
||||
long tag1; |
||||
long tag2; |
||||
long tag3; |
||||
zval *queue_obj; |
||||
long flags = 0; |
||||
/* "Olll|l" == 1 Object, 3 mandatory longs, 1 optional long */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"Olll|l", |
||||
&queue_obj, grpc_ce_completion_queue, |
||||
&tag1, |
||||
&tag2, |
||||
&tag3, |
||||
&flags) == FAILURE){ |
||||
zend_throw_exception( |
||||
spl_ce_InvalidArgumentException, |
||||
"start_invoke needs a CompletionQueue, 3 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); |
||||
RETURN_LONG(grpc_call_start_invoke(call->wrapped, |
||||
queue->wrapped, |
||||
(void*)tag1, |
||||
(void*)tag2, |
||||
(void*)tag3, |
||||
(gpr_uint32)flags)); |
||||
} |
||||
|
||||
/**
|
||||
* 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 long Error code |
||||
*/ |
||||
PHP_METHOD(Call, accept){ |
||||
long tag; |
||||
zval *queue_obj; |
||||
long flags = 0; |
||||
/* "Ol|l" == 1 Object, 1 mandatory long, 1 optional long */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"Ol|l", |
||||
&queue_obj, grpc_ce_completion_queue, |
||||
&tag, |
||||
&flags) == FAILURE){ |
||||
zend_throw_exception( |
||||
spl_ce_InvalidArgumentException, |
||||
"accept expects a CompletionQueue, a long, 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); |
||||
RETURN_LONG(grpc_call_accept(call->wrapped, |
||||
queue->wrapped, |
||||
(void*)tag, |
||||
(gpr_uint32)flags)); |
||||
} |
||||
|
||||
/**
|
||||
* Called by clients to cancel an RPC on the server. |
||||
* @return long Error code |
||||
*/ |
||||
PHP_METHOD(Call, cancel){ |
||||
wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
RETURN_LONG(grpc_call_cancel(call->wrapped)); |
||||
} |
||||
|
||||
/**
|
||||
* 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 long Error code |
||||
*/ |
||||
PHP_METHOD(Call, start_write){ |
||||
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", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
RETURN_LONG(grpc_call_start_write(call->wrapped, |
||||
string_to_byte_buffer(buffer, buffer_len), |
||||
(void*)tag, |
||||
(gpr_uint32)flags)); |
||||
} |
||||
|
||||
/**
|
||||
* 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 long Error code |
||||
*/ |
||||
PHP_METHOD(Call, start_write_status){ |
||||
wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
long status_code; |
||||
int status_details_length; |
||||
long tag; |
||||
grpc_status status; |
||||
/* "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; |
||||
} |
||||
status.code = (gpr_uint32)status_code; |
||||
RETURN_LONG(grpc_call_start_write_status(call->wrapped, |
||||
status, |
||||
(void*)tag)); |
||||
} |
||||
|
||||
/**
|
||||
* Indicate that there are no more messages to send |
||||
* @return long Error code |
||||
*/ |
||||
PHP_METHOD(Call, writes_done){ |
||||
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; |
||||
} |
||||
RETURN_LONG(grpc_call_writes_done(call->wrapped, (void*)tag)); |
||||
} |
||||
|
||||
/**
|
||||
* 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 long Error code |
||||
*/ |
||||
PHP_METHOD(Call, start_read){ |
||||
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; |
||||
} |
||||
RETURN_LONG(grpc_call_start_read(call->wrapped, (void*)tag)); |
||||
} |
||||
|
||||
static zend_function_entry call_methods[] = { |
||||
PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) |
||||
PHP_ME(Call, accept, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Call, start_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 |
||||
}; |
||||
|
||||
void grpc_init_call(TSRMLS_D){ |
||||
zend_class_entry ce; |
||||
INIT_CLASS_ENTRY(ce, "Grpc\\Call", call_methods); |
||||
ce.create_object = create_wrapped_grpc_call; |
||||
grpc_ce_call = zend_register_internal_class(&ce TSRMLS_CC); |
||||
} |
@ -0,0 +1,35 @@ |
||||
#ifndef NET_GRPC_PHP_GRPC_CALL_H_ |
||||
#define NET_GRPC_PHP_GRPC_CALL_H_ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
|
||||
/* Class entry for the Call PHP class */ |
||||
zend_class_entry *grpc_ce_call; |
||||
|
||||
/* Wrapper struct for grpc_call that can be associated with a PHP object */ |
||||
typedef struct wrapped_grpc_call { |
||||
zend_object std; |
||||
|
||||
grpc_call *wrapped; |
||||
} wrapped_grpc_call; |
||||
|
||||
/* Initializes the Call PHP class */ |
||||
void grpc_init_call(TSRMLS_D); |
||||
|
||||
/* Creates a Call object that wraps the given grpc_call struct */ |
||||
zval *grpc_php_wrap_call(grpc_call *wrapped); |
||||
|
||||
/* Creates and returns a PHP associative array of metadata from a C array of
|
||||
* call metadata */ |
||||
zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements); |
||||
|
||||
#endif /* NET_GRPC_PHP_GRPC_CHANNEL_H_ */ |
@ -0,0 +1,182 @@ |
||||
#include "channel.h" |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "ext/spl/spl_exceptions.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "zend_exceptions.h" |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "grpc/grpc.h" |
||||
#include "grpc/support/log.h" |
||||
#include "grpc/grpc_security.h" |
||||
|
||||
#include "completion_queue.h" |
||||
#include "server.h" |
||||
#include "credentials.h" |
||||
|
||||
/* Frees and destroys an instance of wrapped_grpc_channel */ |
||||
void free_wrapped_grpc_channel(void *object TSRMLS_DC){ |
||||
wrapped_grpc_channel *channel = (wrapped_grpc_channel*)object; |
||||
if(channel->wrapped != NULL){ |
||||
grpc_channel_destroy(channel->wrapped); |
||||
} |
||||
efree(channel); |
||||
} |
||||
|
||||
/* Initializes an instance of wrapped_grpc_channel to be associated with an
|
||||
* object of a class specified by class_type */ |
||||
zend_object_value create_wrapped_grpc_channel( |
||||
zend_class_entry *class_type TSRMLS_DC){ |
||||
zend_object_value retval; |
||||
wrapped_grpc_channel *intern; |
||||
intern = (wrapped_grpc_channel*)emalloc(sizeof(wrapped_grpc_channel)); |
||||
memset(intern, 0, sizeof(wrapped_grpc_channel)); |
||||
zend_object_std_init(&intern->std, class_type TSRMLS_CC); |
||||
object_properties_init(&intern->std, class_type); |
||||
retval.handle = zend_objects_store_put( |
||||
intern, |
||||
(zend_objects_store_dtor_t)zend_objects_destroy_object, |
||||
free_wrapped_grpc_channel, |
||||
NULL TSRMLS_CC); |
||||
retval.handlers = zend_get_std_object_handlers(); |
||||
return retval; |
||||
} |
||||
|
||||
void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args){ |
||||
HashTable *array_hash; |
||||
HashPosition array_pointer; |
||||
int args_index; |
||||
zval **data; |
||||
char *key; |
||||
uint key_len; |
||||
ulong index; |
||||
array_hash = Z_ARRVAL_P(args_array); |
||||
args->num_args = zend_hash_num_elements(array_hash); |
||||
args->args = ecalloc(args->num_args, sizeof(grpc_arg)); |
||||
args_index = 0; |
||||
for(zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer); |
||||
zend_hash_get_current_data_ex(array_hash, |
||||
(void**)&data, |
||||
&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){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"args keys must be strings", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
args->args[args_index].key = key; |
||||
switch(Z_TYPE_P(*data)){ |
||||
case IS_LONG: |
||||
args->args[args_index].value.integer = (int)Z_LVAL_P(*data); |
||||
break; |
||||
case IS_STRING: |
||||
args->args[args_index].value.string = Z_STRVAL_P(*data); |
||||
break; |
||||
default: |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"args values must be int or string", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
args_index++; |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Construct an instance of the Channel class. If the $args array contains a |
||||
* "credentials" key mapping to a Credentials object, a secure channel will be |
||||
* created with those credentials. |
||||
* @param string $target The hostname to associate with this channel |
||||
* @param array $args The arguments to pass to the Channel (optional) |
||||
*/ |
||||
PHP_METHOD(Channel, __construct){ |
||||
wrapped_grpc_channel *channel = |
||||
(wrapped_grpc_channel*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
char *target; |
||||
int target_length; |
||||
zval *args_array = NULL; |
||||
grpc_channel_args args; |
||||
HashTable *array_hash; |
||||
zval **creds_obj = NULL; |
||||
wrapped_grpc_credentials *creds = NULL; |
||||
/* "s|a" == 1 string, 1 optional array */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"s|a", |
||||
&target, &target_length, |
||||
&args_array) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"Channel expects a string and an array", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
if (args_array == NULL) { |
||||
channel->wrapped = grpc_channel_create(target, NULL); |
||||
} else { |
||||
array_hash = Z_ARRVAL_P(args_array); |
||||
if(zend_hash_find(array_hash, |
||||
"credentials", |
||||
sizeof("credentials"), |
||||
(void**)&creds_obj) == SUCCESS) { |
||||
if(zend_get_class_entry(*creds_obj TSRMLS_CC) != grpc_ce_credentials) { |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"credentials must be a Credentials object", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
creds = (wrapped_grpc_credentials*)zend_object_store_get_object( |
||||
*creds_obj TSRMLS_CC); |
||||
zend_hash_del(array_hash, "credentials", 12); |
||||
} |
||||
php_grpc_read_args_array(args_array, &args); |
||||
if (creds == NULL) { |
||||
channel->wrapped = grpc_channel_create(target, &args); |
||||
} else { |
||||
gpr_log(GPR_DEBUG, "Initialized secure channel"); |
||||
channel->wrapped = grpc_secure_channel_create(creds->wrapped, |
||||
target, |
||||
&args); |
||||
} |
||||
efree(args.args); |
||||
} |
||||
channel->target = ecalloc(target_length+1, sizeof(char)); |
||||
memcpy(channel->target, target, target_length); |
||||
} |
||||
|
||||
/**
|
||||
* Close the channel |
||||
*/ |
||||
PHP_METHOD(Channel, close){ |
||||
wrapped_grpc_channel *channel = |
||||
(wrapped_grpc_channel*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
if(channel->wrapped != NULL) { |
||||
grpc_channel_destroy(channel->wrapped); |
||||
channel->wrapped = NULL; |
||||
} |
||||
} |
||||
|
||||
static zend_function_entry channel_methods[] = { |
||||
PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) |
||||
PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_FE_END |
||||
}; |
||||
|
||||
void grpc_init_channel(TSRMLS_D){ |
||||
zend_class_entry ce; |
||||
INIT_CLASS_ENTRY(ce, "Grpc\\Channel", channel_methods); |
||||
ce.create_object = create_wrapped_grpc_channel; |
||||
grpc_ce_channel = zend_register_internal_class(&ce TSRMLS_CC); |
||||
} |
@ -0,0 +1,32 @@ |
||||
#ifndef NET_GRPC_PHP_GRPC_CHANNEL_H_ |
||||
#define NET_GRPC_PHP_GRPC_CHANNEL_H_ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
|
||||
/* Class entry for the PHP Channel class */ |
||||
zend_class_entry *grpc_ce_channel; |
||||
|
||||
/* Wrapper struct for grpc_channel that can be associated with a PHP object */ |
||||
typedef struct wrapped_grpc_channel { |
||||
zend_object std; |
||||
|
||||
grpc_channel *wrapped; |
||||
char *target; |
||||
} wrapped_grpc_channel; |
||||
|
||||
/* Initializes the Channel class */ |
||||
void grpc_init_channel(TSRMLS_D); |
||||
|
||||
/* Iterates through a PHP array and populates args with the contents */ |
||||
void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args); |
||||
|
||||
#endif /* NET_GRPC_PHP_GRPC_CHANNEL_H_ */ |
@ -0,0 +1,145 @@ |
||||
#include "completion_queue.h" |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "ext/spl/spl_exceptions.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "zend_exceptions.h" |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "grpc/grpc.h" |
||||
|
||||
#include "event.h" |
||||
#include "timeval.h" |
||||
|
||||
/* Frees and destroys a wrapped instance of grpc_completion_queue */ |
||||
void free_wrapped_grpc_completion_queue(void *object TSRMLS_DC){ |
||||
wrapped_grpc_completion_queue *queue = NULL; |
||||
grpc_event *event; |
||||
queue = (wrapped_grpc_completion_queue*)object; |
||||
if(queue->wrapped != NULL){ |
||||
grpc_completion_queue_shutdown(queue->wrapped); |
||||
event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future); |
||||
while(event != NULL){ |
||||
if(event->type == GRPC_QUEUE_SHUTDOWN){ |
||||
break; |
||||
} |
||||
event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future); |
||||
} |
||||
grpc_completion_queue_destroy(queue->wrapped); |
||||
} |
||||
efree(queue); |
||||
} |
||||
|
||||
/* Initializes an instance of wrapped_grpc_channel to be associated with an
|
||||
* object of a class specified by class_type */ |
||||
zend_object_value create_wrapped_grpc_completion_queue( |
||||
zend_class_entry *class_type TSRMLS_DC){ |
||||
zend_object_value retval; |
||||
wrapped_grpc_completion_queue *intern; |
||||
|
||||
intern = (wrapped_grpc_completion_queue*)emalloc( |
||||
sizeof(wrapped_grpc_completion_queue)); |
||||
memset(intern, 0, sizeof(wrapped_grpc_completion_queue)); |
||||
|
||||
zend_object_std_init(&intern->std, class_type TSRMLS_CC); |
||||
object_properties_init(&intern->std, class_type); |
||||
retval.handle = zend_objects_store_put( |
||||
intern, |
||||
(zend_objects_store_dtor_t) zend_objects_destroy_object, |
||||
free_wrapped_grpc_completion_queue, |
||||
NULL TSRMLS_CC); |
||||
retval.handlers = zend_get_std_object_handlers(); |
||||
return retval; |
||||
} |
||||
|
||||
/**
|
||||
* Construct an instance of CompletionQueue |
||||
*/ |
||||
PHP_METHOD(CompletionQueue, __construct){ |
||||
wrapped_grpc_completion_queue *queue = |
||||
(wrapped_grpc_completion_queue*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
queue->wrapped = grpc_completion_queue_create(); |
||||
} |
||||
|
||||
/**
|
||||
* Blocks until an event is available, the completion queue is being shutdown, |
||||
* or timeout is reached. Returns NULL on timeout, otherwise the event that |
||||
* occurred. Callers should call event.finish once they have processed the |
||||
* event. |
||||
* @param Timeval $timeout The timeout for the event |
||||
* @return Event The event that occurred |
||||
*/ |
||||
PHP_METHOD(CompletionQueue, next){ |
||||
zval *timeout; |
||||
/* "O" == 1 Object */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"O", |
||||
&timeout, grpc_ce_timeval)==FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"next needs a Timeval", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
wrapped_grpc_completion_queue *completion_queue = |
||||
(wrapped_grpc_completion_queue*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
wrapped_grpc_timeval *wrapped_timeout = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(timeout TSRMLS_CC); |
||||
grpc_event *event = grpc_completion_queue_next(completion_queue->wrapped, |
||||
wrapped_timeout->wrapped); |
||||
if(event == NULL){ |
||||
RETURN_NULL(); |
||||
} |
||||
zval *wrapped_event = grpc_php_wrap_event(event); |
||||
RETURN_DESTROY_ZVAL(wrapped_event); |
||||
} |
||||
|
||||
PHP_METHOD(CompletionQueue, pluck){ |
||||
long tag; |
||||
zval *timeout; |
||||
/* "lO" == 1 long, 1 Object */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"lO", |
||||
&tag, |
||||
&timeout, grpc_ce_timeval)==FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"pluck needs a long and a Timeval", |
||||
1 TSRMLS_CC); |
||||
} |
||||
wrapped_grpc_completion_queue *completion_queue = |
||||
(wrapped_grpc_completion_queue*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
wrapped_grpc_timeval *wrapped_timeout = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(timeout TSRMLS_CC); |
||||
grpc_event *event = grpc_completion_queue_pluck(completion_queue->wrapped, |
||||
(void*)tag, |
||||
wrapped_timeout->wrapped); |
||||
if(event == NULL){ |
||||
RETURN_NULL(); |
||||
} |
||||
zval *wrapped_event = grpc_php_wrap_event(event); |
||||
RETURN_DESTROY_ZVAL(wrapped_event); |
||||
} |
||||
|
||||
static zend_function_entry completion_queue_methods[] = { |
||||
PHP_ME(CompletionQueue, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) |
||||
PHP_ME(CompletionQueue, next, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(CompletionQueue, pluck, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_FE_END |
||||
}; |
||||
|
||||
void grpc_init_completion_queue(TSRMLS_D){ |
||||
zend_class_entry ce; |
||||
INIT_CLASS_ENTRY(ce, "Grpc\\CompletionQueue", completion_queue_methods); |
||||
ce.create_object = create_wrapped_grpc_completion_queue; |
||||
grpc_ce_completion_queue = zend_register_internal_class(&ce TSRMLS_CC); |
||||
} |
@ -0,0 +1,29 @@ |
||||
#ifndef NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_ |
||||
#define NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
|
||||
/* Class entry for the PHP CompletionQueue class */ |
||||
zend_class_entry *grpc_ce_completion_queue; |
||||
|
||||
/* Wrapper class for grpc_completion_queue that can be associated with a
|
||||
PHP object */ |
||||
typedef struct wrapped_grpc_completion_queue { |
||||
zend_object std; |
||||
|
||||
grpc_completion_queue *wrapped; |
||||
} wrapped_grpc_completion_queue; |
||||
|
||||
/* Initialize the CompletionQueue class */ |
||||
void grpc_init_completion_queue(TSRMLS_D); |
||||
|
||||
#endif /* NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_ */ |
@ -0,0 +1,74 @@ |
||||
PHP_ARG_ENABLE(grpc, whether to enable grpc support, |
||||
[ --enable-grpc Enable grpc support]) |
||||
|
||||
if test "$PHP_GRPC" != "no"; then |
||||
dnl Write more examples of tests here... |
||||
|
||||
dnl # --with-grpc -> check with-path |
||||
SEARCH_PATH="/usr/local /usr $HOME/grpc_dev" # you might want to change this |
||||
SEARCH_FOR="include/grpc/grpc.h" # you most likely want to change this |
||||
if test -r $PHP_GRPC/$SEARCH_FOR; then # path given as parameter |
||||
GRPC_DIR=$PHP_GRPC |
||||
else # search default path list |
||||
AC_MSG_CHECKING([for grpc files in default path]) |
||||
for i in $SEARCH_PATH ; do |
||||
if test -r $i/$SEARCH_FOR; then |
||||
GRPC_DIR=$i |
||||
AC_MSG_RESULT(found in $i) |
||||
fi |
||||
done |
||||
fi |
||||
if test -z "$GRPC_DIR"; then |
||||
AC_MSG_RESULT([not found]) |
||||
AC_MSG_ERROR([Please reinstall the grpc distribution]) |
||||
fi |
||||
|
||||
dnl # --with-grpc -> add include path |
||||
PHP_ADD_INCLUDE($GRPC_DIR/include) |
||||
|
||||
LIBS="-lpthread $LIBS" |
||||
|
||||
dnl PHP_ADD_LIBRARY(pthread,,GRPC_SHARED_LIBADD) |
||||
GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD" |
||||
PHP_ADD_LIBRARY(pthread) |
||||
|
||||
PHP_ADD_LIBRARY(rt,,GRPC_SHARED_LIBADD) |
||||
PHP_ADD_LIBRARY(rt) |
||||
|
||||
PHP_ADD_LIBPATH($GRPC_DIR/lib) |
||||
|
||||
PHP_CHECK_LIBRARY(gpr,gpr_now, |
||||
[ |
||||
PHP_ADD_LIBRARY(gpr,,GRPC_SHARED_LIBADD) |
||||
PHP_ADD_LIBRARY(gpr) |
||||
AC_DEFINE(HAVE_GPRLIB,1,[ ]) |
||||
],[ |
||||
AC_MSG_ERROR([wrong gpr lib version or lib not found]) |
||||
],[ |
||||
-L$GRPC_DIR/lib |
||||
]) |
||||
|
||||
PHP_ADD_LIBRARY(event,,GRPC_SHARED_LIBADD) |
||||
PHP_ADD_LIBRARY(event) |
||||
|
||||
PHP_ADD_LIBRARY(event_pthreads,,GRPC_SHARED_LIBADD) |
||||
PHP_ADD_LIBRARY(event_pthreads) |
||||
|
||||
PHP_ADD_LIBRARY(event_core,,GRPC_SHARED_LIBADD) |
||||
PHP_ADD_LIBRARY(event_core) |
||||
|
||||
PHP_CHECK_LIBRARY(grpc,grpc_channel_destroy, |
||||
[ |
||||
PHP_ADD_LIBRARY(grpc,,GRPC_SHARED_LIBADD) |
||||
dnl PHP_ADD_LIBRARY_WITH_PATH(grpc, $GRPC_DIR/lib, GRPC_SHARED_LIBADD) |
||||
AC_DEFINE(HAVE_GRPCLIB,1,[ ]) |
||||
],[ |
||||
AC_MSG_ERROR([wrong grpc lib version or lib not found]) |
||||
],[ |
||||
-L$GRPC_DIR/lib |
||||
]) |
||||
|
||||
PHP_SUBST(GRPC_SHARED_LIBADD) |
||||
|
||||
PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c completion_queue.c credentials.c event.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -pedantic -std=c99) |
||||
fi |
@ -0,0 +1,171 @@ |
||||
#include "credentials.h" |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "ext/spl/spl_exceptions.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "zend_exceptions.h" |
||||
#include "zend_hash.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
#include "grpc/grpc_security.h" |
||||
|
||||
/* Frees and destroys an instance of wrapped_grpc_credentials */ |
||||
void free_wrapped_grpc_credentials(void *object TSRMLS_DC){ |
||||
wrapped_grpc_credentials *creds = (wrapped_grpc_credentials*)object; |
||||
if(creds->wrapped != NULL) { |
||||
grpc_credentials_release(creds->wrapped); |
||||
} |
||||
efree(creds); |
||||
} |
||||
|
||||
/* Initializes an instance of wrapped_grpc_credentials to be associated with an
|
||||
* object of a class specified by class_type */ |
||||
zend_object_value create_wrapped_grpc_credentials( |
||||
zend_class_entry *class_type TSRMLS_DC){ |
||||
zend_object_value retval; |
||||
wrapped_grpc_credentials *intern; |
||||
|
||||
intern = (wrapped_grpc_credentials*)emalloc(sizeof(wrapped_grpc_credentials)); |
||||
memset(intern, 0, sizeof(wrapped_grpc_credentials)); |
||||
|
||||
zend_object_std_init(&intern->std, class_type TSRMLS_CC); |
||||
object_properties_init(&intern->std, class_type); |
||||
retval.handle = zend_objects_store_put( |
||||
intern, |
||||
(zend_objects_store_dtor_t) zend_objects_destroy_object, |
||||
free_wrapped_grpc_credentials, |
||||
NULL TSRMLS_CC); |
||||
retval.handlers = zend_get_std_object_handlers(); |
||||
return retval; |
||||
} |
||||
|
||||
zval *grpc_php_wrap_credentials(grpc_credentials *wrapped){ |
||||
zval *credentials_object; |
||||
MAKE_STD_ZVAL(credentials_object); |
||||
object_init_ex(credentials_object, grpc_ce_credentials); |
||||
wrapped_grpc_credentials *credentials = |
||||
(wrapped_grpc_credentials*)zend_object_store_get_object( |
||||
credentials_object TSRMLS_CC); |
||||
credentials->wrapped = wrapped; |
||||
return credentials_object; |
||||
} |
||||
|
||||
/**
|
||||
* Create a default credentials object. |
||||
* @return Credentials The new default credentials object |
||||
*/ |
||||
PHP_METHOD(Credentials, createDefault){ |
||||
grpc_credentials *creds = grpc_default_credentials_create(); |
||||
zval *creds_object = grpc_php_wrap_credentials(creds); |
||||
RETURN_DESTROY_ZVAL(creds_object); |
||||
} |
||||
|
||||
/**
|
||||
* Create SSL credentials. |
||||
* @param string pem_root_certs PEM encoding of the server root certificates |
||||
* @param string pem_private_key PEM encoding of the client's private key |
||||
* (optional) |
||||
* @param string pem_cert_chain PEM encoding of the client's certificate chain |
||||
* (optional) |
||||
* @return Credentials The new SSL credentials object |
||||
*/ |
||||
PHP_METHOD(Credentials, createSsl){ |
||||
char *pem_root_certs; |
||||
char *pem_private_key = NULL; |
||||
char *pem_cert_chain = NULL; |
||||
|
||||
int root_certs_length, private_key_length = 0, cert_chain_length = 0; |
||||
|
||||
/* "s|s!s! == 1 string, 2 optional nullable strings */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"s|s!s!", |
||||
&pem_root_certs, &root_certs_length, |
||||
&pem_private_key, &private_key_length, |
||||
&pem_cert_chain, &cert_chain_length) == FAILURE) { |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"createSsl expects 1 to 3 strings", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
grpc_credentials *creds = grpc_ssl_credentials_create( |
||||
(unsigned char*)pem_root_certs, (size_t)root_certs_length, |
||||
(unsigned char*)pem_private_key, (size_t)private_key_length, |
||||
(unsigned char*)pem_cert_chain, (size_t)cert_chain_length); |
||||
zval *creds_object = grpc_php_wrap_credentials(creds); |
||||
RETURN_DESTROY_ZVAL(creds_object); |
||||
} |
||||
|
||||
/**
|
||||
* Create composite credentials from two existing credentials. |
||||
* @param Credentials cred1 The first credential |
||||
* @param Credentials cred2 The second credential |
||||
* @return Credentials The new composite credentials object |
||||
*/ |
||||
PHP_METHOD(Credentials, createComposite){ |
||||
zval *cred1_obj; |
||||
zval *cred2_obj; |
||||
|
||||
/* "OO" == 3 Objects */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"OO", |
||||
&cred1_obj, grpc_ce_credentials, |
||||
&cred2_obj, grpc_ce_credentials) == FAILURE) { |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"createComposite expects 2 Credentials", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
wrapped_grpc_credentials *cred1 = |
||||
(wrapped_grpc_credentials*)zend_object_store_get_object( |
||||
cred1_obj TSRMLS_CC); |
||||
wrapped_grpc_credentials *cred2 = |
||||
(wrapped_grpc_credentials*)zend_object_store_get_object( |
||||
cred2_obj TSRMLS_CC); |
||||
grpc_credentials *creds = grpc_composite_credentials_create(cred1->wrapped, |
||||
cred2->wrapped); |
||||
zval *creds_object = grpc_php_wrap_credentials(creds); |
||||
RETURN_DESTROY_ZVAL(creds_object); |
||||
} |
||||
|
||||
/**
|
||||
* Create Google Compute Engine credentials |
||||
* @return Credentials The new GCE credentials object |
||||
*/ |
||||
PHP_METHOD(Credentials, createGce) { |
||||
grpc_credentials *creds = grpc_compute_engine_credentials_create(); |
||||
zval *creds_object = grpc_php_wrap_credentials(creds); |
||||
RETURN_DESTROY_ZVAL(creds_object); |
||||
} |
||||
|
||||
/**
|
||||
* Create fake credentials. Only to be used for testing. |
||||
* @return Credentials The new fake credentials object |
||||
*/ |
||||
PHP_METHOD(Credentials, createFake) { |
||||
grpc_credentials *creds = grpc_fake_transport_security_credentials_create(); |
||||
zval *creds_object = grpc_php_wrap_credentials(creds); |
||||
RETURN_DESTROY_ZVAL(creds_object); |
||||
} |
||||
|
||||
static zend_function_entry credentials_methods[] = { |
||||
PHP_ME(Credentials, createDefault, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Credentials, createSsl, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Credentials, createComposite, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Credentials, createGce, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Credentials, createFake, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_FE_END |
||||
}; |
||||
|
||||
void grpc_init_credentials(TSRMLS_D){ |
||||
zend_class_entry ce; |
||||
INIT_CLASS_ENTRY(ce, "Grpc\\Credentials", credentials_methods); |
||||
ce.create_object = create_wrapped_grpc_credentials; |
||||
grpc_ce_credentials = zend_register_internal_class(&ce TSRMLS_CC); |
||||
} |
@ -0,0 +1,30 @@ |
||||
#ifndef NET_GRPC_PHP_GRPC_CREDENTIALS_H_ |
||||
#define NET_GRPC_PHP_GRPC_CREDENTIALS_H_ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
#include "grpc/grpc_security.h" |
||||
|
||||
/* Class entry for the Credentials PHP class */ |
||||
zend_class_entry *grpc_ce_credentials; |
||||
|
||||
/* Wrapper struct for grpc_credentials that can be associated with a PHP
|
||||
* object */ |
||||
typedef struct wrapped_grpc_credentials { |
||||
zend_object std; |
||||
|
||||
grpc_credentials *wrapped; |
||||
} wrapped_grpc_credentials; |
||||
|
||||
/* Initializes the Credentials PHP class */ |
||||
void grpc_init_credentials(TSRMLS_D); |
||||
|
||||
#endif /* NET_GRPC_PHP_GRPC_CREDENTIALS_H_ */ |
@ -0,0 +1,191 @@ |
||||
#include "event.h" |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "grpc/grpc.h" |
||||
|
||||
#include "byte_buffer.h" |
||||
#include "call.h" |
||||
#include "timeval.h" |
||||
|
||||
/* Frees and finishes a wrapped instance of grpc_event */ |
||||
void free_wrapped_grpc_event(void *object TSRMLS_DC){ |
||||
wrapped_grpc_event *event = (wrapped_grpc_event*)object; |
||||
if(event->wrapped != NULL){ |
||||
grpc_event_finish(event->wrapped); |
||||
} |
||||
efree(event); |
||||
} |
||||
|
||||
/* Initializes an instance of wrapped_grpc_channel to be associated with an
|
||||
* object of a class specified by class_type */ |
||||
zend_object_value create_wrapped_grpc_event( |
||||
zend_class_entry *class_type TSRMLS_DC){ |
||||
zend_object_value retval; |
||||
wrapped_grpc_event *intern; |
||||
intern = (wrapped_grpc_event*)emalloc(sizeof(wrapped_grpc_event)); |
||||
memset(intern, 0, sizeof(wrapped_grpc_event)); |
||||
zend_object_std_init(&intern->std, class_type TSRMLS_CC); |
||||
object_properties_init(&intern->std, class_type); |
||||
retval.handle = zend_objects_store_put( |
||||
intern, |
||||
(zend_objects_store_dtor_t)zend_objects_destroy_object, |
||||
free_wrapped_grpc_event, |
||||
NULL TSRMLS_CC); |
||||
retval.handlers = zend_get_std_object_handlers(); |
||||
return retval; |
||||
} |
||||
|
||||
zval *grpc_php_wrap_event(grpc_event *wrapped){ |
||||
zval *event_object; |
||||
MAKE_STD_ZVAL(event_object); |
||||
|
||||
object_init_ex(event_object, grpc_ce_event); |
||||
wrapped_grpc_event *event = (wrapped_grpc_event*)zend_object_store_get_object( |
||||
event_object TSRMLS_CC); |
||||
event->wrapped = wrapped; |
||||
return event_object; |
||||
} |
||||
|
||||
/**
|
||||
* Get the type of the event |
||||
* @return long Integer representing the type |
||||
*/ |
||||
PHP_METHOD(Event, get_type){ |
||||
wrapped_grpc_event *event = (wrapped_grpc_event*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
RETURN_LONG((long)(event->wrapped->type)); |
||||
} |
||||
|
||||
/**
|
||||
* Get the tag of the event |
||||
* @return long The event's tag |
||||
*/ |
||||
PHP_METHOD(Event, get_tag){ |
||||
wrapped_grpc_event *event = (wrapped_grpc_event*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
RETURN_LONG((long)(event->wrapped->tag)); |
||||
} |
||||
|
||||
/**
|
||||
* Get the call associated with the event |
||||
* @return Call The call |
||||
*/ |
||||
PHP_METHOD(Event, get_call){ |
||||
wrapped_grpc_event *event = (wrapped_grpc_event*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
zval *call_obj = grpc_php_wrap_call(event->wrapped->call); |
||||
RETURN_DESTROY_ZVAL(call_obj); |
||||
} |
||||
|
||||
/**
|
||||
* Get the data associated with the event |
||||
* @return object The data, with type depending on the type field |
||||
*/ |
||||
PHP_METHOD(Event, get_data){ |
||||
zval *retval; |
||||
wrapped_grpc_event *wrapped_event = |
||||
(wrapped_grpc_event*)zend_object_store_get_object( |
||||
getThis() TSRMLS_CC); |
||||
grpc_event *event = wrapped_event->wrapped; |
||||
char *detail_string; |
||||
size_t detail_len; |
||||
char *method_string; |
||||
size_t method_len; |
||||
char *host_string; |
||||
size_t host_len; |
||||
char *read_string; |
||||
size_t read_len; |
||||
|
||||
switch(event->type){ |
||||
case GRPC_QUEUE_SHUTDOWN: RETURN_NULL(); break; |
||||
case GRPC_READ: |
||||
if(event->data.read == NULL){ |
||||
RETURN_NULL(); |
||||
} else { |
||||
byte_buffer_to_string(event->data.read, &read_string, &read_len); |
||||
RETURN_STRINGL(read_string, read_len, true); |
||||
} |
||||
break; |
||||
case GRPC_INVOKE_ACCEPTED: |
||||
RETURN_LONG((long)event->data.invoke_accepted); break; |
||||
case GRPC_WRITE_ACCEPTED: |
||||
RETURN_LONG((long)event->data.write_accepted); break; |
||||
case GRPC_FINISH_ACCEPTED: |
||||
RETURN_LONG((long)event->data.finish_accepted); break; |
||||
case GRPC_CLIENT_METADATA_READ: |
||||
retval = grpc_call_create_metadata_array( |
||||
event->data.client_metadata_read.count, |
||||
event->data.client_metadata_read.elements); |
||||
break; |
||||
case GRPC_FINISHED: |
||||
MAKE_STD_ZVAL(retval); |
||||
object_init(retval); |
||||
add_property_long(retval, "code", event->data.finished.code); |
||||
if(event->data.finished.details == NULL){ |
||||
add_property_null(retval, "details"); |
||||
} else { |
||||
detail_len = strlen(event->data.finished.details); |
||||
detail_string = ecalloc(detail_len+1, sizeof(char)); |
||||
memcpy(detail_string, event->data.finished.details, detail_len); |
||||
add_property_string(retval, |
||||
"details", |
||||
detail_string, |
||||
true); |
||||
} |
||||
break; |
||||
case GRPC_SERVER_RPC_NEW: |
||||
MAKE_STD_ZVAL(retval); |
||||
object_init(retval); |
||||
method_len = strlen(event->data.server_rpc_new.method); |
||||
method_string = ecalloc(method_len+1, sizeof(char)); |
||||
memcpy(method_string, event->data.server_rpc_new.method, method_len); |
||||
add_property_string(retval, |
||||
"method", |
||||
method_string, |
||||
false); |
||||
host_len = strlen(event->data.server_rpc_new.host); |
||||
host_string = ecalloc(host_len+1, sizeof(char)); |
||||
memcpy(host_string, event->data.server_rpc_new.host, host_len); |
||||
add_property_string(retval, |
||||
"host", |
||||
host_string, |
||||
false); |
||||
add_property_zval(retval, |
||||
"absolute_timeout", |
||||
grpc_php_wrap_timeval( |
||||
event->data.server_rpc_new.deadline)); |
||||
add_property_zval(retval, |
||||
"metadata", |
||||
grpc_call_create_metadata_array( |
||||
event->data.server_rpc_new.metadata_count, |
||||
event->data.server_rpc_new.metadata_elements)); |
||||
break; |
||||
default: RETURN_NULL(); break; |
||||
} |
||||
RETURN_DESTROY_ZVAL(retval); |
||||
} |
||||
|
||||
static zend_function_entry event_methods[] = { |
||||
PHP_ME(Event, get_call, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Event, get_data, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Event, get_tag, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Event, get_type, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_FE_END |
||||
}; |
||||
|
||||
void grpc_init_event(TSRMLS_D){ |
||||
zend_class_entry ce; |
||||
INIT_CLASS_ENTRY(ce, "Grpc\\Event", event_methods); |
||||
ce.create_object = create_wrapped_grpc_event; |
||||
grpc_ce_event = zend_register_internal_class(&ce TSRMLS_CC); |
||||
} |
@ -0,0 +1,31 @@ |
||||
#ifndef NET_GRPC_PHP_GRPC_EVENT_H_ |
||||
#define NET_GRPC_PHP_GRPC_EVENT_H_ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
|
||||
/* Class entry for the PHP Event class */ |
||||
zend_class_entry *grpc_ce_event; |
||||
|
||||
/* Struct wrapping grpc_event that can be associated with a PHP object */ |
||||
typedef struct wrapped_grpc_event { |
||||
zend_object std; |
||||
|
||||
grpc_event *wrapped; |
||||
} wrapped_grpc_event; |
||||
|
||||
/* Initialize the Event class */ |
||||
void grpc_init_event(TSRMLS_D); |
||||
|
||||
/* Create a new Event object that wraps an existing grpc_event struct */ |
||||
zval *grpc_php_wrap_event(grpc_event *wrapped); |
||||
|
||||
#endif /* NET_GRPC_PHP_GRPC_COMPLETION_CHANNEL_H */ |
@ -0,0 +1,247 @@ |
||||
#include "call.h" |
||||
#include "channel.h" |
||||
#include "server.h" |
||||
#include "completion_queue.h" |
||||
#include "event.h" |
||||
#include "timeval.h" |
||||
#include "credentials.h" |
||||
#include "server_credentials.h" |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
//ZEND_DECLARE_MODULE_GLOBALS(grpc)
|
||||
|
||||
/* {{{ grpc_functions[]
|
||||
* |
||||
* Every user visible function must have an entry in grpc_functions[]. |
||||
*/ |
||||
const zend_function_entry grpc_functions[] = { |
||||
PHP_FE_END /* Must be the last line in grpc_functions[] */ |
||||
}; |
||||
/* }}} */ |
||||
|
||||
/* {{{ grpc_module_entry
|
||||
*/ |
||||
zend_module_entry grpc_module_entry = { |
||||
#if ZEND_MODULE_API_NO >= 20010901 |
||||
STANDARD_MODULE_HEADER, |
||||
#endif |
||||
"grpc", |
||||
grpc_functions, |
||||
PHP_MINIT(grpc), |
||||
PHP_MSHUTDOWN(grpc), |
||||
NULL, |
||||
NULL, |
||||
PHP_MINFO(grpc), |
||||
#if ZEND_MODULE_API_NO >= 20010901 |
||||
PHP_GRPC_VERSION, |
||||
#endif |
||||
STANDARD_MODULE_PROPERTIES |
||||
}; |
||||
/* }}} */ |
||||
|
||||
#ifdef COMPILE_DL_GRPC |
||||
ZEND_GET_MODULE(grpc) |
||||
#endif |
||||
|
||||
/* {{{ PHP_INI
|
||||
*/ |
||||
/* Remove comments and fill if you need to have entries in php.ini
|
||||
PHP_INI_BEGIN() |
||||
STD_PHP_INI_ENTRY("grpc.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_grpc_globals, grpc_globals) |
||||
STD_PHP_INI_ENTRY("grpc.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_grpc_globals, grpc_globals) |
||||
PHP_INI_END() |
||||
*/ |
||||
/* }}} */ |
||||
|
||||
/* {{{ php_grpc_init_globals
|
||||
*/ |
||||
/* Uncomment this function if you have INI entries
|
||||
static void php_grpc_init_globals(zend_grpc_globals *grpc_globals) |
||||
{ |
||||
grpc_globals->global_value = 0; |
||||
grpc_globals->global_string = NULL; |
||||
} |
||||
*/ |
||||
/* }}} */ |
||||
|
||||
/* {{{ PHP_MINIT_FUNCTION
|
||||
*/ |
||||
PHP_MINIT_FUNCTION(grpc) |
||||
{ |
||||
/* If you have INI entries, uncomment these lines
|
||||
REGISTER_INI_ENTRIES(); |
||||
*/ |
||||
/* Register call error constants */ |
||||
grpc_init(); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK, CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR", GRPC_CALL_ERROR, CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_SERVER", |
||||
GRPC_CALL_ERROR_NOT_ON_SERVER, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_CLIENT", |
||||
GRPC_CALL_ERROR_NOT_ON_CLIENT, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_INVOKED", |
||||
GRPC_CALL_ERROR_ALREADY_INVOKED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_INVOKED", |
||||
GRPC_CALL_ERROR_NOT_INVOKED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_FINISHED", |
||||
GRPC_CALL_ERROR_ALREADY_FINISHED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_TOO_MANY_OPERATIONS", |
||||
GRPC_CALL_ERROR_TOO_MANY_OPERATIONS, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_INVALID_FLAGS", |
||||
GRPC_CALL_ERROR_INVALID_FLAGS, |
||||
CONST_CS); |
||||
|
||||
/* Register op error constants */ |
||||
REGISTER_LONG_CONSTANT("Grpc\\OP_OK", GRPC_OP_OK, CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\OP_ERROR", GRPC_OP_ERROR, CONST_CS); |
||||
|
||||
/* Register flag constants */ |
||||
REGISTER_LONG_CONSTANT("Grpc\\WRITE_BUFFER_HINT", |
||||
GRPC_WRITE_BUFFER_HINT, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\WRITE_NO_COMPRESS", |
||||
GRPC_WRITE_NO_COMPRESS, |
||||
CONST_CS); |
||||
|
||||
/* Register completion type constants */ |
||||
REGISTER_LONG_CONSTANT("Grpc\\QUEUE_SHUTDOWN", |
||||
GRPC_QUEUE_SHUTDOWN, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\READ", GRPC_READ, CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\INVOKE_ACCEPTED", |
||||
GRPC_INVOKE_ACCEPTED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\WRITE_ACCEPTED", |
||||
GRPC_WRITE_ACCEPTED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\FINISH_ACCEPTED", |
||||
GRPC_FINISH_ACCEPTED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\CLIENT_METADATA_READ", |
||||
GRPC_CLIENT_METADATA_READ, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\FINISHED", GRPC_FINISHED, CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\SERVER_RPC_NEW", |
||||
GRPC_SERVER_RPC_NEW, |
||||
CONST_CS); |
||||
|
||||
/* Register status constants */ |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK", |
||||
GRPC_STATUS_OK, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_CANCELLED", |
||||
GRPC_STATUS_CANCELLED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNKNOWN", |
||||
GRPC_STATUS_UNKNOWN, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_INVALID_ARGUMENT", |
||||
GRPC_STATUS_INVALID_ARGUMENT, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_DEADLINE_EXCEEDED", |
||||
GRPC_STATUS_DEADLINE_EXCEEDED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_NOT_FOUND", |
||||
GRPC_STATUS_NOT_FOUND, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_ALREADY_EXISTS", |
||||
GRPC_STATUS_ALREADY_EXISTS, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_PERMISSION_DENIED", |
||||
GRPC_STATUS_PERMISSION_DENIED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAUTHENTICATED", |
||||
GRPC_STATUS_UNAUTHENTICATED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_RESOURCE_EXHAUSTED", |
||||
GRPC_STATUS_RESOURCE_EXHAUSTED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_FAILED_PRECONDITION", |
||||
GRPC_STATUS_FAILED_PRECONDITION, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_ABORTED", |
||||
GRPC_STATUS_ABORTED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE", |
||||
GRPC_STATUS_OUT_OF_RANGE, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNIMPLEMENTED", |
||||
GRPC_STATUS_UNIMPLEMENTED, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_INTERNAL", |
||||
GRPC_STATUS_INTERNAL, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAVAILABLE", |
||||
GRPC_STATUS_UNAVAILABLE, |
||||
CONST_CS); |
||||
REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS", |
||||
GRPC_STATUS_DATA_LOSS, |
||||
CONST_CS); |
||||
|
||||
grpc_init_call(TSRMLS_C); |
||||
grpc_init_channel(TSRMLS_C); |
||||
grpc_init_server(TSRMLS_C); |
||||
grpc_init_completion_queue(TSRMLS_C); |
||||
grpc_init_event(TSRMLS_C); |
||||
grpc_init_timeval(TSRMLS_C); |
||||
grpc_init_credentials(TSRMLS_C); |
||||
grpc_init_server_credentials(TSRMLS_C); |
||||
return SUCCESS; |
||||
} |
||||
/* }}} */ |
||||
|
||||
/* {{{ PHP_MSHUTDOWN_FUNCTION
|
||||
*/ |
||||
PHP_MSHUTDOWN_FUNCTION(grpc) |
||||
{ |
||||
/* uncomment this line if you have INI entries
|
||||
UNREGISTER_INI_ENTRIES(); |
||||
*/ |
||||
grpc_shutdown_timeval(TSRMLS_C); |
||||
grpc_shutdown(); |
||||
return SUCCESS; |
||||
} |
||||
/* }}} */ |
||||
|
||||
/* {{{ PHP_MINFO_FUNCTION
|
||||
*/ |
||||
PHP_MINFO_FUNCTION(grpc) |
||||
{ |
||||
php_info_print_table_start(); |
||||
php_info_print_table_header(2, "grpc support", "enabled"); |
||||
php_info_print_table_end(); |
||||
|
||||
/* Remove comments if you have entries in php.ini
|
||||
DISPLAY_INI_ENTRIES(); |
||||
*/ |
||||
} |
||||
/* }}} */ |
||||
/* The previous line is meant for vim and emacs, so it can correctly fold and
|
||||
unfold functions in source code. See the corresponding marks just before |
||||
function definition, where the functions purpose is also documented. Please |
||||
follow this convention for the convenience of others editing your code. |
||||
*/ |
||||
|
||||
|
||||
/*
|
||||
* Local variables: |
||||
* tab-width: 4 |
||||
* c-basic-offset: 4 |
||||
* End: |
||||
* vim600: noet sw=4 ts=4 fdm=marker |
||||
* vim<600: noet sw=4 ts=4 |
||||
*/ |
@ -0,0 +1,66 @@ |
||||
|
||||
#ifndef PHP_GRPC_H |
||||
#define PHP_GRPC_H |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
extern zend_module_entry grpc_module_entry; |
||||
#define phpext_grpc_ptr &grpc_module_entry |
||||
|
||||
#define PHP_GRPC_VERSION "0.1.0" /* Replace with version number for your extension */ |
||||
|
||||
#ifdef PHP_WIN32 |
||||
# define PHP_GRPC_API __declspec(dllexport) |
||||
#elif defined(__GNUC__) && __GNUC__ >= 4 |
||||
# define PHP_GRPC_API __attribute__ ((visibility("default"))) |
||||
#else |
||||
# define PHP_GRPC_API |
||||
#endif |
||||
|
||||
#ifdef ZTS |
||||
#include "TSRM.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
|
||||
#define RETURN_DESTROY_ZVAL(val) \ |
||||
RETURN_ZVAL( \
|
||||
val, \
|
||||
false /* Don't execute copy constructor */, \
|
||||
true /* Dealloc original before returning */) |
||||
|
||||
/* These are all function declarations */ |
||||
/* Code that runs at module initialization */ |
||||
PHP_MINIT_FUNCTION(grpc); |
||||
/* Code that runs at module shutdown */ |
||||
PHP_MSHUTDOWN_FUNCTION(grpc); |
||||
/* Displays information about the module */ |
||||
PHP_MINFO_FUNCTION(grpc); |
||||
|
||||
/*
|
||||
Declare any global variables you may need between the BEGIN |
||||
and END macros here: |
||||
|
||||
ZEND_BEGIN_MODULE_GLOBALS(grpc) |
||||
ZEND_END_MODULE_GLOBALS(grpc) |
||||
*/ |
||||
|
||||
/* In every utility function you add that needs to use variables
|
||||
in php_grpc_globals, call TSRMLS_FETCH(); after declaring other |
||||
variables used by that function, or better yet, pass in TSRMLS_CC |
||||
after the last function argument and declare your utility function |
||||
with TSRMLS_DC after the last declared argument. Always refer to |
||||
the globals in your function as GRPC_G(variable). You are |
||||
encouraged to rename these macros something shorter, see |
||||
examples in any other php module directory. |
||||
*/ |
||||
|
||||
#ifdef ZTS |
||||
#define GRPC_G(v) TSRMG(grpc_globals_id, zend_grpc_globals *, v) |
||||
#else |
||||
#define GRPC_G(v) (grpc_globals.v) |
||||
#endif |
||||
|
||||
#endif /* PHP_GRPC_H */ |
@ -0,0 +1,202 @@ |
||||
#include "call.h" |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "ext/spl/spl_exceptions.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "zend_exceptions.h" |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "grpc/grpc.h" |
||||
#include "grpc/support/log.h" |
||||
#include "grpc/grpc_security.h" |
||||
|
||||
#include "server.h" |
||||
#include "completion_queue.h" |
||||
#include "channel.h" |
||||
#include "server_credentials.h" |
||||
|
||||
/* Frees and destroys an instance of wrapped_grpc_server */ |
||||
void free_wrapped_grpc_server(void *object TSRMLS_DC){ |
||||
wrapped_grpc_server *server = (wrapped_grpc_server*)object; |
||||
if(server->wrapped != NULL){ |
||||
grpc_server_shutdown(server->wrapped); |
||||
grpc_server_destroy(server->wrapped); |
||||
} |
||||
efree(server); |
||||
} |
||||
|
||||
/* Initializes an instance of wrapped_grpc_call to be associated with an object
|
||||
* of a class specified by class_type */ |
||||
zend_object_value create_wrapped_grpc_server( |
||||
zend_class_entry *class_type TSRMLS_DC){ |
||||
zend_object_value retval; |
||||
wrapped_grpc_server *intern; |
||||
|
||||
intern = (wrapped_grpc_server*)emalloc(sizeof(wrapped_grpc_server)); |
||||
memset(intern, 0, sizeof(wrapped_grpc_server)); |
||||
|
||||
zend_object_std_init(&intern->std, class_type TSRMLS_CC); |
||||
object_properties_init(&intern->std, class_type); |
||||
retval.handle = zend_objects_store_put( |
||||
intern, |
||||
(zend_objects_store_dtor_t) zend_objects_destroy_object, |
||||
free_wrapped_grpc_server, |
||||
NULL TSRMLS_CC); |
||||
retval.handlers = zend_get_std_object_handlers(); |
||||
return retval; |
||||
} |
||||
|
||||
/**
|
||||
* Constructs a new instance of the Server class |
||||
* @param CompletionQueue $queue The completion queue to use with the server |
||||
* @param array $args The arguments to pass to the server (optional) |
||||
*/ |
||||
PHP_METHOD(Server, __construct){ |
||||
wrapped_grpc_server *server = |
||||
(wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
zval *queue_obj; |
||||
zval *args_array = NULL; |
||||
grpc_channel_args args; |
||||
HashTable *array_hash; |
||||
zval **creds_obj = NULL; |
||||
wrapped_grpc_server_credentials *creds = NULL; |
||||
/* "O|a" == 1 Object, 1 optional array */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"O|a", |
||||
&queue_obj, grpc_ce_completion_queue, |
||||
&args_array) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"Server expects a CompletionQueue and an array", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
add_property_zval(getThis(), "completion_queue", queue_obj); |
||||
wrapped_grpc_completion_queue *queue = |
||||
(wrapped_grpc_completion_queue*)zend_object_store_get_object( |
||||
queue_obj TSRMLS_CC); |
||||
if (args_array == NULL) { |
||||
server->wrapped = grpc_server_create(queue->wrapped, NULL); |
||||
} else { |
||||
array_hash = Z_ARRVAL_P(args_array); |
||||
if(zend_hash_find(array_hash, |
||||
"credentials", |
||||
sizeof("credentials"), |
||||
(void**)&creds_obj) == SUCCESS) { |
||||
if(zend_get_class_entry(*creds_obj TSRMLS_CC) != |
||||
grpc_ce_server_credentials) { |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"credentials must be a ServerCredentials object", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
creds = (wrapped_grpc_server_credentials*)zend_object_store_get_object( |
||||
*creds_obj TSRMLS_CC); |
||||
zend_hash_del(array_hash, "credentials", sizeof("credentials")); |
||||
} |
||||
php_grpc_read_args_array(args_array, &args); |
||||
if (creds == NULL) { |
||||
server->wrapped = grpc_server_create(queue->wrapped, &args); |
||||
} else { |
||||
gpr_log(GPR_DEBUG, "Initialized secure server"); |
||||
server->wrapped = grpc_secure_server_create(creds->wrapped, |
||||
queue->wrapped, |
||||
&args); |
||||
} |
||||
efree(args.args); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Request a call on a server. Creates a single GRPC_SERVER_RPC_NEW event. |
||||
* @param long $tag_new The tag to associate with the new request |
||||
* @param long $tag_cancel The tag to use if the call is cancelled |
||||
* @return Void |
||||
*/ |
||||
PHP_METHOD(Server, request_call){ |
||||
wrapped_grpc_server *server = |
||||
(wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
long tag_new; |
||||
/* "l" == 1 long */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"l", |
||||
&tag_new) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"request_call expects a long", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
grpc_server_request_call(server->wrapped, (void*)tag_new); |
||||
} |
||||
|
||||
/**
|
||||
* Add a http2 over tcp listener. |
||||
* @param string $addr The address to add |
||||
* @return true on success, false on failure |
||||
*/ |
||||
PHP_METHOD(Server, add_http2_port){ |
||||
wrapped_grpc_server *server = |
||||
(wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
const char *addr; |
||||
int addr_len; |
||||
/* "s" == 1 string */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"s", |
||||
&addr, &addr_len) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"add_http2_port expects a string", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
RETURN_BOOL(grpc_server_add_http2_port(server->wrapped, addr)); |
||||
} |
||||
|
||||
PHP_METHOD(Server, add_secure_http2_port){ |
||||
wrapped_grpc_server *server = |
||||
(wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
const char *addr; |
||||
int addr_len; |
||||
/* "s" == 1 string */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"s", |
||||
&addr, &addr_len) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"add_http2_port expects a string", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
RETURN_BOOL(grpc_server_add_secure_http2_port(server->wrapped, addr)); |
||||
} |
||||
|
||||
/**
|
||||
* Start a server - tells all listeners to start listening |
||||
* @return Void |
||||
*/ |
||||
PHP_METHOD(Server, start){ |
||||
wrapped_grpc_server *server = |
||||
(wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
grpc_server_start(server->wrapped); |
||||
} |
||||
|
||||
static zend_function_entry server_methods[] = { |
||||
PHP_ME(Server, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) |
||||
PHP_ME(Server, request_call, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Server, add_http2_port, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Server, add_secure_http2_port, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_FE_END |
||||
}; |
||||
|
||||
void grpc_init_server(TSRMLS_D){ |
||||
zend_class_entry ce; |
||||
INIT_CLASS_ENTRY(ce, "Grpc\\Server", server_methods); |
||||
ce.create_object = create_wrapped_grpc_server; |
||||
grpc_ce_server = zend_register_internal_class(&ce TSRMLS_CC); |
||||
} |
@ -0,0 +1,28 @@ |
||||
#ifndef NET_GRPC_PHP_GRPC_SERVER_H_ |
||||
#define NET_GRPC_PHP_GRPC_SERVER_H_ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
|
||||
/* Class entry for the Server PHP class */ |
||||
zend_class_entry *grpc_ce_server; |
||||
|
||||
/* Wrapper struct for grpc_server that can be associated with a PHP object */ |
||||
typedef struct wrapped_grpc_server { |
||||
zend_object std; |
||||
|
||||
grpc_server *wrapped; |
||||
} wrapped_grpc_server; |
||||
|
||||
/* Initializes the Server class */ |
||||
void grpc_init_server(TSRMLS_D); |
||||
|
||||
#endif /* NET_GRPC_PHP_GRPC_SERVER_H_ */ |
@ -0,0 +1,117 @@ |
||||
#include "server_credentials.h" |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "ext/spl/spl_exceptions.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "zend_exceptions.h" |
||||
#include "zend_hash.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
#include "grpc/grpc_security.h" |
||||
|
||||
/* Frees and destroys an instace of wrapped_grpc_server_credentials */ |
||||
void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC){ |
||||
wrapped_grpc_server_credentials *creds = |
||||
(wrapped_grpc_server_credentials*)object; |
||||
if(creds->wrapped != NULL) { |
||||
grpc_server_credentials_release(creds->wrapped); |
||||
} |
||||
efree(creds); |
||||
} |
||||
|
||||
/* Initializes an instace of wrapped_grpc_server_credentials to be associated
|
||||
* with an object of a class specified by class_type */ |
||||
zend_object_value create_wrapped_grpc_server_credentials( |
||||
zend_class_entry *class_type TSRMLS_DC){ |
||||
zend_object_value retval; |
||||
wrapped_grpc_server_credentials *intern; |
||||
|
||||
intern = (wrapped_grpc_server_credentials*)emalloc(sizeof( |
||||
wrapped_grpc_server_credentials)); |
||||
memset(intern, 0, sizeof(wrapped_grpc_server_credentials)); |
||||
|
||||
zend_object_std_init(&intern->std, class_type TSRMLS_CC); |
||||
object_properties_init(&intern->std, class_type); |
||||
retval.handle = zend_objects_store_put( |
||||
intern, |
||||
(zend_objects_store_dtor_t) zend_objects_destroy_object, |
||||
free_wrapped_grpc_server_credentials, |
||||
NULL TSRMLS_CC); |
||||
retval.handlers = zend_get_std_object_handlers(); |
||||
return retval; |
||||
} |
||||
|
||||
zval *grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped){ |
||||
zval *server_credentials_object; |
||||
MAKE_STD_ZVAL(server_credentials_object); |
||||
object_init_ex(server_credentials_object, grpc_ce_server_credentials); |
||||
wrapped_grpc_server_credentials *server_credentials = |
||||
(wrapped_grpc_server_credentials*)zend_object_store_get_object( |
||||
server_credentials_object TSRMLS_CC); |
||||
server_credentials->wrapped = wrapped; |
||||
return server_credentials_object; |
||||
} |
||||
|
||||
/**
|
||||
* Create SSL credentials. |
||||
* @param string pem_root_certs PEM encoding of the server root certificates |
||||
* @param string pem_private_key PEM encoding of the client's private key |
||||
* @param string pem_cert_chain PEM encoding of the client's certificate chain |
||||
* @return Credentials The new SSL credentials object |
||||
*/ |
||||
PHP_METHOD(ServerCredentials, createSsl){ |
||||
char *pem_root_certs = 0; |
||||
char *pem_private_key; |
||||
char *pem_cert_chain; |
||||
|
||||
int root_certs_length = 0, private_key_length, cert_chain_length; |
||||
|
||||
/* "s!ss" == 1 nullable string, 2 strings */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"s!ss", |
||||
&pem_root_certs, &root_certs_length, |
||||
&pem_private_key, &private_key_length, |
||||
&pem_cert_chain, &cert_chain_length) == FAILURE) { |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"createSsl expects 3 strings", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
grpc_server_credentials *creds = grpc_ssl_server_credentials_create( |
||||
(unsigned char*)pem_root_certs, (size_t)root_certs_length, |
||||
(unsigned char*)pem_private_key, (size_t)private_key_length, |
||||
(unsigned char*)pem_cert_chain, (size_t)cert_chain_length); |
||||
zval *creds_object = grpc_php_wrap_server_credentials(creds); |
||||
RETURN_DESTROY_ZVAL(creds_object); |
||||
} |
||||
|
||||
/**
|
||||
* Create fake credentials. Only to be used for testing. |
||||
* @return ServerCredentials The new fake credentials object |
||||
*/ |
||||
PHP_METHOD(ServerCredentials, createFake){ |
||||
grpc_server_credentials *creds = |
||||
grpc_fake_transport_security_server_credentials_create(); |
||||
zval *creds_object = grpc_php_wrap_server_credentials(creds); |
||||
RETURN_DESTROY_ZVAL(creds_object); |
||||
} |
||||
|
||||
static zend_function_entry server_credentials_methods[] = { |
||||
PHP_ME(ServerCredentials, createSsl, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(ServerCredentials, createFake, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_FE_END |
||||
}; |
||||
|
||||
void grpc_init_server_credentials(TSRMLS_D){ |
||||
zend_class_entry ce; |
||||
INIT_CLASS_ENTRY(ce, "Grpc\\ServerCredentials", server_credentials_methods); |
||||
ce.create_object = create_wrapped_grpc_server_credentials; |
||||
grpc_ce_server_credentials = zend_register_internal_class(&ce TSRMLS_CC); |
||||
} |
@ -0,0 +1,30 @@ |
||||
#ifndef NET_GRPC_PHP_GRPC_SERVER_CREDENTIALS_H_ |
||||
#define NET_GRPC_PHP_GRPC_SERVER_CREDENTIALS_H_ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
#include "grpc/grpc_security.h" |
||||
|
||||
/* Class entry for the Server_Credentials PHP class */ |
||||
zend_class_entry *grpc_ce_server_credentials; |
||||
|
||||
/* Wrapper struct for grpc_server_credentials that can be associated with a PHP
|
||||
* object */ |
||||
typedef struct wrapped_grpc_server_credentials { |
||||
zend_object std; |
||||
|
||||
grpc_server_credentials *wrapped; |
||||
} wrapped_grpc_server_credentials; |
||||
|
||||
/* Initializes the Server_Credentials PHP class */ |
||||
void grpc_init_server_credentials(TSRMLS_D); |
||||
|
||||
#endif /* NET_GRPC_PHP_GRPC_SERVER_CREDENTIALS_H_ */ |
@ -0,0 +1,255 @@ |
||||
#include "timeval.h" |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "ext/spl/spl_exceptions.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "zend_exceptions.h" |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "grpc/grpc.h" |
||||
#include "grpc/support/time.h" |
||||
|
||||
/* Frees and destroys an instance of wrapped_grpc_call */ |
||||
void free_wrapped_grpc_timeval(void *object TSRMLS_DC){ |
||||
efree(object); |
||||
} |
||||
|
||||
/* Initializes an instance of wrapped_grpc_timeval to be associated with an
|
||||
* object of a class specified by class_type */ |
||||
zend_object_value create_wrapped_grpc_timeval( |
||||
zend_class_entry *class_type TSRMLS_DC){ |
||||
zend_object_value retval; |
||||
wrapped_grpc_timeval *intern; |
||||
intern = (wrapped_grpc_timeval*)emalloc(sizeof(wrapped_grpc_timeval)); |
||||
memset(intern, 0, sizeof(wrapped_grpc_timeval)); |
||||
zend_object_std_init(&intern->std, class_type TSRMLS_CC); |
||||
object_properties_init(&intern->std, class_type); |
||||
retval.handle = zend_objects_store_put( |
||||
intern, |
||||
(zend_objects_store_dtor_t)zend_objects_destroy_object, |
||||
free_wrapped_grpc_timeval, |
||||
NULL TSRMLS_CC); |
||||
retval.handlers = zend_get_std_object_handlers(); |
||||
return retval; |
||||
} |
||||
|
||||
zval *grpc_php_wrap_timeval(gpr_timespec wrapped){ |
||||
zval *timeval_object; |
||||
MAKE_STD_ZVAL(timeval_object); |
||||
object_init_ex(timeval_object, grpc_ce_timeval); |
||||
wrapped_grpc_timeval *timeval = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object( |
||||
timeval_object TSRMLS_CC); |
||||
memcpy(&timeval->wrapped, &wrapped, sizeof(gpr_timespec)); |
||||
return timeval_object; |
||||
} |
||||
|
||||
/**
|
||||
* Constructs a new instance of the Timeval class |
||||
* @param long $usec The number of microseconds in the interval |
||||
*/ |
||||
PHP_METHOD(Timeval, __construct){ |
||||
wrapped_grpc_timeval *timeval = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
long microseconds; |
||||
/* "l" == 1 long */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"l", |
||||
µseconds) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"Timeval expects a long", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
gpr_timespec time = gpr_time_from_micros(microseconds); |
||||
memcpy(&timeval->wrapped, &time, sizeof(gpr_timespec)); |
||||
} |
||||
|
||||
/**
|
||||
* Adds another Timeval to this one and returns the sum. Calculations saturate |
||||
* at infinities. |
||||
* @param Timeval $other The other Timeval object to add |
||||
* @return Timeval A new Timeval object containing the sum |
||||
*/ |
||||
PHP_METHOD(Timeval, add){ |
||||
zval *other_obj; |
||||
/* "O" == 1 Object */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"O", |
||||
&other_obj, grpc_ce_timeval) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"add expects a Timeval", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
wrapped_grpc_timeval *self = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
wrapped_grpc_timeval *other = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(other_obj TSRMLS_CC); |
||||
zval *sum = grpc_php_wrap_timeval(gpr_time_add(self->wrapped, |
||||
other->wrapped)); |
||||
RETURN_DESTROY_ZVAL(sum); |
||||
} |
||||
|
||||
/**
|
||||
* Subtracts another Timeval from this one and returns the difference. |
||||
* Calculations saturate at infinities. |
||||
* @param Timeval $other The other Timeval object to subtract |
||||
* @param Timeval A new Timeval object containing the sum |
||||
*/ |
||||
PHP_METHOD(Timeval, subtract){ |
||||
zval *other_obj; |
||||
/* "O" == 1 Object */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"O", |
||||
&other_obj, grpc_ce_timeval) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"subtract expects a Timeval", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
wrapped_grpc_timeval *self = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
wrapped_grpc_timeval *other = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(other_obj TSRMLS_CC); |
||||
zval *diff = grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, |
||||
other->wrapped)); |
||||
RETURN_DESTROY_ZVAL(diff); |
||||
} |
||||
|
||||
/**
|
||||
* Return negative, 0, or positive according to whether a < b, a == b, or a > b |
||||
* respectively. |
||||
* @param Timeval $a The first time to compare |
||||
* @param Timeval $b The second time to compare |
||||
* @return long |
||||
*/ |
||||
PHP_METHOD(Timeval, compare){ |
||||
zval *a_obj, *b_obj; |
||||
/* "OO" == 2 Objects */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"OO", |
||||
&a_obj, grpc_ce_timeval, |
||||
&b_obj, grpc_ce_timeval) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"compare expects two Timevals", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
wrapped_grpc_timeval *a = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(a_obj TSRMLS_CC); |
||||
wrapped_grpc_timeval *b = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(b_obj TSRMLS_CC); |
||||
long result = gpr_time_cmp(a->wrapped, b->wrapped); |
||||
RETURN_LONG(result); |
||||
} |
||||
|
||||
/**
|
||||
* Checks whether the two times are within $threshold of each other |
||||
* @param Timeval $a The first time to compare |
||||
* @param Timeval $b The second time to compare |
||||
* @param Timeval $threshold The threshold to check against |
||||
* @return bool True if $a and $b are within $threshold, False otherwise |
||||
*/ |
||||
PHP_METHOD(Timeval, similar){ |
||||
zval *a_obj, *b_obj, *thresh_obj; |
||||
/* "OOO" == 3 Objects */ |
||||
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, |
||||
"OOO", |
||||
&a_obj, grpc_ce_timeval, |
||||
&b_obj, grpc_ce_timeval, |
||||
&thresh_obj, grpc_ce_timeval) == FAILURE){ |
||||
zend_throw_exception(spl_ce_InvalidArgumentException, |
||||
"compare expects three Timevals", |
||||
1 TSRMLS_CC); |
||||
return; |
||||
} |
||||
wrapped_grpc_timeval *a = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(a_obj TSRMLS_CC); |
||||
wrapped_grpc_timeval *b = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(b_obj TSRMLS_CC); |
||||
wrapped_grpc_timeval *thresh = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(thresh_obj TSRMLS_CC); |
||||
int result = gpr_time_similar(a->wrapped, b->wrapped, thresh->wrapped); |
||||
RETURN_BOOL(result); |
||||
} |
||||
|
||||
/**
|
||||
* Returns the current time as a timeval object |
||||
* @return Timeval The current time |
||||
*/ |
||||
PHP_METHOD(Timeval, now){ |
||||
zval *now = grpc_php_wrap_timeval(gpr_now()); |
||||
RETURN_DESTROY_ZVAL(now); |
||||
} |
||||
|
||||
/**
|
||||
* Returns the zero time interval as a timeval object |
||||
* @return Timeval Zero length time interval |
||||
*/ |
||||
PHP_METHOD(Timeval, zero){ |
||||
zval *grpc_php_timeval_zero = grpc_php_wrap_timeval(gpr_time_0); |
||||
RETURN_ZVAL(grpc_php_timeval_zero, |
||||
false, /* Copy original before returning? */ |
||||
true /* Destroy original before returning */); |
||||
} |
||||
|
||||
/**
|
||||
* Returns the infinite future time value as a timeval object |
||||
* @return Timeval Infinite future time value |
||||
*/ |
||||
PHP_METHOD(Timeval, inf_future){ |
||||
zval *grpc_php_timeval_inf_future = grpc_php_wrap_timeval(gpr_inf_future); |
||||
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future); |
||||
} |
||||
|
||||
/**
|
||||
* Returns the infinite past time value as a timeval object |
||||
* @return Timeval Infinite past time value |
||||
*/ |
||||
PHP_METHOD(Timeval, inf_past){ |
||||
zval *grpc_php_timeval_inf_past = grpc_php_wrap_timeval(gpr_inf_past); |
||||
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past); |
||||
} |
||||
|
||||
/**
|
||||
* Sleep until this time, interpreted as an absolute timeout |
||||
* @return void |
||||
*/ |
||||
PHP_METHOD(Timeval, sleep_until){ |
||||
wrapped_grpc_timeval *this = |
||||
(wrapped_grpc_timeval*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
gpr_sleep_until(this->wrapped); |
||||
} |
||||
|
||||
static zend_function_entry timeval_methods[] = { |
||||
PHP_ME(Timeval, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) |
||||
PHP_ME(Timeval, add, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Timeval, compare, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Timeval, inf_future, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Timeval, inf_past, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Timeval, now, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Timeval, similar, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Timeval, sleep_until, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Timeval, subtract, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(Timeval, zero, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_FE_END |
||||
}; |
||||
|
||||
void grpc_init_timeval(TSRMLS_D){ |
||||
zend_class_entry ce; |
||||
INIT_CLASS_ENTRY(ce, "Grpc\\Timeval", timeval_methods); |
||||
ce.create_object = create_wrapped_grpc_timeval; |
||||
grpc_ce_timeval = zend_register_internal_class(&ce TSRMLS_CC); |
||||
} |
||||
|
||||
void grpc_shutdown_timeval(TSRMLS_D){ |
||||
} |
@ -0,0 +1,35 @@ |
||||
#ifndef NET_GRPC_PHP_GRPC_TIMEVAL_H_ |
||||
#define NET_GRPC_PHP_GRPC_TIMEVAL_H_ |
||||
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include "php.h" |
||||
#include "php_ini.h" |
||||
#include "ext/standard/info.h" |
||||
#include "php_grpc.h" |
||||
|
||||
#include "grpc/grpc.h" |
||||
#include "grpc/support/time.h" |
||||
|
||||
/* Class entry for the Timeval PHP Class */ |
||||
zend_class_entry *grpc_ce_timeval; |
||||
|
||||
/* Wrapper struct for timeval that can be associated with a PHP object */ |
||||
typedef struct wrapped_grpc_timeval { |
||||
zend_object std; |
||||
|
||||
gpr_timespec wrapped; |
||||
} wrapped_grpc_timeval; |
||||
|
||||
/* Initialize the Timeval PHP class */ |
||||
void grpc_init_timeval(TSRMLS_D); |
||||
|
||||
/* Shutdown the Timeval PHP class */ |
||||
void grpc_shutdown_timeval(TSRMLS_D); |
||||
|
||||
/* Creates a Timeval object that wraps the given timeval struct */ |
||||
zval *grpc_php_wrap_timeval(gpr_timespec wrapped); |
||||
|
||||
#endif /* NET_GRPC_PHP_GRPC_TIMEVAL_H_ */ |
@ -0,0 +1,98 @@ |
||||
<?php |
||||
namespace Grpc; |
||||
|
||||
/** |
||||
* Represents an active call that allows sending and recieving binary data |
||||
*/ |
||||
class ActiveCall { |
||||
private $completion_queue; |
||||
private $call; |
||||
private $flags; |
||||
private $metadata; |
||||
|
||||
/** |
||||
* Create a new active call. |
||||
* @param Channel $channel The channel to communicate on |
||||
* @param string $method The method to call on the remote server |
||||
* @param array $metadata Metadata to send with the call, if applicable |
||||
* @param long $flags Write flags to use with this call |
||||
*/ |
||||
public function __construct(Channel $channel, |
||||
$method, |
||||
$metadata = array(), |
||||
$flags = 0) { |
||||
$this->completion_queue = new CompletionQueue(); |
||||
$this->call = new Call($channel, $method, Timeval::inf_future()); |
||||
$this->call->add_metadata($metadata, 0); |
||||
$this->flags = $flags; |
||||
|
||||
// Invoke the call. |
||||
$this->call->start_invoke($this->completion_queue, |
||||
INVOKE_ACCEPTED, |
||||
CLIENT_METADATA_READ, |
||||
FINISHED, 0); |
||||
$this->completion_queue->pluck(INVOKE_ACCEPTED, |
||||
Timeval::inf_future()); |
||||
$metadata_event = $this->completion_queue->pluck(CLIENT_METADATA_READ, |
||||
Timeval::inf_future()); |
||||
$this->metadata = $metadata_event->get_data(); |
||||
} |
||||
|
||||
/** |
||||
* @return The metadata sent by the server. |
||||
*/ |
||||
public function getMetadata() { |
||||
return $this->metadata; |
||||
} |
||||
|
||||
/** |
||||
* Cancels the call |
||||
*/ |
||||
public function cancel() { |
||||
$this->call->cancel(); |
||||
} |
||||
|
||||
/** |
||||
* Read a single message from the server. |
||||
* @return The next message from the server, or null if there is none. |
||||
*/ |
||||
public function read() { |
||||
$this->call->start_read(READ); |
||||
$read_event = $this->completion_queue->pluck(READ, Timeval::inf_future()); |
||||
return $read_event->get_data(); |
||||
} |
||||
|
||||
/** |
||||
* Write a single message to the server. This cannot be called after |
||||
* writesDone is called. |
||||
* @param ByteBuffer $data The data to write |
||||
*/ |
||||
public function write($data) { |
||||
if($this->call->start_write($data, |
||||
WRITE_ACCEPTED, |
||||
$this->flags) != OP_OK) { |
||||
// TODO(mlumish): more useful error |
||||
throw new \Exception("Cannot call write after writesDone"); |
||||
} |
||||
$this->completion_queue->pluck(WRITE_ACCEPTED, Timeval::inf_future()); |
||||
} |
||||
|
||||
/** |
||||
* Indicate that no more writes will be sent. |
||||
*/ |
||||
public function writesDone() { |
||||
$this->call->writes_done(FINISH_ACCEPTED); |
||||
$this->completion_queue->pluck(FINISH_ACCEPTED, Timeval::inf_future()); |
||||
} |
||||
|
||||
/** |
||||
* Wait for the server to send the status, and return it. |
||||
* @return object The status object, with integer $code and string $details |
||||
* members |
||||
*/ |
||||
public function getStatus() { |
||||
$status_event = $this->completion_queue->pluck(FINISHED, |
||||
Timeval::inf_future()); |
||||
return $status_event->get_data(); |
||||
} |
||||
} |
@ -0,0 +1,106 @@ |
||||
<?php |
||||
|
||||
namespace Grpc; |
||||
|
||||
/** |
||||
* Base class for generated client stubs. Stub methods are expected to call |
||||
* _simpleRequest or _streamRequest and return the result. |
||||
*/ |
||||
class BaseStub { |
||||
|
||||
private $channel; |
||||
|
||||
public function __construct($hostname) { |
||||
$this->channel = new Channel($hostname, []); |
||||
} |
||||
|
||||
/** |
||||
* Close the communication channel associated with this stub |
||||
*/ |
||||
public function close() { |
||||
$channel->close(); |
||||
} |
||||
|
||||
/* This class is intended to be subclassed by generated code, so all functions |
||||
begin with "_" to avoid name collisions. */ |
||||
|
||||
/** |
||||
* Call a remote method that takes a single argument and has a single output |
||||
* |
||||
* @param string $method The name of the method to call |
||||
* @param $argument The argument to the method |
||||
* @param callable $deserialize A function that deserializes the response |
||||
* @param array $metadata A metadata map to send to the server |
||||
* @return SimpleSurfaceActiveCall The active call object |
||||
*/ |
||||
protected function _simpleRequest($method, |
||||
$argument, |
||||
callable $deserialize, |
||||
$metadata = array()) { |
||||
return new SimpleSurfaceActiveCall($this->channel, |
||||
$method, |
||||
$deserialize, |
||||
$argument, |
||||
$metadata); |
||||
} |
||||
|
||||
/** |
||||
* Call a remote method that takes a stream of arguments and has a single |
||||
* output |
||||
* |
||||
* @param string $method The name of the method to call |
||||
* @param $arguments An array or Traversable of arguments to stream to the |
||||
* server |
||||
* @param callable $deserialize A function that deserializes the response |
||||
* @param array $metadata A metadata map to send to the server |
||||
* @return ClientStreamingSurfaceActiveCall The active call object |
||||
*/ |
||||
protected function _clientStreamRequest($method, |
||||
$arguments, |
||||
callable $deserialize, |
||||
$metadata = array()) { |
||||
return new ClientStreamingSurfaceActiveCall($this->channel, |
||||
$method, |
||||
$deserialize, |
||||
$arguments, |
||||
$metadata); |
||||
} |
||||
|
||||
/** |
||||
* Call a remote method that takes a single argument and returns a stream of |
||||
* responses |
||||
* |
||||
* @param string $method The name of the method to call |
||||
* @param $argument The argument to the method |
||||
* @param callable $deserialize A function that deserializes the responses |
||||
* @param array $metadata A metadata map to send to the server |
||||
* @return ServerStreamingSurfaceActiveCall The active call object |
||||
*/ |
||||
protected function _serverStreamRequest($method, |
||||
$argument, |
||||
callable $deserialize, |
||||
$metadata = array()) { |
||||
return new ServerStreamingSurfaceActiveCall($this->channel, |
||||
$method, |
||||
$deserialize, |
||||
$argument, |
||||
$metadata); |
||||
} |
||||
|
||||
/** |
||||
* Call a remote method with messages streaming in both directions |
||||
* |
||||
* @param string $method The name of the method to call |
||||
* @param callable $deserialize A function that deserializes the responses |
||||
* @param array $metadata A metadata map to send to the server |
||||
* @return BidiStreamingSurfaceActiveCall The active call object |
||||
*/ |
||||
protected function _bidiRequest($method, |
||||
callable $deserialize, |
||||
$metadata = array()) { |
||||
return new BidiStreamingSurfaceActiveCall($this->channel, |
||||
$method, |
||||
$deserialize, |
||||
$metadata); |
||||
} |
||||
} |
@ -0,0 +1,211 @@ |
||||
<?php |
||||
namespace Grpc; |
||||
|
||||
/** |
||||
* Represents an active call that allows sending and recieving messages. |
||||
* Subclasses restrict how data can be sent and recieved. |
||||
*/ |
||||
abstract class AbstractSurfaceActiveCall { |
||||
private $active_call; |
||||
private $deserialize; |
||||
|
||||
/** |
||||
* Create a new surface active call. |
||||
* @param Channel $channel The channel to communicate on |
||||
* @param string $method The method to call on the remote server |
||||
* @param callable $deserialize The function to deserialize a value |
||||
* @param array $metadata Metadata to send with the call, if applicable |
||||
* @param long $flags Write flags to use with this call |
||||
*/ |
||||
public function __construct(Channel $channel, |
||||
$method, |
||||
callable $deserialize, |
||||
$metadata = array(), |
||||
$flags = 0) { |
||||
$this->active_call = new ActiveCall($channel, $method, $metadata, $flags); |
||||
$this->deserialize = $deserialize; |
||||
} |
||||
|
||||
/** |
||||
* @return The metadata sent by the server |
||||
*/ |
||||
public function getMetadata() { |
||||
return $this->metadata(); |
||||
} |
||||
|
||||
/** |
||||
* Cancels the call |
||||
*/ |
||||
public function cancel() { |
||||
$this->active_call->cancel(); |
||||
} |
||||
|
||||
protected function _read() { |
||||
$response = $this->active_call->read(); |
||||
if ($response == null) { |
||||
return null; |
||||
} |
||||
return call_user_func($this->deserialize, $response); |
||||
} |
||||
|
||||
protected function _write($value) { |
||||
return $this->active_call->write($value->serialize()); |
||||
} |
||||
|
||||
protected function _writesDone() { |
||||
$this->active_call->writesDone(); |
||||
} |
||||
|
||||
protected function _getStatus() { |
||||
return $this->active_call->getStatus(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Represents an active call that sends a single message and then gets a single |
||||
* response. |
||||
*/ |
||||
class SimpleSurfaceActiveCall extends AbstractSurfaceActiveCall { |
||||
/** |
||||
* Create a new simple (single request/single response) active call. |
||||
* @param Channel $channel The channel to communicate on |
||||
* @param string $method The method to call on the remote server |
||||
* @param callable $deserialize The function to deserialize a value |
||||
* @param $arg The argument to send |
||||
* @param array $metadata Metadata to send with the call, if applicable |
||||
*/ |
||||
public function __construct(Channel $channel, |
||||
$method, |
||||
callable $deserialize, |
||||
$arg, |
||||
$metadata = array()) { |
||||
parent::__construct($channel, $method, $deserialize, $metadata, |
||||
\Grpc\WRITE_BUFFER_HINT); |
||||
$this->_write($arg); |
||||
$this->_writesDone(); |
||||
} |
||||
|
||||
/** |
||||
* Wait for the server to respond with data and a status |
||||
* @return [response data, status] |
||||
*/ |
||||
public function wait() { |
||||
$response = $this->_read(); |
||||
$status = $this->_getStatus(); |
||||
return array($response, $status); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Represents an active call that sends a stream of messages and then gets a |
||||
* single response. |
||||
*/ |
||||
class ClientStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall { |
||||
/** |
||||
* Create a new simple (single request/single response) active call. |
||||
* @param Channel $channel The channel to communicate on |
||||
* @param string $method The method to call on the remote server |
||||
* @param callable $deserialize The function to deserialize a value |
||||
* @param Traversable $arg_iter The iterator of arguments to send |
||||
* @param array $metadata Metadata to send with the call, if applicable |
||||
*/ |
||||
public function __construct(Channel $channel, |
||||
$method, |
||||
callable $deserialize, |
||||
$arg_iter, |
||||
$metadata = array()) { |
||||
parent::__construct($channel, $method, $deserialize, $metadata, 0); |
||||
foreach($arg_iter as $arg) { |
||||
$this->_write($arg); |
||||
} |
||||
$this->_writesDone(); |
||||
} |
||||
|
||||
/** |
||||
* Wait for the server to respond with data and a status |
||||
* @return [response data, status] |
||||
*/ |
||||
public function wait() { |
||||
$response = $this->_read(); |
||||
$status = $this->_getStatus(); |
||||
return array($response, $status); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Represents an active call that sends a single message and then gets a stream |
||||
* of reponses |
||||
*/ |
||||
class ServerStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall { |
||||
/** |
||||
* Create a new simple (single request/single response) active call. |
||||
* @param Channel $channel The channel to communicate on |
||||
* @param string $method The method to call on the remote server |
||||
* @param callable $deserialize The function to deserialize a value |
||||
* @param $arg The argument to send |
||||
* @param array $metadata Metadata to send with the call, if applicable |
||||
*/ |
||||
public function __construct(Channel $channel, |
||||
$method, |
||||
callable $deserialize, |
||||
$arg, |
||||
$metadata = array()) { |
||||
parent::__construct($channel, $method, $deserialize, $metadata, |
||||
\Grpc\WRITE_BUFFER_HINT); |
||||
$this->_write($arg); |
||||
$this->_writesDone(); |
||||
} |
||||
|
||||
/** |
||||
* @return An iterator of response values |
||||
*/ |
||||
public function responses() { |
||||
while(($response = $this->_read()) != null) { |
||||
yield $response; |
||||
} |
||||
} |
||||
|
||||
public function getStatus() { |
||||
return $this->_getStatus(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Represents an active call that allows for sending and recieving messages in |
||||
* streams in any order. |
||||
*/ |
||||
class BidiStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall { |
||||
|
||||
/** |
||||
* Reads the next value from the server. |
||||
* @return The next value from the server, or null if there is none |
||||
*/ |
||||
public function read() { |
||||
return $this->_read(); |
||||
} |
||||
|
||||
/** |
||||
* Writes a single message to the server. This cannot be called after |
||||
* writesDone is called. |
||||
* @param $value The message to send |
||||
*/ |
||||
public function write($value) { |
||||
$this->_write($value); |
||||
} |
||||
|
||||
/** |
||||
* Indicate that no more writes will be sent |
||||
*/ |
||||
public function writesDone() { |
||||
$this->_writesDone(); |
||||
} |
||||
|
||||
/** |
||||
* Wait for the server to send the status, and return it. |
||||
* @return object The status object, with integer $code and string $details |
||||
* members |
||||
*/ |
||||
public function getStatus() { |
||||
return $this->_getStatus(); |
||||
} |
||||
} |
@ -0,0 +1,70 @@ |
||||
<?php |
||||
require __DIR__ . '/../../lib/Grpc/ActiveCall.php'; |
||||
require __DIR__ . '/../../lib/Grpc/SurfaceActiveCall.php'; |
||||
require __DIR__ . '/../../lib/Grpc/BaseStub.php'; |
||||
require 'DrSlump/Protobuf.php'; |
||||
\DrSlump\Protobuf::autoload(); |
||||
require 'math.php'; |
||||
class GeneratedCodeTest extends PHPUnit_Framework_TestCase { |
||||
/* These tests require that a server exporting the math service must be |
||||
* running on $GRPC_TEST_HOST */ |
||||
protected static $client; |
||||
protected static $timeout; |
||||
public static function setUpBeforeClass() { |
||||
self::$client = new math\MathClient(getenv('GRPC_TEST_HOST')); |
||||
} |
||||
|
||||
public function testSimpleRequest() { |
||||
$div_arg = new math\DivArgs(); |
||||
$div_arg->setDividend(7); |
||||
$div_arg->setDivisor(4); |
||||
list($response, $status) = self::$client->Div($div_arg)->wait(); |
||||
$this->assertEquals(1, $response->getQuotient()); |
||||
$this->assertEquals(3, $response->getRemainder()); |
||||
$this->assertEquals(\Grpc\STATUS_OK, $status->code); |
||||
} |
||||
|
||||
public function testServerStreaming() { |
||||
$fib_arg = new math\FibArgs(); |
||||
$fib_arg->setLimit(7); |
||||
$call = self::$client->Fib($fib_arg); |
||||
$result_array = iterator_to_array($call->responses()); |
||||
$extract_num = function($num){ |
||||
return $num->getNum(); |
||||
}; |
||||
$values = array_map($extract_num, $result_array); |
||||
$this->assertEquals([1, 1, 2, 3, 5, 8, 13], $values); |
||||
$status = $call->getStatus(); |
||||
$this->assertEquals(\Grpc\STATUS_OK, $status->code); |
||||
} |
||||
|
||||
public function testClientStreaming() { |
||||
$num_iter = function() { |
||||
for ($i = 0; $i < 7; $i++) { |
||||
$num = new math\Num(); |
||||
$num->setNum($i); |
||||
yield $num; |
||||
} |
||||
}; |
||||
$call = self::$client->Sum($num_iter()); |
||||
list($response, $status) = $call->wait(); |
||||
$this->assertEquals(21, $response->getNum()); |
||||
$this->assertEquals(\Grpc\STATUS_OK, $status->code); |
||||
} |
||||
|
||||
public function testBidiStreaming() { |
||||
$call = self::$client->DivMany(); |
||||
for ($i = 0; $i < 7; $i++) { |
||||
$div_arg = new math\DivArgs(); |
||||
$div_arg->setDividend(2 * $i + 1); |
||||
$div_arg->setDivisor(2); |
||||
$call->write($div_arg); |
||||
$response = $call->read(); |
||||
$this->assertEquals($i, $response->getQuotient()); |
||||
$this->assertEquals(1, $response->getRemainder()); |
||||
} |
||||
$call->writesDone(); |
||||
$status = $call->getStatus(); |
||||
$this->assertEquals(\Grpc\STATUS_OK, $status->code); |
||||
} |
||||
} |
@ -0,0 +1,479 @@ |
||||
<?php |
||||
// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0 |
||||
// Source: math.proto |
||||
// Date: 2014-11-14 00:00:41 |
||||
|
||||
namespace math { |
||||
|
||||
class DivArgs extends \DrSlump\Protobuf\Message { |
||||
|
||||
/** @var int */ |
||||
public $dividend = null; |
||||
|
||||
/** @var int */ |
||||
public $divisor = null; |
||||
|
||||
|
||||
/** @var \Closure[] */ |
||||
protected static $__extensions = array(); |
||||
|
||||
public static function descriptor() |
||||
{ |
||||
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.DivArgs'); |
||||
|
||||
// REQUIRED INT64 dividend = 1 |
||||
$f = new \DrSlump\Protobuf\Field(); |
||||
$f->number = 1; |
||||
$f->name = "dividend"; |
||||
$f->type = \DrSlump\Protobuf::TYPE_INT64; |
||||
$f->rule = \DrSlump\Protobuf::RULE_REQUIRED; |
||||
$descriptor->addField($f); |
||||
|
||||
// REQUIRED INT64 divisor = 2 |
||||
$f = new \DrSlump\Protobuf\Field(); |
||||
$f->number = 2; |
||||
$f->name = "divisor"; |
||||
$f->type = \DrSlump\Protobuf::TYPE_INT64; |
||||
$f->rule = \DrSlump\Protobuf::RULE_REQUIRED; |
||||
$descriptor->addField($f); |
||||
|
||||
foreach (self::$__extensions as $cb) { |
||||
$descriptor->addField($cb(), true); |
||||
} |
||||
|
||||
return $descriptor; |
||||
} |
||||
|
||||
/** |
||||
* Check if <dividend> has a value |
||||
* |
||||
* @return boolean |
||||
*/ |
||||
public function hasDividend(){ |
||||
return $this->_has(1); |
||||
} |
||||
|
||||
/** |
||||
* Clear <dividend> value |
||||
* |
||||
* @return \math\DivArgs |
||||
*/ |
||||
public function clearDividend(){ |
||||
return $this->_clear(1); |
||||
} |
||||
|
||||
/** |
||||
* Get <dividend> value |
||||
* |
||||
* @return int |
||||
*/ |
||||
public function getDividend(){ |
||||
return $this->_get(1); |
||||
} |
||||
|
||||
/** |
||||
* Set <dividend> value |
||||
* |
||||
* @param int $value |
||||
* @return \math\DivArgs |
||||
*/ |
||||
public function setDividend( $value){ |
||||
return $this->_set(1, $value); |
||||
} |
||||
|
||||
/** |
||||
* Check if <divisor> has a value |
||||
* |
||||
* @return boolean |
||||
*/ |
||||
public function hasDivisor(){ |
||||
return $this->_has(2); |
||||
} |
||||
|
||||
/** |
||||
* Clear <divisor> value |
||||
* |
||||
* @return \math\DivArgs |
||||
*/ |
||||
public function clearDivisor(){ |
||||
return $this->_clear(2); |
||||
} |
||||
|
||||
/** |
||||
* Get <divisor> value |
||||
* |
||||
* @return int |
||||
*/ |
||||
public function getDivisor(){ |
||||
return $this->_get(2); |
||||
} |
||||
|
||||
/** |
||||
* Set <divisor> value |
||||
* |
||||
* @param int $value |
||||
* @return \math\DivArgs |
||||
*/ |
||||
public function setDivisor( $value){ |
||||
return $this->_set(2, $value); |
||||
} |
||||
} |
||||
} |
||||
|
||||
namespace math { |
||||
|
||||
class DivReply extends \DrSlump\Protobuf\Message { |
||||
|
||||
/** @var int */ |
||||
public $quotient = null; |
||||
|
||||
/** @var int */ |
||||
public $remainder = null; |
||||
|
||||
|
||||
/** @var \Closure[] */ |
||||
protected static $__extensions = array(); |
||||
|
||||
public static function descriptor() |
||||
{ |
||||
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.DivReply'); |
||||
|
||||
// REQUIRED INT64 quotient = 1 |
||||
$f = new \DrSlump\Protobuf\Field(); |
||||
$f->number = 1; |
||||
$f->name = "quotient"; |
||||
$f->type = \DrSlump\Protobuf::TYPE_INT64; |
||||
$f->rule = \DrSlump\Protobuf::RULE_REQUIRED; |
||||
$descriptor->addField($f); |
||||
|
||||
// REQUIRED INT64 remainder = 2 |
||||
$f = new \DrSlump\Protobuf\Field(); |
||||
$f->number = 2; |
||||
$f->name = "remainder"; |
||||
$f->type = \DrSlump\Protobuf::TYPE_INT64; |
||||
$f->rule = \DrSlump\Protobuf::RULE_REQUIRED; |
||||
$descriptor->addField($f); |
||||
|
||||
foreach (self::$__extensions as $cb) { |
||||
$descriptor->addField($cb(), true); |
||||
} |
||||
|
||||
return $descriptor; |
||||
} |
||||
|
||||
/** |
||||
* Check if <quotient> has a value |
||||
* |
||||
* @return boolean |
||||
*/ |
||||
public function hasQuotient(){ |
||||
return $this->_has(1); |
||||
} |
||||
|
||||
/** |
||||
* Clear <quotient> value |
||||
* |
||||
* @return \math\DivReply |
||||
*/ |
||||
public function clearQuotient(){ |
||||
return $this->_clear(1); |
||||
} |
||||
|
||||
/** |
||||
* Get <quotient> value |
||||
* |
||||
* @return int |
||||
*/ |
||||
public function getQuotient(){ |
||||
return $this->_get(1); |
||||
} |
||||
|
||||
/** |
||||
* Set <quotient> value |
||||
* |
||||
* @param int $value |
||||
* @return \math\DivReply |
||||
*/ |
||||
public function setQuotient( $value){ |
||||
return $this->_set(1, $value); |
||||
} |
||||
|
||||
/** |
||||
* Check if <remainder> has a value |
||||
* |
||||
* @return boolean |
||||
*/ |
||||
public function hasRemainder(){ |
||||
return $this->_has(2); |
||||
} |
||||
|
||||
/** |
||||
* Clear <remainder> value |
||||
* |
||||
* @return \math\DivReply |
||||
*/ |
||||
public function clearRemainder(){ |
||||
return $this->_clear(2); |
||||
} |
||||
|
||||
/** |
||||
* Get <remainder> value |
||||
* |
||||
* @return int |
||||
*/ |
||||
public function getRemainder(){ |
||||
return $this->_get(2); |
||||
} |
||||
|
||||
/** |
||||
* Set <remainder> value |
||||
* |
||||
* @param int $value |
||||
* @return \math\DivReply |
||||
*/ |
||||
public function setRemainder( $value){ |
||||
return $this->_set(2, $value); |
||||
} |
||||
} |
||||
} |
||||
|
||||
namespace math { |
||||
|
||||
class FibArgs extends \DrSlump\Protobuf\Message { |
||||
|
||||
/** @var int */ |
||||
public $limit = null; |
||||
|
||||
|
||||
/** @var \Closure[] */ |
||||
protected static $__extensions = array(); |
||||
|
||||
public static function descriptor() |
||||
{ |
||||
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.FibArgs'); |
||||
|
||||
// OPTIONAL INT64 limit = 1 |
||||
$f = new \DrSlump\Protobuf\Field(); |
||||
$f->number = 1; |
||||
$f->name = "limit"; |
||||
$f->type = \DrSlump\Protobuf::TYPE_INT64; |
||||
$f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; |
||||
$descriptor->addField($f); |
||||
|
||||
foreach (self::$__extensions as $cb) { |
||||
$descriptor->addField($cb(), true); |
||||
} |
||||
|
||||
return $descriptor; |
||||
} |
||||
|
||||
/** |
||||
* Check if <limit> has a value |
||||
* |
||||
* @return boolean |
||||
*/ |
||||
public function hasLimit(){ |
||||
return $this->_has(1); |
||||
} |
||||
|
||||
/** |
||||
* Clear <limit> value |
||||
* |
||||
* @return \math\FibArgs |
||||
*/ |
||||
public function clearLimit(){ |
||||
return $this->_clear(1); |
||||
} |
||||
|
||||
/** |
||||
* Get <limit> value |
||||
* |
||||
* @return int |
||||
*/ |
||||
public function getLimit(){ |
||||
return $this->_get(1); |
||||
} |
||||
|
||||
/** |
||||
* Set <limit> value |
||||
* |
||||
* @param int $value |
||||
* @return \math\FibArgs |
||||
*/ |
||||
public function setLimit( $value){ |
||||
return $this->_set(1, $value); |
||||
} |
||||
} |
||||
} |
||||
|
||||
namespace math { |
||||
|
||||
class Num extends \DrSlump\Protobuf\Message { |
||||
|
||||
/** @var int */ |
||||
public $num = null; |
||||
|
||||
|
||||
/** @var \Closure[] */ |
||||
protected static $__extensions = array(); |
||||
|
||||
public static function descriptor() |
||||
{ |
||||
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.Num'); |
||||
|
||||
// REQUIRED INT64 num = 1 |
||||
$f = new \DrSlump\Protobuf\Field(); |
||||
$f->number = 1; |
||||
$f->name = "num"; |
||||
$f->type = \DrSlump\Protobuf::TYPE_INT64; |
||||
$f->rule = \DrSlump\Protobuf::RULE_REQUIRED; |
||||
$descriptor->addField($f); |
||||
|
||||
foreach (self::$__extensions as $cb) { |
||||
$descriptor->addField($cb(), true); |
||||
} |
||||
|
||||
return $descriptor; |
||||
} |
||||
|
||||
/** |
||||
* Check if <num> has a value |
||||
* |
||||
* @return boolean |
||||
*/ |
||||
public function hasNum(){ |
||||
return $this->_has(1); |
||||
} |
||||
|
||||
/** |
||||
* Clear <num> value |
||||
* |
||||
* @return \math\Num |
||||
*/ |
||||
public function clearNum(){ |
||||
return $this->_clear(1); |
||||
} |
||||
|
||||
/** |
||||
* Get <num> value |
||||
* |
||||
* @return int |
||||
*/ |
||||
public function getNum(){ |
||||
return $this->_get(1); |
||||
} |
||||
|
||||
/** |
||||
* Set <num> value |
||||
* |
||||
* @param int $value |
||||
* @return \math\Num |
||||
*/ |
||||
public function setNum( $value){ |
||||
return $this->_set(1, $value); |
||||
} |
||||
} |
||||
} |
||||
|
||||
namespace math { |
||||
|
||||
class FibReply extends \DrSlump\Protobuf\Message { |
||||
|
||||
/** @var int */ |
||||
public $count = null; |
||||
|
||||
|
||||
/** @var \Closure[] */ |
||||
protected static $__extensions = array(); |
||||
|
||||
public static function descriptor() |
||||
{ |
||||
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.FibReply'); |
||||
|
||||
// REQUIRED INT64 count = 1 |
||||
$f = new \DrSlump\Protobuf\Field(); |
||||
$f->number = 1; |
||||
$f->name = "count"; |
||||
$f->type = \DrSlump\Protobuf::TYPE_INT64; |
||||
$f->rule = \DrSlump\Protobuf::RULE_REQUIRED; |
||||
$descriptor->addField($f); |
||||
|
||||
foreach (self::$__extensions as $cb) { |
||||
$descriptor->addField($cb(), true); |
||||
} |
||||
|
||||
return $descriptor; |
||||
} |
||||
|
||||
/** |
||||
* Check if <count> has a value |
||||
* |
||||
* @return boolean |
||||
*/ |
||||
public function hasCount(){ |
||||
return $this->_has(1); |
||||
} |
||||
|
||||
/** |
||||
* Clear <count> value |
||||
* |
||||
* @return \math\FibReply |
||||
*/ |
||||
public function clearCount(){ |
||||
return $this->_clear(1); |
||||
} |
||||
|
||||
/** |
||||
* Get <count> value |
||||
* |
||||
* @return int |
||||
*/ |
||||
public function getCount(){ |
||||
return $this->_get(1); |
||||
} |
||||
|
||||
/** |
||||
* Set <count> value |
||||
* |
||||
* @param int $value |
||||
* @return \math\FibReply |
||||
*/ |
||||
public function setCount( $value){ |
||||
return $this->_set(1, $value); |
||||
} |
||||
} |
||||
} |
||||
|
||||
namespace math { |
||||
|
||||
class MathClient extends \Grpc\BaseStub { |
||||
/** |
||||
* @param math\DivArgs $input |
||||
* @return math\DivReply |
||||
*/ |
||||
public function Div(\math\DivArgs $argument, $metadata = array()) { |
||||
return $this->_simpleRequest('/Math/Div', $argument, '\math\DivReply::deserialize', $metadata); |
||||
} |
||||
/** |
||||
* @param math\DivArgs $input |
||||
* @return math\DivReply |
||||
*/ |
||||
public function DivMany($metadata = array()) { |
||||
return $this->_bidiRequest('/Math/DivMany', '\math\DivReply::deserialize', $metadata); |
||||
} |
||||
/** |
||||
* @param math\FibArgs $input |
||||
* @return math\Num |
||||
*/ |
||||
public function Fib($argument, $metadata = array()) { |
||||
return $this->_serverStreamRequest('/Math/Fib', $argument, '\math\Num::deserialize', $metadata); |
||||
} |
||||
/** |
||||
* @param math\Num $input |
||||
* @return math\Num |
||||
*/ |
||||
public function Sum($arguments, $metadata = array()) { |
||||
return $this->_clientStreamRequest('/Math/Sum', $arguments, '\math\Num::deserialize', $metadata); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
<?php |
||||
// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0 |
||||
// Source: net/proto2/proto/empty.proto |
||||
// Date: 2014-12-03 22:02:20 |
||||
|
||||
namespace proto2 { |
||||
|
||||
class EmptyMessage extends \DrSlump\Protobuf\Message { |
||||
|
||||
|
||||
/** @var \Closure[] */ |
||||
protected static $__extensions = array(); |
||||
|
||||
public static function descriptor() |
||||
{ |
||||
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'proto2.EmptyMessage'); |
||||
|
||||
foreach (self::$__extensions as $cb) { |
||||
$descriptor->addField($cb(), true); |
||||
} |
||||
|
||||
return $descriptor; |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,191 @@ |
||||
<?php |
||||
require __DIR__ . '/../../lib/Grpc/ActiveCall.php'; |
||||
require __DIR__ . '/../../lib/Grpc/SurfaceActiveCall.php'; |
||||
require __DIR__ . '/../../lib/Grpc/BaseStub.php'; |
||||
require 'DrSlump/Protobuf.php'; |
||||
\DrSlump\Protobuf::autoload(); |
||||
require 'empty.php'; |
||||
require 'message_set.php'; |
||||
require 'messages.php'; |
||||
require 'test.php'; |
||||
/** |
||||
* Assertion function that always exits with an error code if the assertion is |
||||
* falsy |
||||
* @param $value Assertion value. Should be true. |
||||
* @param $error_message Message to display if the assertion is false |
||||
*/ |
||||
function hardAssert($value, $error_message) { |
||||
if(!$value) { |
||||
echo $error_message . "\n"; |
||||
exit(1); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Run the empty_unary test. |
||||
* Currently not tested against any server as of 2014-12-04 |
||||
* @param $stub Stub object that has service methods |
||||
*/ |
||||
function emptyUnary($stub) { |
||||
list($result, $status) = $stub->EmptyCall(new proto2\EmptyMessage())->wait(); |
||||
hardAssert($status->code == Grpc\STATUS_OK, 'Call did not complete successfully'); |
||||
hardAssert($result != null, 'Call completed with a null response'); |
||||
} |
||||
|
||||
/** |
||||
* Run the large_unary test. |
||||
* Passes when run against the C++ server as of 2014-12-04 |
||||
* Not tested against any other server as of 2014-12-04 |
||||
* @param $stub Stub object that has service methods |
||||
*/ |
||||
function largeUnary($stub) { |
||||
$request_len = 271828; |
||||
$response_len = 314159; |
||||
|
||||
$request = new grpc\testing\SimpleRequest(); |
||||
$request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); |
||||
$request->setResponseSize($response_len); |
||||
$payload = new grpc\testing\Payload(); |
||||
$payload->setType(grpc\testing\PayloadType::COMPRESSABLE); |
||||
$payload->setBody(str_repeat("\0", $request_len)); |
||||
$request->setPayload($payload); |
||||
|
||||
list($result, $status) = $stub->UnaryCall($request)->wait(); |
||||
hardAssert($status->code == Grpc\STATUS_OK, 'Call did not complete successfully'); |
||||
hardAssert($result != null, 'Call returned a null response'); |
||||
$payload = $result->getPayload(); |
||||
hardAssert($payload->getType() == grpc\testing\PayloadType::COMPRESSABLE, |
||||
'Payload had the wrong type'); |
||||
hardAssert(strlen($payload->getBody()) == $response_len, |
||||
'Payload had the wrong length'); |
||||
hardAssert($payload->getBody() == str_repeat("\0", $response_len), |
||||
'Payload had the wrong content'); |
||||
} |
||||
|
||||
/** |
||||
* Run the client_streaming test. |
||||
* Not tested against any server as of 2014-12-04. |
||||
* @param $stub Stub object that has service methods |
||||
*/ |
||||
function clientStreaming($stub) { |
||||
$request_lengths = array(27182, 8, 1828, 45904); |
||||
|
||||
$requests = array_map( |
||||
function($length) { |
||||
$request = new grpc\testing\StreamingInputCallRequest(); |
||||
$payload = new grpc\testing\Payload(); |
||||
$payload->setBody(str_repeat("\0", $length)); |
||||
$request->setPayload($payload); |
||||
return $request; |
||||
}, $request_lengths); |
||||
|
||||
list($result, $status) = $stub->StreamingInputCall($requests)->wait(); |
||||
hardAssert($status->code == Grpc\STATUS_OK, 'Call did not complete successfully'); |
||||
hardAssert($result->getAggregatedPayloadSize() == 74922, |
||||
'aggregated_payload_size was incorrect'); |
||||
} |
||||
|
||||
/** |
||||
* Run the server_streaming test. |
||||
* Not tested against any server as of 2014-12-04. |
||||
* @param $stub Stub object that has service methods. |
||||
*/ |
||||
function serverStreaming($stub) { |
||||
$sizes = array(31415, 9, 2653, 58979); |
||||
|
||||
$request = new grpc\testing\StreamingOutputCallRequest(); |
||||
$request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); |
||||
foreach($sizes as $size) { |
||||
$response_parameters = new grpc\testing\ResponseParameters(); |
||||
$response_parameters->setSize($size); |
||||
$request->addResponseParameters($response_parameters); |
||||
} |
||||
|
||||
$call = $stub->StreamingOutputCall($request); |
||||
hardAssert($call->getStatus()->code == Grpc\STATUS_OK, |
||||
'Call did not complete successfully'); |
||||
$i = 0; |
||||
foreach($call->responses() as $value) { |
||||
hardAssert($i < 4, 'Too many responses'); |
||||
$payload = $value->getPayload(); |
||||
hardAssert($payload->getType() == grpc\testing\PayloadType::COMPRESSABLE, |
||||
'Payload ' . $i . ' had the wrong type'); |
||||
hardAssert(strlen($payload->getBody()) == $sizes[$i], |
||||
'Response ' . $i . ' had the wrong length'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Run the ping_pong test. |
||||
* Not tested against any server as of 2014-12-04. |
||||
* @param $stub Stub object that has service methods. |
||||
*/ |
||||
function pingPong($stub) { |
||||
$request_lengths = array(27182, 8, 1828, 45904); |
||||
$response_lengths = array(31415, 9, 2653, 58979); |
||||
|
||||
$call = $stub->FullDuplexCall(); |
||||
for($i = 0; $i < 4; $i++) { |
||||
$request = new grpc\testing\StreamingOutputCallRequest(); |
||||
$request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); |
||||
$response_parameters = new grpc\testing\ResponseParameters(); |
||||
$response_parameters->setSize($response_lengths[$i]); |
||||
$request->addResponseParameters($response_parameters); |
||||
$payload = new grpc\testing\Payload(); |
||||
$payload->setBody(str_repeat("\0", $request_lengths[$i])); |
||||
$request->setPayload($payload); |
||||
|
||||
$call->write($request); |
||||
$response = $call->read(); |
||||
|
||||
hardAssert($response != null, 'Server returned too few responses'); |
||||
$payload = $response->getPayload(); |
||||
hardAssert($payload->getType() == grpc\testing\PayloadType::COMPRESSABLE, |
||||
'Payload ' . $i . ' had the wrong type'); |
||||
hardAssert(strlen($payload->getBody()) == $response_lengths[$i], |
||||
'Payload ' . $i . ' had the wrong length'); |
||||
} |
||||
$call->writesDone(); |
||||
hardAssert($call->read() == null, 'Server returned too many responses'); |
||||
hardAssert($call->getStatus()->code == Grpc\STATUS_OK, |
||||
'Call did not complete successfully'); |
||||
} |
||||
|
||||
$args = getopt('', array('server_host:', 'server_port:', 'test_case:')); |
||||
if (!array_key_exists('server_host', $args) || |
||||
!array_key_exists('server_port', $args) || |
||||
!array_key_exists('test_case', $args)) { |
||||
throw new Exception('Missing argument'); |
||||
} |
||||
|
||||
$server_address = $args['server_host'] . ':' . $args['server_port']; |
||||
|
||||
$credentials = Grpc\Credentials::createSsl( |
||||
file_get_contents(dirname(__FILE__) . '/../data/ca.pem')); |
||||
$stub = new grpc\testing\TestServiceClient( |
||||
$server_address, |
||||
[ |
||||
'grpc.ssl_target_name_override' => 'foo.test.google.com', |
||||
'credentials' => $credentials |
||||
]); |
||||
|
||||
echo "Connecting to $server_address\n"; |
||||
echo "Running test case $args[test_case]\n"; |
||||
|
||||
switch($args['test_case']) { |
||||
case 'empty_unary': |
||||
emptyUnary($stub); |
||||
break; |
||||
case 'large_unary': |
||||
largeUnary($stub); |
||||
break; |
||||
case 'client_streaming': |
||||
clientStreaming($stub); |
||||
break; |
||||
case 'server_streaming': |
||||
serverStreaming($stub); |
||||
break; |
||||
case 'ping_pong': |
||||
pingPong($stub); |
||||
break; |
||||
} |
@ -0,0 +1,26 @@ |
||||
<?php |
||||
// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0 |
||||
// Source: net/proto2/bridge/proto/message_set.proto |
||||
// Date: 2014-12-03 22:02:20 |
||||
|
||||
namespace proto2\bridge { |
||||
|
||||
class MessageSet extends \DrSlump\Protobuf\Message { |
||||
|
||||
|
||||
/** @var \Closure[] */ |
||||
protected static $__extensions = array(); |
||||
|
||||
public static function descriptor() |
||||
{ |
||||
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'proto2.bridge.MessageSet'); |
||||
|
||||
foreach (self::$__extensions as $cb) { |
||||
$descriptor->addField($cb(), true); |
||||
} |
||||
|
||||
return $descriptor; |
||||
} |
||||
} |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,52 @@ |
||||
<?php |
||||
// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0 |
||||
// Source: third_party/stubby/testing/proto/test.proto |
||||
// Date: 2014-12-03 22:02:20 |
||||
|
||||
namespace grpc\testing { |
||||
|
||||
class TestServiceClient extends \Grpc\BaseStub { |
||||
/** |
||||
* @param proto2\EmptyMessage $input |
||||
* @return proto2\EmptyMessage |
||||
*/ |
||||
public function EmptyCall(\proto2\EmptyMessage $argument, $metadata = array()) { |
||||
return $this->_simpleRequest('/TestService/EmptyCall', $argument, '\proto2\EmptyMessage::deserialize', $metadata); |
||||
} |
||||
/** |
||||
* @param grpc\testing\SimpleRequest $input |
||||
* @return grpc\testing\SimpleResponse |
||||
*/ |
||||
public function UnaryCall(\grpc\testing\SimpleRequest $argument, $metadata = array()) { |
||||
return $this->_simpleRequest('/TestService/UnaryCall', $argument, '\grpc\testing\SimpleResponse::deserialize', $metadata); |
||||
} |
||||
/** |
||||
* @param grpc\testing\StreamingOutputCallRequest $input |
||||
* @return grpc\testing\StreamingOutputCallResponse |
||||
*/ |
||||
public function StreamingOutputCall($argument, $metadata = array()) { |
||||
return $this->_serverStreamRequest('/TestService/StreamingOutputCall', $argument, '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata); |
||||
} |
||||
/** |
||||
* @param grpc\testing\StreamingInputCallRequest $input |
||||
* @return grpc\testing\StreamingInputCallResponse |
||||
*/ |
||||
public function StreamingInputCall($arguments, $metadata = array()) { |
||||
return $this->_clientStreamRequest('/TestService/StreamingInputCall', $arguments, '\grpc\testing\StreamingInputCallResponse::deserialize', $metadata); |
||||
} |
||||
/** |
||||
* @param grpc\testing\StreamingOutputCallRequest $input |
||||
* @return grpc\testing\StreamingOutputCallResponse |
||||
*/ |
||||
public function FullDuplexCall($metadata = array()) { |
||||
return $this->_bidiRequest('/TestService/FullDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata); |
||||
} |
||||
/** |
||||
* @param grpc\testing\StreamingOutputCallRequest $input |
||||
* @return grpc\testing\StreamingOutputCallResponse |
||||
*/ |
||||
public function HalfDuplexCall($metadata = array()) { |
||||
return $this->_bidiRequest('/TestService/HalfDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
<?php |
||||
class CallTest extends PHPUnit_Framework_TestCase{ |
||||
static $server; |
||||
|
||||
public static function setUpBeforeClass() { |
||||
$cq = new Grpc\CompletionQueue(); |
||||
self::$server = new Grpc\Server($cq, []); |
||||
self::$server->add_http2_port('localhost:9001'); |
||||
} |
||||
|
||||
public function setUp() { |
||||
$this->channel = new Grpc\Channel('localhost:9001', []); |
||||
$this->call = new Grpc\Call($this->channel, |
||||
'/foo', |
||||
Grpc\Timeval::inf_future()); |
||||
} |
||||
|
||||
/* These test methods with assertTrue(true) at the end just check that the |
||||
method calls completed without errors. PHPUnit warns for tests with no |
||||
asserts, and this avoids that warning without changing the meaning of the |
||||
tests */ |
||||
|
||||
public function testAddEmptyMetadata() { |
||||
$this->call->add_metadata([], 0); |
||||
/* Dummy assert: Checks that the previous call completed without error */ |
||||
$this->assertTrue(true); |
||||
} |
||||
|
||||
public function testAddSingleMetadata() { |
||||
$this->call->add_metadata(['key' => 'value'], 0); |
||||
/* Dummy assert: Checks that the previous call completed without error */ |
||||
$this->assertTrue(true); |
||||
} |
||||
|
||||
public function testAddMultiValueMetadata() { |
||||
$this->call->add_metadata(['key' => ['value1', 'value2']], 0); |
||||
/* Dummy assert: Checks that the previous call completed without error */ |
||||
$this->assertTrue(true); |
||||
} |
||||
|
||||
public function testAddSingleAndMultiValueMetadata() { |
||||
$this->call->add_metadata( |
||||
['key1' => 'value1', |
||||
'key2' => ['value2', 'value3']], 0); |
||||
/* Dummy assert: Checks that the previous call completed without error */ |
||||
$this->assertTrue(true); |
||||
} |
||||
} |
@ -0,0 +1,14 @@ |
||||
<?php |
||||
class CompletionQueueTest extends PHPUnit_Framework_TestCase{ |
||||
public function testNextReturnsNullWithNoCall() { |
||||
$cq = new Grpc\CompletionQueue(); |
||||
$event = $cq->next(Grpc\Timeval::zero()); |
||||
$this->assertNull($event); |
||||
} |
||||
|
||||
public function testPluckReturnsNullWithNoCall() { |
||||
$cq = new Grpc\CompletionQueue(); |
||||
$event = $cq->pluck(0, Grpc\Timeval::zero()); |
||||
$this->assertNull($event); |
||||
} |
||||
} |
@ -0,0 +1,185 @@ |
||||
<?php |
||||
class EndToEndTest extends PHPUnit_Framework_TestCase{ |
||||
public function setUp() { |
||||
$this->client_queue = new Grpc\CompletionQueue(); |
||||
$this->server_queue = new Grpc\CompletionQueue(); |
||||
$this->server = new Grpc\Server($this->server_queue, []); |
||||
$this->server->add_http2_port('localhost:9000'); |
||||
$this->channel = new Grpc\Channel('localhost:9000', []); |
||||
} |
||||
|
||||
public function tearDown() { |
||||
unset($this->channel); |
||||
unset($this->server); |
||||
unset($this->client_queue); |
||||
unset($this->server_queue); |
||||
} |
||||
|
||||
public function testSimpleRequestBody() { |
||||
$deadline = Grpc\Timeval::inf_future(); |
||||
$status_text = 'xyz'; |
||||
$call = new Grpc\Call($this->channel, |
||||
'dummy_method', |
||||
$deadline); |
||||
$tag = 1; |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$call->start_invoke($this->client_queue, |
||||
$tag, |
||||
$tag, |
||||
$tag)); |
||||
|
||||
$server_tag = 2; |
||||
|
||||
// the client invocation was accepted |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->get_type()); |
||||
|
||||
$this->assertEquals(Grpc\CALL_OK, $call->writes_done($tag)); |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->get_type()); |
||||
$this->assertEquals(Grpc\OP_OK, $event->get_data()); |
||||
|
||||
// check that a server rpc new was received |
||||
$this->server->start(); |
||||
$this->assertEquals(Grpc\CALL_OK, $this->server->request_call($server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\SERVER_RPC_NEW, $event->get_type()); |
||||
$server_call = $event->get_call(); |
||||
$this->assertNotNull($server_call); |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->accept($this->server_queue, $server_tag)); |
||||
|
||||
// the server sends the status |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->start_write_status(Grpc\STATUS_OK, |
||||
$status_text, |
||||
$server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->get_type()); |
||||
$this->assertEquals(Grpc\OP_OK, $event->get_data()); |
||||
|
||||
// the client gets CLIENT_METADATA_READ |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->get_type()); |
||||
|
||||
// the client gets FINISHED |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISHED, $event->get_type()); |
||||
$status = $event->get_data(); |
||||
$this->assertEquals(Grpc\STATUS_OK, $status->code); |
||||
$this->assertEquals($status_text, $status->details); |
||||
|
||||
// and the server gets FINISHED |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISHED, $event->get_type()); |
||||
$status = $event->get_data(); |
||||
|
||||
unset($call); |
||||
unset($server_call); |
||||
} |
||||
|
||||
public function testClientServerFullRequestResponse() { |
||||
$deadline = Grpc\Timeval::inf_future(); |
||||
$req_text = 'client_server_full_request_response'; |
||||
$reply_text = 'reply:client_server_full_request_response'; |
||||
$status_text = 'status:client_server_full_response_text'; |
||||
|
||||
$call = new Grpc\Call($this->channel, |
||||
'dummy_method', |
||||
$deadline); |
||||
$tag = 1; |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$call->start_invoke($this->client_queue, |
||||
$tag, |
||||
$tag, |
||||
$tag)); |
||||
|
||||
$server_tag = 2; |
||||
|
||||
// the client invocation was accepted |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->get_type()); |
||||
|
||||
// the client writes |
||||
$this->assertEquals(Grpc\CALL_OK, $call->start_write($req_text, $tag)); |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\WRITE_ACCEPTED, $event->get_type()); |
||||
|
||||
// check that a server rpc new was received |
||||
$this->server->start(); |
||||
$this->assertEquals(Grpc\CALL_OK, $this->server->request_call($server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\SERVER_RPC_NEW, $event->get_type()); |
||||
$server_call = $event->get_call(); |
||||
$this->assertNotNull($server_call); |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->accept($this->server_queue, $server_tag)); |
||||
|
||||
// start the server read |
||||
$this->assertEquals(Grpc\CALL_OK, $server_call->start_read($server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\READ, $event->get_type()); |
||||
$this->assertEquals($req_text, $event->get_data()); |
||||
|
||||
// the server replies |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->start_write($reply_text, $server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\WRITE_ACCEPTED, $event->get_type()); |
||||
|
||||
// the client reads the metadata |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->get_type()); |
||||
|
||||
// the client reads the reply |
||||
$this->assertEquals(Grpc\CALL_OK, $call->start_read($tag)); |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\READ, $event->get_type()); |
||||
$this->assertEquals($reply_text, $event->get_data()); |
||||
|
||||
// the client sends writes done |
||||
$this->assertEquals(Grpc\CALL_OK, $call->writes_done($tag)); |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->get_type()); |
||||
$this->assertEquals(Grpc\OP_OK, $event->get_data()); |
||||
|
||||
// the server sends the status |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->start_write_status(GRPC\STATUS_OK, |
||||
$status_text, |
||||
$server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->get_type()); |
||||
$this->assertEquals(Grpc\OP_OK, $event->get_data()); |
||||
|
||||
// the client gets FINISHED |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISHED, $event->get_type()); |
||||
$status = $event->get_data(); |
||||
$this->assertEquals(Grpc\STATUS_OK, $status->code); |
||||
$this->assertEquals($status_text, $status->details); |
||||
|
||||
// and the server gets FINISHED |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISHED, $event->get_type()); |
||||
|
||||
unset($call); |
||||
unset($server_call); |
||||
} |
||||
} |
@ -0,0 +1,196 @@ |
||||
<?php |
||||
class SecureEndToEndTest extends PHPUnit_Framework_TestCase{ |
||||
public function setUp() { |
||||
$this->client_queue = new Grpc\CompletionQueue(); |
||||
$this->server_queue = new Grpc\CompletionQueue(); |
||||
$credentials = Grpc\Credentials::createSsl( |
||||
file_get_contents(dirname(__FILE__) . '/../data/ca.pem')); |
||||
$server_credentials = Grpc\ServerCredentials::createSsl( |
||||
null, |
||||
file_get_contents(dirname(__FILE__) . '/../data/server1.key'), |
||||
file_get_contents(dirname(__FILE__) . '/../data/server1.pem')); |
||||
$this->server = new Grpc\Server($this->server_queue, |
||||
['credentials' => $server_credentials]); |
||||
$this->server->add_secure_http2_port('localhost:9000'); |
||||
$this->channel = new Grpc\Channel( |
||||
'localhost:9000', |
||||
[ |
||||
'grpc.ssl_target_name_override' => 'foo.test.google.com', |
||||
'credentials' => $credentials |
||||
]); |
||||
} |
||||
|
||||
public function tearDown() { |
||||
unset($this->channel); |
||||
unset($this->server); |
||||
unset($this->client_queue); |
||||
unset($this->server_queue); |
||||
} |
||||
|
||||
public function testSimpleRequestBody() { |
||||
$this->server->start(); |
||||
$deadline = Grpc\Timeval::inf_future(); |
||||
$status_text = 'xyz'; |
||||
$call = new Grpc\Call($this->channel, |
||||
'dummy_method', |
||||
$deadline); |
||||
$tag = 1; |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$call->start_invoke($this->client_queue, |
||||
$tag, |
||||
$tag, |
||||
$tag)); |
||||
$server_tag = 2; |
||||
|
||||
// the client invocation was accepted |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->get_type()); |
||||
|
||||
$this->assertEquals(Grpc\CALL_OK, $call->writes_done($tag)); |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->get_type()); |
||||
$this->assertEquals(Grpc\OP_OK, $event->get_data()); |
||||
|
||||
// check that a server rpc new was received |
||||
$this->assertEquals(Grpc\CALL_OK, $this->server->request_call($server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\SERVER_RPC_NEW, $event->get_type()); |
||||
$server_call = $event->get_call(); |
||||
$this->assertNotNull($server_call); |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->accept($this->server_queue, $server_tag)); |
||||
|
||||
// the server sends the status |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->start_write_status(Grpc\STATUS_OK, |
||||
$status_text, |
||||
$server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->get_type()); |
||||
$this->assertEquals(Grpc\OP_OK, $event->get_data()); |
||||
|
||||
// the client gets CLIENT_METADATA_READ |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->get_type()); |
||||
|
||||
// the client gets FINISHED |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISHED, $event->get_type()); |
||||
$status = $event->get_data(); |
||||
$this->assertEquals(Grpc\STATUS_OK, $status->code); |
||||
$this->assertEquals($status_text, $status->details); |
||||
|
||||
// and the server gets FINISHED |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISHED, $event->get_type()); |
||||
$status = $event->get_data(); |
||||
|
||||
unset($call); |
||||
unset($server_call); |
||||
} |
||||
|
||||
public function testClientServerFullRequestResponse() { |
||||
$this->server->start(); |
||||
$deadline = Grpc\Timeval::inf_future(); |
||||
$req_text = 'client_server_full_request_response'; |
||||
$reply_text = 'reply:client_server_full_request_response'; |
||||
$status_text = 'status:client_server_full_response_text'; |
||||
|
||||
$call = new Grpc\Call($this->channel, |
||||
'dummy_method', |
||||
$deadline); |
||||
$tag = 1; |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$call->start_invoke($this->client_queue, |
||||
$tag, |
||||
$tag, |
||||
$tag)); |
||||
|
||||
$server_tag = 2; |
||||
|
||||
// the client invocation was accepted |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->get_type()); |
||||
|
||||
// the client writes |
||||
$this->assertEquals(Grpc\CALL_OK, $call->start_write($req_text, $tag)); |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\WRITE_ACCEPTED, $event->get_type()); |
||||
|
||||
// check that a server rpc new was received |
||||
$this->assertEquals(Grpc\CALL_OK, $this->server->request_call($server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\SERVER_RPC_NEW, $event->get_type()); |
||||
$server_call = $event->get_call(); |
||||
$this->assertNotNull($server_call); |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->accept($this->server_queue, $server_tag)); |
||||
|
||||
// start the server read |
||||
$this->assertEquals(Grpc\CALL_OK, $server_call->start_read($server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\READ, $event->get_type()); |
||||
$this->assertEquals($req_text, $event->get_data()); |
||||
|
||||
// the server replies |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->start_write($reply_text, $server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\WRITE_ACCEPTED, $event->get_type()); |
||||
|
||||
// the client reads the metadata |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\CLIENT_METADATA_READ, $event->get_type()); |
||||
|
||||
// the client reads the reply |
||||
$this->assertEquals(Grpc\CALL_OK, $call->start_read($tag)); |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\READ, $event->get_type()); |
||||
$this->assertEquals($reply_text, $event->get_data()); |
||||
|
||||
// the client sends writes done |
||||
$this->assertEquals(Grpc\CALL_OK, $call->writes_done($tag)); |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->get_type()); |
||||
$this->assertEquals(Grpc\OP_OK, $event->get_data()); |
||||
|
||||
// the server sends the status |
||||
$this->assertEquals(Grpc\CALL_OK, |
||||
$server_call->start_write_status(GRPC\STATUS_OK, |
||||
$status_text, |
||||
$server_tag)); |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertEquals(Grpc\FINISH_ACCEPTED, $event->get_type()); |
||||
$this->assertEquals(Grpc\OP_OK, $event->get_data()); |
||||
|
||||
// the client gets FINISHED |
||||
$event = $this->client_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISHED, $event->get_type()); |
||||
$status = $event->get_data(); |
||||
$this->assertEquals(Grpc\STATUS_OK, $status->code); |
||||
$this->assertEquals($status_text, $status->details); |
||||
|
||||
// and the server gets FINISHED |
||||
$event = $this->server_queue->next($deadline); |
||||
$this->assertNotNull($event); |
||||
$this->assertEquals(Grpc\FINISHED, $event->get_type()); |
||||
|
||||
unset($call); |
||||
unset($server_call); |
||||
} |
||||
} |
@ -0,0 +1,32 @@ |
||||
<?php |
||||
class TimevalTest extends PHPUnit_Framework_TestCase{ |
||||
public function testCompareSame() { |
||||
$zero = Grpc\Timeval::zero(); |
||||
$this->assertEquals(0, Grpc\Timeval::compare($zero, $zero)); |
||||
} |
||||
|
||||
public function testPastIsLessThanZero() { |
||||
$zero = Grpc\Timeval::zero(); |
||||
$past = Grpc\Timeval::inf_past(); |
||||
$this->assertLessThan(0, Grpc\Timeval::compare($past, $zero)); |
||||
$this->assertGreaterThan(0, Grpc\Timeval::compare($zero, $past)); |
||||
} |
||||
|
||||
public function testFutureIsGreaterThanZero() { |
||||
$zero = Grpc\Timeval::zero(); |
||||
$future = Grpc\Timeval::inf_future(); |
||||
$this->assertLessThan(0, Grpc\Timeval::compare($zero, $future)); |
||||
$this->assertGreaterThan(0, Grpc\Timeval::compare($future, $zero)); |
||||
} |
||||
|
||||
/** |
||||
* @depends testFutureIsGreaterThanZero |
||||
*/ |
||||
public function testNowIsBetweenZeroAndFuture() { |
||||
$zero = Grpc\Timeval::zero(); |
||||
$future = Grpc\Timeval::inf_future(); |
||||
$now = Grpc\Timeval::now(); |
||||
$this->assertLessThan(0, Grpc\Timeval::compare($zero, $now)); |
||||
$this->assertLessThan(0, Grpc\Timeval::compare($now, $future)); |
||||
} |
||||
} |
Loading…
Reference in new issue