diff --git a/src/compiler/ruby_generator.cc b/src/compiler/ruby_generator.cc index 32b6a8d8e4a..a0bb92848b8 100644 --- a/src/compiler/ruby_generator.cc +++ b/src/compiler/ruby_generator.cc @@ -32,24 +32,20 @@ */ #include -#include #include #include +#include "src/compiler/config.h" #include "src/compiler/ruby_generator.h" #include "src/compiler/ruby_generator_helpers-inl.h" #include "src/compiler/ruby_generator_map-inl.h" #include "src/compiler/ruby_generator_string-inl.h" -#include -#include -#include -#include - -using google::protobuf::FileDescriptor; -using google::protobuf::ServiceDescriptor; -using google::protobuf::MethodDescriptor; -using google::protobuf::io::Printer; -using google::protobuf::io::StringOutputStream; + +using grpc::protobuf::FileDescriptor; +using grpc::protobuf::ServiceDescriptor; +using grpc::protobuf::MethodDescriptor; +using grpc::protobuf::io::Printer; +using grpc::protobuf::io::StringOutputStream; using std::map; using std::vector; @@ -57,38 +53,38 @@ namespace grpc_ruby_generator { namespace { // Prints out the method using the ruby gRPC DSL. -void PrintMethod(const MethodDescriptor *method, const std::string &package, +void PrintMethod(const MethodDescriptor *method, const grpc::string &package, Printer *out) { - std::string input_type = RubyTypeOf(method->input_type()->name(), package); + grpc::string input_type = RubyTypeOf(method->input_type()->name(), package); if (method->client_streaming()) { input_type = "stream(" + input_type + ")"; } - std::string output_type = RubyTypeOf(method->output_type()->name(), package); + grpc::string output_type = RubyTypeOf(method->output_type()->name(), package); if (method->server_streaming()) { output_type = "stream(" + output_type + ")"; } - std::map method_vars = + std::map method_vars = ListToDict({"mth.name", method->name(), "input.type", input_type, "output.type", output_type, }); out->Print(method_vars, "rpc :$mth.name$, $input.type$, $output.type$\n"); } // Prints out the service using the ruby gRPC DSL. -void PrintService(const ServiceDescriptor *service, const std::string &package, +void PrintService(const ServiceDescriptor *service, const grpc::string &package, Printer *out) { if (service->method_count() == 0) { return; } // Begin the service module - std::map module_vars = + std::map module_vars = ListToDict({"module.name", CapitalizeFirst(service->name()), }); out->Print(module_vars, "module $module.name$\n"); out->Indent(); // TODO(temiola): add documentation - std::string doc = "TODO: add proto service documentation here"; - std::map template_vars = + grpc::string doc = "TODO: add proto service documentation here"; + std::map template_vars = ListToDict({"Documentation", doc, }); out->Print("\n"); out->Print(template_vars, "# $Documentation$\n"); @@ -101,7 +97,7 @@ void PrintService(const ServiceDescriptor *service, const std::string &package, out->Print("\n"); out->Print("self.marshal_class_method = :encode\n"); out->Print("self.unmarshal_class_method = :decode\n"); - std::map pkg_vars = + std::map pkg_vars = ListToDict({"service.name", service->name(), "pkg.name", package, }); out->Print(pkg_vars, "self.service_name = '$pkg.name$.$service.name$'\n"); out->Print("\n"); @@ -121,8 +117,8 @@ void PrintService(const ServiceDescriptor *service, const std::string &package, } // namespace -std::string GetServices(const FileDescriptor *file) { - std::string output; +grpc::string GetServices(const FileDescriptor *file) { + grpc::string output; StringOutputStream output_stream(&output); Printer out(&output_stream, '$'); @@ -133,7 +129,7 @@ std::string GetServices(const FileDescriptor *file) { } // Write out a file header. - std::map header_comment_vars = ListToDict( + std::map header_comment_vars = ListToDict( {"file.name", file->name(), "file.package", file->package(), }); out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n"); out.Print(header_comment_vars, @@ -144,15 +140,15 @@ std::string GetServices(const FileDescriptor *file) { // Write out require statemment to import the separately generated file // that defines the messages used by the service. This is generated by the // main ruby plugin. - std::map dep_vars = + std::map dep_vars = ListToDict({"dep.name", MessagesRequireName(file), }); out.Print(dep_vars, "require '$dep.name$'\n"); // Write out services within the modules out.Print("\n"); - std::vector modules = Split(file->package(), '.'); + std::vector modules = Split(file->package(), '.'); for (size_t i = 0; i < modules.size(); ++i) { - std::map module_vars = + std::map module_vars = ListToDict({"module.name", CapitalizeFirst(modules[i]), }); out.Print(module_vars, "module $module.name$\n"); out.Indent(); diff --git a/src/compiler/ruby_generator.h b/src/compiler/ruby_generator.h index 4dd38e0c274..a2ab36d4d99 100644 --- a/src/compiler/ruby_generator.h +++ b/src/compiler/ruby_generator.h @@ -34,17 +34,11 @@ #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H -#include - -namespace google { -namespace protobuf { -class FileDescriptor; -} // namespace protobuf -} // namespace google +#include "src/compiler/config.h" namespace grpc_ruby_generator { -std::string GetServices(const google::protobuf::FileDescriptor *file); +grpc::string GetServices(const grpc::protobuf::FileDescriptor *file); } // namespace grpc_ruby_generator diff --git a/src/compiler/ruby_generator_helpers-inl.h b/src/compiler/ruby_generator_helpers-inl.h index f3a087b3f8e..9da7cab3c7f 100644 --- a/src/compiler/ruby_generator_helpers-inl.h +++ b/src/compiler/ruby_generator_helpers-inl.h @@ -34,15 +34,13 @@ #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H -#include - -#include +#include "src/compiler/config.h" #include "src/compiler/ruby_generator_string-inl.h" namespace grpc_ruby_generator { -inline bool ServicesFilename(const google::protobuf::FileDescriptor *file, - std::string *file_name_or_error) { +inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file, + grpc::string *file_name_or_error) { // Get output file name. static const unsigned proto_suffix_length = 6; // length of ".proto" if (file->name().size() > proto_suffix_length && @@ -57,8 +55,8 @@ inline bool ServicesFilename(const google::protobuf::FileDescriptor *file, } } -inline std::string MessagesRequireName( - const google::protobuf::FileDescriptor *file) { +inline grpc::string MessagesRequireName( + const grpc::protobuf::FileDescriptor *file) { return Replace(file->name(), ".proto", ""); } diff --git a/src/compiler/ruby_generator_map-inl.h b/src/compiler/ruby_generator_map-inl.h index f902b6d98f8..6b87774f213 100644 --- a/src/compiler/ruby_generator_map-inl.h +++ b/src/compiler/ruby_generator_map-inl.h @@ -34,11 +34,12 @@ #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H +#include "src/compiler/config.h" + #include #include #include #include // NOLINT -#include #include using std::initializer_list; @@ -49,18 +50,18 @@ namespace grpc_ruby_generator { // Converts an initializer list of the form { key0, value0, key1, value1, ... } // into a map of key* to value*. Is merely a readability helper for later code. -inline std::map ListToDict( - const initializer_list &values) { +inline std::map ListToDict( + const initializer_list &values) { if (values.size() % 2 != 0) { std::cerr << "Not every 'key' has a value in `values`." << std::endl; } - std::map value_map; + std::map value_map; auto value_iter = values.begin(); for (unsigned i = 0; i < values.size() / 2; ++i) { - std::string key = *value_iter; + grpc::string key = *value_iter; ++value_iter; - std::string value = *value_iter; + grpc::string value = *value_iter; value_map[key] = value; ++value_iter; } diff --git a/src/compiler/ruby_generator_string-inl.h b/src/compiler/ruby_generator_string-inl.h index bdd314c16e5..8da3a88da29 100644 --- a/src/compiler/ruby_generator_string-inl.h +++ b/src/compiler/ruby_generator_string-inl.h @@ -34,8 +34,9 @@ #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H +#include "src/compiler/config.h" + #include -#include #include #include @@ -45,10 +46,10 @@ using std::transform; namespace grpc_ruby_generator { // Split splits a string using char into elems. -inline std::vector &Split(const std::string &s, char delim, - std::vector *elems) { +inline std::vector &Split(const grpc::string &s, char delim, + std::vector *elems) { std::stringstream ss(s); - std::string item; + grpc::string item; while (getline(ss, item, delim)) { elems->push_back(item); } @@ -56,17 +57,17 @@ inline std::vector &Split(const std::string &s, char delim, } // Split splits a string using char, returning the result in a vector. -inline std::vector Split(const std::string &s, char delim) { - std::vector elems; +inline std::vector Split(const grpc::string &s, char delim) { + std::vector elems; Split(s, delim, &elems); return elems; } // Replace replaces from with to in s. -inline std::string Replace(std::string s, const std::string &from, - const std::string &to) { +inline grpc::string Replace(grpc::string s, const grpc::string &from, + const grpc::string &to) { size_t start_pos = s.find(from); - if (start_pos == std::string::npos) { + if (start_pos == grpc::string::npos) { return s; } s.replace(start_pos, from.length(), to); @@ -74,10 +75,10 @@ inline std::string Replace(std::string s, const std::string &from, } // ReplaceAll replaces all instances of search with replace in s. -inline std::string ReplaceAll(std::string s, const std::string &search, - const std::string &replace) { +inline grpc::string ReplaceAll(grpc::string s, const grpc::string &search, + const grpc::string &replace) { size_t pos = 0; - while ((pos = s.find(search, pos)) != std::string::npos) { + while ((pos = s.find(search, pos)) != grpc::string::npos) { s.replace(pos, search.length(), replace); pos += replace.length(); } @@ -85,10 +86,10 @@ inline std::string ReplaceAll(std::string s, const std::string &search, } // ReplacePrefix replaces from with to in s if search is a prefix of s. -inline bool ReplacePrefix(std::string *s, const std::string &from, - const std::string &to) { +inline bool ReplacePrefix(grpc::string *s, const grpc::string &from, + const grpc::string &to) { size_t start_pos = s->find(from); - if (start_pos == std::string::npos || start_pos != 0) { + if (start_pos == grpc::string::npos || start_pos != 0) { return false; } s->replace(start_pos, from.length(), to); @@ -96,7 +97,7 @@ inline bool ReplacePrefix(std::string *s, const std::string &from, } // CapitalizeFirst capitalizes the first char in a string. -inline std::string CapitalizeFirst(std::string s) { +inline grpc::string CapitalizeFirst(grpc::string s) { if (s.empty()) { return s; } @@ -105,15 +106,15 @@ inline std::string CapitalizeFirst(std::string s) { } // RubyTypeOf updates a proto type to the required ruby equivalent. -inline std::string RubyTypeOf(const std::string &a_type, - const std::string &package) { - std::string res(a_type); +inline grpc::string RubyTypeOf(const grpc::string &a_type, + const grpc::string &package) { + grpc::string res(a_type); ReplacePrefix(&res, package, ""); // remove the leading package if present ReplacePrefix(&res, ".", ""); // remove the leading . (no package) - if (res.find('.') == std::string::npos) { + if (res.find('.') == grpc::string::npos) { return res; } else { - std::vector prefixes_and_type = Split(res, '.'); + std::vector prefixes_and_type = Split(res, '.'); for (unsigned int i = 0; i < prefixes_and_type.size(); ++i) { if (i != 0) { res += "::"; // switch '.' to the ruby module delim diff --git a/src/compiler/ruby_plugin.cc b/src/compiler/ruby_plugin.cc index 4a6e9f7a5d3..bd10d46e9ca 100644 --- a/src/compiler/ruby_plugin.cc +++ b/src/compiler/ruby_plugin.cc @@ -32,43 +32,35 @@ */ // Generates Ruby gRPC service interface out of Protobuf IDL. -// -// This is a Proto2 compiler plugin. See net/proto2/compiler/proto/plugin.proto -// and net/proto2/compiler/public/plugin.h for more information on plugins. #include -#include +#include "src/compiler/config.h" #include "src/compiler/ruby_generator.h" #include "src/compiler/ruby_generator_helpers-inl.h" -#include -#include -#include -#include -#include -class RubyGrpcGenerator : public google::protobuf::compiler::CodeGenerator { +class RubyGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { public: RubyGrpcGenerator() {} ~RubyGrpcGenerator() {} - bool Generate(const google::protobuf::FileDescriptor *file, - const std::string ¶meter, - google::protobuf::compiler::GeneratorContext *context, - std::string *error) const { - std::string code = grpc_ruby_generator::GetServices(file); + bool Generate(const grpc::protobuf::FileDescriptor *file, + const grpc::string ¶meter, + grpc::protobuf::compiler::GeneratorContext *context, + grpc::string *error) const { + grpc::string code = grpc_ruby_generator::GetServices(file); if (code.size() == 0) { return true; // don't generate a file if there are no services } // Get output file name. - std::string file_name; + grpc::string file_name; if (!grpc_ruby_generator::ServicesFilename(file, &file_name)) { return false; } - std::unique_ptr output( + std::unique_ptr output( context->Open(file_name)); - google::protobuf::io::CodedOutputStream coded_out(output.get()); + grpc::protobuf::io::CodedOutputStream coded_out(output.get()); coded_out.WriteRaw(code.data(), code.size()); return true; } @@ -76,5 +68,5 @@ class RubyGrpcGenerator : public google::protobuf::compiler::CodeGenerator { int main(int argc, char *argv[]) { RubyGrpcGenerator generator; - return google::protobuf::compiler::PluginMain(argc, argv, &generator); + return grpc::protobuf::compiler::PluginMain(argc, argv, &generator); } diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c index 798747109a1..d0e324e2ccd 100644 --- a/src/php/ext/grpc/call.c +++ b/src/php/ext/grpc/call.c @@ -49,11 +49,11 @@ #include #include "grpc/support/log.h" +#include "grpc/support/alloc.h" #include "grpc/grpc.h" #include "timeval.h" #include "channel.h" -#include "completion_queue.h" #include "byte_buffer.h" zend_class_entry *grpc_ce_call; @@ -61,7 +61,19 @@ zend_class_entry *grpc_ce_call; /* Frees and destroys an instance of wrapped_grpc_call */ void free_wrapped_grpc_call(void *object TSRMLS_DC) { wrapped_grpc_call *call = (wrapped_grpc_call *)object; + grpc_event *event; if (call->owned && call->wrapped != NULL) { + if (call->queue != NULL) { + grpc_completion_queue_shutdown(call->queue); + event = grpc_completion_queue_next(call->queue, gpr_inf_future); + while (event != NULL) { + if (event->type == GRPC_QUEUE_SHUTDOWN) { + break; + } + event = grpc_completion_queue_next(call->queue, gpr_inf_future); + } + grpc_completion_queue_destroy(call->queue); + } grpc_call_destroy(call->wrapped); } efree(call); @@ -88,17 +100,23 @@ zend_object_value create_wrapped_grpc_call(zend_class_entry *class_type /* Wraps a grpc_call struct in a PHP object. Owned indicates whether the struct should be destroyed at the end of the object's lifecycle */ -zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned) { +zval *grpc_php_wrap_call(grpc_call *wrapped, grpc_completion_queue *queue, + bool owned) { zval *call_object; MAKE_STD_ZVAL(call_object); object_init_ex(call_object, grpc_ce_call); wrapped_grpc_call *call = (wrapped_grpc_call *)zend_object_store_get_object(call_object TSRMLS_CC); call->wrapped = wrapped; + call->queue = queue; return call_object; } -zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) { +/* Creates and returns a PHP array object with the data in a + * grpc_metadata_array. Returns NULL on failure */ +zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array) { + int count = metadata_array->count; + grpc_metadata *elements = metadata_array->metadata; int i; zval *array; zval **data = NULL; @@ -139,6 +157,64 @@ zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) { return array; } +/* Populates a grpc_metadata_array with the data in a PHP array object. + Returns true on success and false on failure */ +bool create_metadata_array(zval *array, grpc_metadata_array *metadata) { + zval **inner_array; + zval **value; + HashTable *array_hash; + HashPosition array_pointer; + HashTable *inner_array_hash; + HashPosition inner_array_pointer; + char *key; + uint key_len; + ulong index; + if (Z_TYPE_P(array) != IS_ARRAY) { + return false; + } + grpc_metadata_array_init(metadata); + array_hash = Z_ARRVAL_P(array); + for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer); + zend_hash_get_current_data_ex(array_hash, (void**)&inner_array, + &array_pointer) == SUCCESS; + zend_hash_move_forward_ex(array_hash, &array_pointer)) { + if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0, + &array_pointer) != HASH_KEY_IS_STRING) { + return false; + } + if (Z_TYPE_P(*inner_array) != IS_ARRAY) { + return false; + } + inner_array_hash = Z_ARRVAL_P(*inner_array); + metadata->capacity += zend_hash_num_elements(inner_array_hash); + } + metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata)); + for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer); + zend_hash_get_current_data_ex(array_hash, (void**)&inner_array, + &array_pointer) == SUCCESS; + zend_hash_move_forward_ex(array_hash, &array_pointer)) { + if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0, + &array_pointer) != HASH_KEY_IS_STRING) { + return false; + } + inner_array_hash = Z_ARRVAL_P(*inner_array); + for (zend_hash_internal_pointer_reset_ex(inner_array_hash, + &inner_array_pointer); + zend_hash_get_current_data_ex(inner_array_hash, (void**)&value, + &inner_array_pointer) == SUCCESS; + zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) { + if (Z_TYPE_P(*value) != IS_STRING) { + return false; + } + metadata->metadata[metadata->count].key = key; + metadata->metadata[metadata->count].value = Z_STRVAL_P(*value); + metadata->metadata[metadata->count].value_length = Z_STRLEN_P(*value); + metadata->count += 1; + } + } + return true; +} + /** * Constructs a new instance of the Call class. * @param Channel $channel The channel to associate the call with. Must not be @@ -157,9 +233,10 @@ PHP_METHOD(Call, __construct) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO", &channel_obj, grpc_ce_channel, &method, &method_len, &deadline_obj, grpc_ce_timeval) == FAILURE) { - zend_throw_exception(spl_ce_InvalidArgumentException, - "Call expects a Channel, a String, and a Timeval", - 1 TSRMLS_CC); + zend_throw_exception( + spl_ce_InvalidArgumentException, + "Call expects a Channel, a String, and a Timeval", + 1 TSRMLS_CC); return; } wrapped_grpc_channel *channel = @@ -175,289 +252,235 @@ PHP_METHOD(Call, __construct) { wrapped_grpc_timeval *deadline = (wrapped_grpc_timeval *)zend_object_store_get_object( deadline_obj TSRMLS_CC); - call->wrapped = grpc_channel_create_call_old( - channel->wrapped, method, channel->target, deadline->wrapped); + call->queue = grpc_completion_queue_create(); + call->wrapped = grpc_channel_create_call( + channel->wrapped, call->queue, method, channel->target, + deadline->wrapped); } /** - * Add metadata to the call. All array keys must be strings. If the value is a - * string, it is added as a key/value pair. If it is an array, each value is - * added paired with the same string - * @param array $metadata The metadata to add - * @param long $flags A bitwise combination of the Grpc\WRITE_* constants - * (optional) - * @return Void + * Start a batch of RPC actions. + * @param array batch Array of actions to take + * @return object Object with results of all actions */ -PHP_METHOD(Call, add_metadata) { +PHP_METHOD(Call, start_batch) { wrapped_grpc_call *call = (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); - grpc_metadata metadata; - grpc_call_error error_code; + grpc_op ops[8]; + size_t op_num = 0; zval *array; - zval **inner_array; zval **value; + zval **inner_value; HashTable *array_hash; HashPosition array_pointer; - HashTable *inner_array_hash; - HashPosition inner_array_pointer; + HashTable *status_hash; char *key; uint key_len; ulong index; - long flags = 0; - /* "a|l" == 1 array, 1 optional long */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &flags) == + grpc_metadata_array metadata; + grpc_metadata_array trailing_metadata; + grpc_metadata_array recv_metadata; + grpc_metadata_array recv_trailing_metadata; + grpc_status_code status; + char *status_details = NULL; + size_t status_details_capacity = 0; + grpc_byte_buffer *message; + int cancelled; + grpc_call_error error; + grpc_event *event; + zval *result; + char *message_str; + size_t message_len; + zval *recv_status; + grpc_metadata_array_init(&metadata); + grpc_metadata_array_init(&trailing_metadata); + grpc_metadata_array_init(&recv_metadata); + grpc_metadata_array_init(&recv_trailing_metadata); + MAKE_STD_ZVAL(result); + object_init(result); + /* "a" == 1 array */ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) { zend_throw_exception(spl_ce_InvalidArgumentException, - "add_metadata expects an array and an optional long", - 1 TSRMLS_CC); - return; + "start_batch expects an array", 1 TSRMLS_CC); + goto cleanup; } array_hash = Z_ARRVAL_P(array); for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer); - zend_hash_get_current_data_ex(array_hash, (void**)&inner_array, + zend_hash_get_current_data_ex(array_hash, (void**)&value, &array_pointer) == SUCCESS; zend_hash_move_forward_ex(array_hash, &array_pointer)) { if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0, - &array_pointer) != HASH_KEY_IS_STRING) { + &array_pointer) != HASH_KEY_IS_LONG) { zend_throw_exception(spl_ce_InvalidArgumentException, - "metadata keys must be strings", 1 TSRMLS_CC); - return; + "batch keys must be integers", 1 TSRMLS_CC); + goto cleanup; } - if (Z_TYPE_P(*inner_array) != IS_ARRAY) { - zend_throw_exception(spl_ce_InvalidArgumentException, - "metadata values must be arrays", - 1 TSRMLS_CC); - return; - } - inner_array_hash = Z_ARRVAL_P(*inner_array); - for (zend_hash_internal_pointer_reset_ex(inner_array_hash, - &inner_array_pointer); - zend_hash_get_current_data_ex(inner_array_hash, (void**)&value, - &inner_array_pointer) == SUCCESS; - zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) { - if (Z_TYPE_P(*value) != IS_STRING) { + switch(index) { + case GRPC_OP_SEND_INITIAL_METADATA: + if (!create_metadata_array(*value, &metadata)) { + zend_throw_exception(spl_ce_InvalidArgumentException, + "Bad metadata value given", 1 TSRMLS_CC); + goto cleanup; + } + ops[op_num].data.send_initial_metadata.count = + metadata.count; + ops[op_num].data.send_initial_metadata.metadata = + metadata.metadata; + break; + case GRPC_OP_SEND_MESSAGE: + if (Z_TYPE_PP(value) != IS_STRING) { + zend_throw_exception(spl_ce_InvalidArgumentException, + "Expected a string for send message", + 1 TSRMLS_CC); + } + ops[op_num].data.send_message = + string_to_byte_buffer(Z_STRVAL_PP(value), Z_STRLEN_PP(value)); + break; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + break; + case GRPC_OP_SEND_STATUS_FROM_SERVER: + status_hash = Z_ARRVAL_PP(value); + if (zend_hash_find(status_hash, "metadata", sizeof("metadata"), + (void **)&inner_value) == SUCCESS) { + if (!create_metadata_array(*inner_value, &trailing_metadata)) { + zend_throw_exception(spl_ce_InvalidArgumentException, + "Bad trailing metadata value given", + 1 TSRMLS_CC); + goto cleanup; + } + ops[op_num].data.send_status_from_server.trailing_metadata = + trailing_metadata.metadata; + ops[op_num].data.send_status_from_server.trailing_metadata_count = + trailing_metadata.count; + } + if (zend_hash_find(status_hash, "code", sizeof("code"), + (void**)&inner_value) == SUCCESS) { + if (Z_TYPE_PP(inner_value) != IS_LONG) { + zend_throw_exception(spl_ce_InvalidArgumentException, + "Status code must be an integer", + 1 TSRMLS_CC); + goto cleanup; + } + ops[op_num].data.send_status_from_server.status = + Z_LVAL_PP(inner_value); + } else { + zend_throw_exception(spl_ce_InvalidArgumentException, + "Integer status code is required", + 1 TSRMLS_CC); + goto cleanup; + } + if (zend_hash_find(status_hash, "details", sizeof("details"), + (void**)&inner_value) == SUCCESS) { + if (Z_TYPE_PP(inner_value) != IS_STRING) { + zend_throw_exception(spl_ce_InvalidArgumentException, + "Status details must be a string", + 1 TSRMLS_CC); + goto cleanup; + } + ops[op_num].data.send_status_from_server.status_details = + Z_STRVAL_PP(inner_value); + } else { + zend_throw_exception(spl_ce_InvalidArgumentException, + "String status details is required", + 1 TSRMLS_CC); + goto cleanup; + } + break; + case GRPC_OP_RECV_INITIAL_METADATA: + ops[op_num].data.recv_initial_metadata = &recv_metadata; + break; + case GRPC_OP_RECV_MESSAGE: + ops[op_num].data.recv_message = &message; + break; + case GRPC_OP_RECV_STATUS_ON_CLIENT: + ops[op_num].data.recv_status_on_client.trailing_metadata = + &recv_trailing_metadata; + ops[op_num].data.recv_status_on_client.status = &status; + ops[op_num].data.recv_status_on_client.status_details = + &status_details; + ops[op_num].data.recv_status_on_client.status_details_capacity = + &status_details_capacity; + break; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + ops[op_num].data.recv_close_on_server.cancelled = &cancelled; + break; + default: zend_throw_exception(spl_ce_InvalidArgumentException, - "metadata values must be arrays of strings", - 1 TSRMLS_CC); - return; - } - metadata.key = key; - metadata.value = Z_STRVAL_P(*value); - metadata.value_length = Z_STRLEN_P(*value); - error_code = grpc_call_add_metadata_old(call->wrapped, &metadata, 0u); - MAYBE_THROW_CALL_ERROR(add_metadata, error_code); + "Unrecognized key in batch", 1 TSRMLS_CC); + goto cleanup; } + ops[op_num].op = (grpc_op_type)index; + op_num++; } -} - -/** - * Invoke the RPC. Starts sending metadata and request headers over the wire - * @param CompletionQueue $queue The completion queue to use with this call - * @param long $metadata_tag The tag to associate with returned metadata - * @param long $finished_tag The tag to associate with the finished event - * @param long $flags A bitwise combination of the Grpc\WRITE_* constants - * (optional) - * @return Void - */ -PHP_METHOD(Call, invoke) { - grpc_call_error error_code; - long tag1; - long tag2; - zval *queue_obj; - long flags = 0; - /* "Oll|l" == 1 Object, 3 mandatory longs, 1 optional long */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oll|l", &queue_obj, - grpc_ce_completion_queue, &tag1, &tag2, - &flags) == FAILURE) { - zend_throw_exception( - spl_ce_InvalidArgumentException, - "invoke needs a CompletionQueue, 2 longs, and an optional long", - 1 TSRMLS_CC); - return; - } - add_property_zval(getThis(), "completion_queue", queue_obj); - wrapped_grpc_call *call = - (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); - wrapped_grpc_completion_queue *queue = - (wrapped_grpc_completion_queue *)zend_object_store_get_object( - queue_obj TSRMLS_CC); - error_code = grpc_call_invoke_old(call->wrapped, queue->wrapped, (void *)tag1, - (void *)tag2, (gpr_uint32)flags); - MAYBE_THROW_CALL_ERROR(invoke, error_code); -} - -/** - * Accept an incoming RPC, binding a completion queue to it. To be called after - * adding metadata to the call, but before sending messages. Can only be called - * on the server - * @param CompletionQueue $queue The completion queue to use with this call - * @param long $finished_tag The tag to associate with the finished event - * @param long $flags A bitwise combination of the Grpc\WRITE_* constants - * (optional) - * @return Void - */ -PHP_METHOD(Call, server_accept) { - long tag; - zval *queue_obj; - grpc_call_error error_code; - /* "Ol|l" == 1 Object, 1 long */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &queue_obj, - grpc_ce_completion_queue, &tag) == FAILURE) { - zend_throw_exception( - spl_ce_InvalidArgumentException, - "server_accept expects a CompletionQueue, a long, and an optional long", - 1 TSRMLS_CC); - return; + error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped); + if (error != GRPC_CALL_OK) { + zend_throw_exception(spl_ce_LogicException, + "start_batch was called incorrectly", + (long)error TSRMLS_CC); + goto cleanup; } - add_property_zval(getThis(), "completion_queue", queue_obj); - wrapped_grpc_call *call = - (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); - wrapped_grpc_completion_queue *queue = - (wrapped_grpc_completion_queue *)zend_object_store_get_object( - queue_obj TSRMLS_CC); - error_code = - grpc_call_server_accept_old(call->wrapped, queue->wrapped, (void *)tag); - MAYBE_THROW_CALL_ERROR(server_accept, error_code); -} - -PHP_METHOD(Call, server_end_initial_metadata) { - grpc_call_error error_code; - long flags = 0; - /* "|l" == 1 optional long */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == - FAILURE) { - zend_throw_exception(spl_ce_InvalidArgumentException, - "server_end_initial_metadata expects an optional long", - 1 TSRMLS_CC); - } - wrapped_grpc_call *call = - (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); - error_code = grpc_call_server_end_initial_metadata_old(call->wrapped, flags); - MAYBE_THROW_CALL_ERROR(server_end_initial_metadata, error_code); -} - -/** - * Called by clients to cancel an RPC on the server. - * @return Void - */ -PHP_METHOD(Call, cancel) { - wrapped_grpc_call *call = - (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); - grpc_call_error error_code = grpc_call_cancel(call->wrapped); - MAYBE_THROW_CALL_ERROR(cancel, error_code); -} - -/** - * Queue a byte buffer for writing - * @param string $buffer The buffer to queue for writing - * @param long $tag The tag to associate with this write - * @param long $flags A bitwise combination of the Grpc\WRITE_* constants - * (optional) - * @return Void - */ -PHP_METHOD(Call, start_write) { - grpc_call_error error_code; - wrapped_grpc_call *call = - (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); - char *buffer; - int buffer_len; - long tag; - long flags = 0; - /* "Ol|l" == 1 Object, 1 mandatory long, 1 optional long */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &buffer, - &buffer_len, &tag, &flags) == FAILURE) { - zend_throw_exception(spl_ce_InvalidArgumentException, - "start_write expects a string and an optional long", + event = grpc_completion_queue_pluck(call->queue, call->wrapped, + gpr_inf_future); + if (event->data.op_complete != GRPC_OP_OK) { + zend_throw_exception(spl_ce_LogicException, + "The batch failed for some reason", 1 TSRMLS_CC); - return; - } - error_code = grpc_call_start_write_old( - call->wrapped, string_to_byte_buffer(buffer, buffer_len), (void *)tag, - (gpr_uint32)flags); - MAYBE_THROW_CALL_ERROR(start_write, error_code); -} - -/** - * Queue a status for writing - * @param long $status_code The status code to send - * @param string $status_details The status details to send - * @param long $tag The tag to associate with this status - * @return Void - */ -PHP_METHOD(Call, start_write_status) { - grpc_call_error error_code; - wrapped_grpc_call *call = - (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); - long status_code; - int status_details_length; - long tag; - char *status_details; - /* "lsl" == 1 long, 1 string, 1 long */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &status_code, - &status_details, &status_details_length, - &tag) == FAILURE) { - zend_throw_exception( - spl_ce_InvalidArgumentException, - "start_write_status expects a long, a string, and a long", 1 TSRMLS_CC); - return; + goto cleanup; } - error_code = grpc_call_start_write_status_old(call->wrapped, - (grpc_status_code)status_code, - status_details, (void *)tag); - MAYBE_THROW_CALL_ERROR(start_write_status, error_code); -} - -/** - * Indicate that there are no more messages to send - * @return Void - */ -PHP_METHOD(Call, writes_done) { - grpc_call_error error_code; - wrapped_grpc_call *call = - (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); - long tag; - /* "l" == 1 long */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) { - zend_throw_exception(spl_ce_InvalidArgumentException, - "writes_done expects a long", 1 TSRMLS_CC); - return; + for (int i = 0; i < op_num; i++) { + switch(ops[i].op) { + case GRPC_OP_SEND_INITIAL_METADATA: + add_property_bool(result, "send_metadata", true); + break; + case GRPC_OP_SEND_MESSAGE: + add_property_bool(result, "send_message", true); + break; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + add_property_bool(result, "send_close", true); + break; + case GRPC_OP_SEND_STATUS_FROM_SERVER: + add_property_bool(result, "send_status", true); + break; + case GRPC_OP_RECV_INITIAL_METADATA: + add_property_zval(result, "metadata", + grpc_parse_metadata_array(&recv_metadata)); + break; + case GRPC_OP_RECV_MESSAGE: + byte_buffer_to_string(message, &message_str, &message_len); + add_property_stringl(result, "message", message_str, message_len, + false); + break; + case GRPC_OP_RECV_STATUS_ON_CLIENT: + MAKE_STD_ZVAL(recv_status); + object_init(recv_status); + add_property_zval(recv_status, "metadata", + grpc_parse_metadata_array(&recv_trailing_metadata)); + add_property_long(recv_status, "code", status); + add_property_string(recv_status, "details", status_details, true); + add_property_zval(result, "status", recv_status); + break; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + add_property_bool(result, "cancelled", cancelled); + break; + default: + break; + } } - error_code = grpc_call_writes_done_old(call->wrapped, (void *)tag); - MAYBE_THROW_CALL_ERROR(writes_done, error_code); -} - -/** - * Initiate a read on a call. Output event contains a byte buffer with the - * result of the read - * @param long $tag The tag to associate with this read - * @return Void - */ -PHP_METHOD(Call, start_read) { - grpc_call_error error_code; - wrapped_grpc_call *call = - (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); - long tag; - /* "l" == 1 long */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) { - zend_throw_exception(spl_ce_InvalidArgumentException, - "start_read expects a long", 1 TSRMLS_CC); - return; +cleanup: + grpc_metadata_array_destroy(&metadata); + grpc_metadata_array_destroy(&trailing_metadata); + grpc_metadata_array_destroy(&recv_metadata); + grpc_metadata_array_destroy(&recv_trailing_metadata); + if (status_details != NULL) { + gpr_free(status_details); } - error_code = grpc_call_start_read_old(call->wrapped, (void *)tag); - MAYBE_THROW_CALL_ERROR(start_read, error_code); + RETURN_DESTROY_ZVAL(result); } static zend_function_entry call_methods[] = { PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) - PHP_ME(Call, server_accept, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Call, server_end_initial_metadata, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Call, invoke, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Call, start_read, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Call, start_write, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Call, start_write_status, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Call, writes_done, NULL, ZEND_ACC_PUBLIC) PHP_FE_END}; + PHP_ME(Call, start_batch, NULL, ZEND_ACC_PUBLIC) PHP_FE_END}; void grpc_init_call(TSRMLS_D) { zend_class_entry ce; diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h index bce5d82974f..743effe5a1b 100644 --- a/src/php/ext/grpc/call.h +++ b/src/php/ext/grpc/call.h @@ -45,17 +45,6 @@ #include "grpc/grpc.h" -// Throw an exception if error_code is not OK -#define MAYBE_THROW_CALL_ERROR(func_name, error_code) \ - do { \ - if (error_code != GRPC_CALL_OK) { \ - zend_throw_exception(spl_ce_LogicException, \ - #func_name " was called incorrectly", \ - (long)error_code TSRMLS_CC); \ - return; \ - } \ - } while (0) - /* Class entry for the Call PHP class */ extern zend_class_entry *grpc_ce_call; @@ -65,16 +54,18 @@ typedef struct wrapped_grpc_call { bool owned; grpc_call *wrapped; + grpc_completion_queue *queue; } 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, bool owned); +zval *grpc_php_wrap_call(grpc_call *wrapped, grpc_completion_queue *queue, + bool owned); /* 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); +zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array); #endif /* NET_GRPC_PHP_GRPC_CHANNEL_H_ */ diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c index 5e99332fab8..c96fb128a60 100644 --- a/src/php/ext/grpc/channel.c +++ b/src/php/ext/grpc/channel.c @@ -51,7 +51,6 @@ #include "grpc/support/log.h" #include "grpc/grpc_security.h" -#include "completion_queue.h" #include "server.h" #include "credentials.h" @@ -139,6 +138,9 @@ PHP_METHOD(Channel, __construct) { HashTable *array_hash; zval **creds_obj = NULL; wrapped_grpc_credentials *creds = NULL; + zval **override_obj; + char *override; + int override_len; /* "s|a" == 1 string, 1 optional array */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &target, &target_length, &args_array) == FAILURE) { @@ -146,6 +148,8 @@ PHP_METHOD(Channel, __construct) { "Channel expects a string and an array", 1 TSRMLS_CC); return; } + override = target; + override_len = target_length; if (args_array == NULL) { channel->wrapped = grpc_channel_create(target, NULL); } else { @@ -162,6 +166,19 @@ PHP_METHOD(Channel, __construct) { *creds_obj TSRMLS_CC); zend_hash_del(array_hash, "credentials", 12); } + if (zend_hash_find(array_hash, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, + sizeof(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG), + (void **)&override_obj) == SUCCESS) { + if (Z_TYPE_PP(override_obj) != IS_STRING) { + zend_throw_exception(spl_ce_InvalidArgumentException, + GRPC_SSL_TARGET_NAME_OVERRIDE_ARG + " must be a string", + 1 TSRMLS_CC); + return; + } + override = Z_STRVAL_PP(override_obj); + override_len = Z_STRLEN_PP(override_obj); + } php_grpc_read_args_array(args_array, &args); if (creds == NULL) { channel->wrapped = grpc_channel_create(target, &args); @@ -172,8 +189,8 @@ PHP_METHOD(Channel, __construct) { } efree(args.args); } - channel->target = ecalloc(target_length + 1, sizeof(char)); - memcpy(channel->target, target, target_length); + channel->target = ecalloc(override_len + 1, sizeof(char)); + memcpy(channel->target, override, override_len); } /** diff --git a/src/php/ext/grpc/completion_queue.c b/src/php/ext/grpc/completion_queue.c deleted file mode 100644 index 93abf5df36b..00000000000 --- a/src/php/ext/grpc/completion_queue.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#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 - -#include "grpc/grpc.h" - -#include "event.h" -#include "timeval.h" - -zend_class_entry *grpc_ce_completion_queue; - -/* 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_convert_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_convert_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); -} diff --git a/src/php/ext/grpc/completion_queue.h b/src/php/ext/grpc/completion_queue.h deleted file mode 100755 index 1d386cc58f4..00000000000 --- a/src/php/ext/grpc/completion_queue.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef 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 */ -extern 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_ */ diff --git a/src/php/ext/grpc/config.m4 b/src/php/ext/grpc/config.m4 index 27c67781e78..d1a8decb73a 100755 --- a/src/php/ext/grpc/config.m4 +++ b/src/php/ext/grpc/config.m4 @@ -66,5 +66,5 @@ if test "$PHP_GRPC" != "no"; then 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) + PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c credentials.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -pedantic -std=c99) fi diff --git a/src/php/ext/grpc/event.c b/src/php/ext/grpc/event.c deleted file mode 100644 index 452c4b8bcba..00000000000 --- a/src/php/ext/grpc/event.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#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 - -#include "grpc/grpc.h" - -#include "byte_buffer.h" -#include "call.h" -#include "timeval.h" - -/* Create a new PHP object containing the event data in the event struct. - event must not be used after this function is called */ -zval *grpc_php_convert_event(grpc_event *event) { - zval *data_object; - 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; - - zval *event_object; - - if (event == NULL) { - return NULL; - } - - MAKE_STD_ZVAL(event_object); - object_init(event_object); - - add_property_zval( - event_object, "call", - grpc_php_wrap_call(event->call, event->type == GRPC_SERVER_RPC_NEW)); - add_property_long(event_object, "type", event->type); - add_property_long(event_object, "tag", (long)event->tag); - - switch (event->type) { - case GRPC_QUEUE_SHUTDOWN: - add_property_null(event_object, "data"); - break; - case GRPC_READ: - if (event->data.read == NULL) { - add_property_null(event_object, "data"); - } else { - byte_buffer_to_string(event->data.read, &read_string, &read_len); - add_property_stringl(event_object, "data", read_string, read_len, true); - } - break; - case GRPC_WRITE_ACCEPTED: - add_property_long(event_object, "data", (long)event->data.write_accepted); - break; - case GRPC_FINISH_ACCEPTED: - add_property_long(event_object, "data", - (long)event->data.finish_accepted); - break; - case GRPC_CLIENT_METADATA_READ: - data_object = grpc_call_create_metadata_array( - event->data.client_metadata_read.count, - event->data.client_metadata_read.elements); - add_property_zval(event_object, "data", data_object); - break; - case GRPC_FINISHED: - MAKE_STD_ZVAL(data_object); - object_init(data_object); - add_property_long(data_object, "code", event->data.finished.status); - if (event->data.finished.details == NULL) { - add_property_null(data_object, "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(data_object, "details", detail_string, true); - } - add_property_zval(data_object, "metadata", - grpc_call_create_metadata_array( - event->data.finished.metadata_count, - event->data.finished.metadata_elements)); - add_property_zval(event_object, "data", data_object); - break; - case GRPC_SERVER_RPC_NEW: - MAKE_STD_ZVAL(data_object); - object_init(data_object); - 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(data_object, "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(data_object, "host", host_string, false); - add_property_zval( - data_object, "absolute_timeout", - grpc_php_wrap_timeval(event->data.server_rpc_new.deadline)); - add_property_zval(data_object, "metadata", - grpc_call_create_metadata_array( - event->data.server_rpc_new.metadata_count, - event->data.server_rpc_new.metadata_elements)); - add_property_zval(event_object, "data", data_object); - break; - default: - add_property_null(event_object, "data"); - break; - } - grpc_event_finish(event); - return event_object; -} diff --git a/src/php/ext/grpc/event.h b/src/php/ext/grpc/event.h deleted file mode 100755 index ef5846aee1d..00000000000 --- a/src/php/ext/grpc/event.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef 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" - -/* Create a new Event object that wraps an existing grpc_event struct */ -zval *grpc_php_convert_event(grpc_event *event); - -#endif /* NET_GRPC_PHP_GRPC_COMPLETION_CHANNEL_H */ diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c index 67e366c385d..1f9edfe881a 100644 --- a/src/php/ext/grpc/php_grpc.c +++ b/src/php/ext/grpc/php_grpc.c @@ -34,8 +34,6 @@ #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" @@ -127,27 +125,12 @@ PHP_MINIT_FUNCTION(grpc) { 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\\FINISH_ACCEPTED", GRPC_FINISH_ACCEPTED, - CONST_CS); - REGISTER_LONG_CONSTANT("Grpc\\WRITE_ACCEPTED", GRPC_WRITE_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, @@ -181,10 +164,27 @@ PHP_MINIT_FUNCTION(grpc) { REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS", GRPC_STATUS_DATA_LOSS, CONST_CS); + /* Register op type constants */ + REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_INITIAL_METADATA", + GRPC_OP_SEND_INITIAL_METADATA, CONST_CS); + REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_MESSAGE", + GRPC_OP_SEND_MESSAGE, CONST_CS); + REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_CLOSE_FROM_CLIENT", + GRPC_OP_SEND_CLOSE_FROM_CLIENT, CONST_CS); + REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_STATUS_FROM_SERVER", + GRPC_OP_SEND_STATUS_FROM_SERVER, CONST_CS); + REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_INITIAL_METADATA", + GRPC_OP_RECV_INITIAL_METADATA, CONST_CS); + REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_MESSAGE", + GRPC_OP_RECV_MESSAGE, CONST_CS); + REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_STATUS_ON_CLIENT", + GRPC_OP_RECV_STATUS_ON_CLIENT, CONST_CS); + REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_CLOSE_ON_SERVER", + GRPC_OP_RECV_CLOSE_ON_SERVER, 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_timeval(TSRMLS_C); grpc_init_credentials(TSRMLS_C); grpc_init_server_credentials(TSRMLS_C); diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c index a5cfd952871..86b29958fbf 100644 --- a/src/php/ext/grpc/server.c +++ b/src/php/ext/grpc/server.c @@ -52,15 +52,27 @@ #include "grpc/grpc_security.h" #include "server.h" -#include "completion_queue.h" #include "channel.h" #include "server_credentials.h" +#include "timeval.h" zend_class_entry *grpc_ce_server; /* 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; + grpc_event *event; + if (server->queue != NULL) { + grpc_completion_queue_shutdown(server->queue); + event = grpc_completion_queue_next(server->queue, gpr_inf_future); + while (event != NULL) { + if (event->type == GRPC_QUEUE_SHUTDOWN) { + break; + } + event = grpc_completion_queue_next(server->queue, gpr_inf_future); + } + grpc_completion_queue_destroy(server->queue); + } if (server->wrapped != NULL) { grpc_server_shutdown(server->wrapped); grpc_server_destroy(server->wrapped); @@ -95,26 +107,22 @@ zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type 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; - /* "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) { + /* "|a" == 1 optional array */ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &args_array) == + FAILURE) { zend_throw_exception(spl_ce_InvalidArgumentException, - "Server expects a CompletionQueue and an array", + "Server expects 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); + server->queue = grpc_completion_queue_create(); if (args_array == NULL) { - server->wrapped = grpc_server_create(queue->wrapped, NULL); + server->wrapped = grpc_server_create(server->queue, NULL); } else { php_grpc_read_args_array(args_array, &args); - server->wrapped = grpc_server_create(queue->wrapped, &args); + server->wrapped = grpc_server_create(server->queue, &args); efree(args.args); } } @@ -129,16 +137,40 @@ PHP_METHOD(Server, request_call) { grpc_call_error error_code; 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_call *call; + grpc_call_details details; + grpc_metadata_array metadata; + zval *result; + grpc_event *event; + MAKE_STD_ZVAL(result); + object_init(result); + grpc_call_details_init(&details); + grpc_metadata_array_init(&metadata); + error_code = grpc_server_request_call(server->wrapped, &call, &details, + &metadata, server->queue, NULL); + if (error_code != GRPC_CALL_OK) { + zend_throw_exception(spl_ce_LogicException, "request_call failed", + (long)error_code TSRMLS_CC); + goto cleanup; + } + event = grpc_completion_queue_pluck(server->queue, NULL, gpr_inf_future); + if (event->data.op_complete != GRPC_OP_OK) { + zend_throw_exception(spl_ce_LogicException, + "Failed to request a call for some reason", + 1 TSRMLS_CC); + goto cleanup; } - error_code = grpc_server_request_call_old(server->wrapped, (void *)tag_new); - MAYBE_THROW_CALL_ERROR(request_call, error_code); + add_property_zval(result, "call", grpc_php_wrap_call(call, server->queue, + true)); + add_property_string(result, "method", details.method, true); + add_property_string(result, "host", details.host, true); + add_property_zval(result, "absolute_deadline", + grpc_php_wrap_timeval(details.deadline)); + add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata)); +cleanup: + grpc_call_details_destroy(&details); + grpc_metadata_array_destroy(&metadata); + RETURN_DESTROY_ZVAL(result); } /** @@ -168,7 +200,7 @@ PHP_METHOD(Server, add_secure_http2_port) { int addr_len; zval *creds_obj; /* "sO" == 1 string, 1 object */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len, + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO", &addr, &addr_len, &creds_obj, grpc_ce_server_credentials) == FAILURE) { zend_throw_exception( diff --git a/src/php/ext/grpc/server.h b/src/php/ext/grpc/server.h index b55689c5816..ebb8d25ae1a 100755 --- a/src/php/ext/grpc/server.h +++ b/src/php/ext/grpc/server.h @@ -53,6 +53,7 @@ typedef struct wrapped_grpc_server { zend_object std; grpc_server *wrapped; + grpc_completion_queue *queue; } wrapped_grpc_server; /* Initializes the Server class */ diff --git a/src/php/lib/Grpc/ActiveCall.php b/src/php/lib/Grpc/ActiveCall.php index f0d0d555825..af4dca50d76 100755 --- a/src/php/lib/Grpc/ActiveCall.php +++ b/src/php/lib/Grpc/ActiveCall.php @@ -38,9 +38,7 @@ require_once realpath(dirname(__FILE__) . '/../autoload.php'); * Represents an active call that allows sending and recieving binary data */ class ActiveCall { - private $completion_queue; private $call; - private $flags; private $metadata; /** @@ -48,24 +46,15 @@ class ActiveCall { * @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(); + $metadata = array()) { $this->call = new Call($channel, $method, Timeval::inf_future()); - $this->call->add_metadata($metadata, 0); - $this->flags = $flags; - // Invoke the call. - $this->call->invoke($this->completion_queue, - CLIENT_METADATA_READ, - FINISHED, 0); - $metadata_event = $this->completion_queue->pluck(CLIENT_METADATA_READ, - Timeval::inf_future()); - $this->metadata = $metadata_event->data; + $event = $this->call->start_batch([OP_SEND_INITIAL_METADATA => $metadata]); + + $this->metadata = $event->metadata; } /** @@ -87,8 +76,7 @@ class ActiveCall { * @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()); + $read_event = $this->call->start_batch([OP_RECV_MESSAGE => true]); return $read_event->data; } @@ -98,16 +86,14 @@ class ActiveCall { * @param ByteBuffer $data The data to write */ public function write($data) { - $this->call->start_write($data, WRITE_ACCEPTED, $this->flags); - $this->completion_queue->pluck(WRITE_ACCEPTED, Timeval::inf_future()); + $this->call->start_batch([OP_SEND_MESSAGE => $data]); } /** * 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()); + $this->call->start_batch([OP_SEND_CLOSE_FROM_CLIENT => true]); } /** @@ -116,8 +102,7 @@ class ActiveCall { * and array $metadata members */ public function getStatus() { - $status_event = $this->completion_queue->pluck(FINISHED, - Timeval::inf_future()); + $status_event = $this->call->start_batch([RECV_STATUS_ON_CLIENT => true]); return $status_event->data; } } diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php index 8bb0927f212..d361ce0030d 100755 --- a/src/php/tests/unit_tests/CallTest.php +++ b/src/php/tests/unit_tests/CallTest.php @@ -36,65 +36,47 @@ class CallTest extends PHPUnit_Framework_TestCase{ static $port; public static function setUpBeforeClass() { - $cq = new Grpc\CompletionQueue(); - self::$server = new Grpc\Server($cq, []); + self::$server = new Grpc\Server([]); self::$port = self::$server->add_http2_port('0.0.0.0:0'); } public function setUp() { - $this->cq = new Grpc\CompletionQueue(); $this->channel = new Grpc\Channel('localhost:' . self::$port, []); $this->call = new Grpc\Call($this->channel, '/foo', Grpc\Timeval::inf_future()); } - /** - * @expectedException LogicException - * @expectedExceptionCode Grpc\CALL_ERROR_INVALID_FLAGS - * @expectedExceptionMessage invoke - */ - public function testInvokeRejectsBadFlags() { - $this->call->invoke($this->cq, 0, 0, 0xDEADBEEF); - } - - /** - * @expectedException LogicException - * @expectedExceptionCode Grpc\CALL_ERROR_NOT_ON_CLIENT - * @expectedExceptionMessage server_accept - */ - public function testServerAcceptFailsCorrectly() { - $this->call->server_accept($this->cq, 0); - } - - /* 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); + $batch = [ + Grpc\OP_SEND_INITIAL_METADATA => [] + ]; + $result = $this->call->start_batch($batch); + $this->assertTrue($result->send_metadata); } public function testAddSingleMetadata() { - $this->call->add_metadata(['key' => ['value']], 0); - /* Dummy assert: Checks that the previous call completed without error */ - $this->assertTrue(true); + $batch = [ + Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value']] + ]; + $result = $this->call->start_batch($batch); + $this->assertTrue($result->send_metadata); } public function testAddMultiValueMetadata() { - $this->call->add_metadata(['key' => ['value1', 'value2']], 0); - /* Dummy assert: Checks that the previous call completed without error */ - $this->assertTrue(true); + $batch = [ + Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value1', 'value2']] + ]; + $result = $this->call->start_batch($batch); + $this->assertTrue($result->send_metadata); } 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); + $batch = [ + Grpc\OP_SEND_INITIAL_METADATA => ['key1' => ['value1'], + 'key2' => ['value2', 'value3']] + ]; + $result = $this->call->start_batch($batch); + $this->assertTrue($result->send_metadata); } } diff --git a/src/php/tests/unit_tests/CompletionQueueTest.php b/src/php/tests/unit_tests/CompletionQueueTest.php deleted file mode 100755 index 76ee61dfe8e..00000000000 --- a/src/php/tests/unit_tests/CompletionQueueTest.php +++ /dev/null @@ -1,46 +0,0 @@ -next(Grpc\Timeval::zero()); - $this->assertNull($event); - } - - public function testPluckReturnsNullWithNoCall() { - $cq = new Grpc\CompletionQueue(); - $event = $cq->pluck(0, Grpc\Timeval::zero()); - $this->assertNull($event); - } -} diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php index 0cbc506c8e4..3e165b7213d 100755 --- a/src/php/tests/unit_tests/EndToEndTest.php +++ b/src/php/tests/unit_tests/EndToEndTest.php @@ -33,18 +33,15 @@ */ 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 = new Grpc\Server([]); $port = $this->server->add_http2_port('0.0.0.0:0'); $this->channel = new Grpc\Channel('localhost:' . $port, []); + $this->server->start(); } public function tearDown() { unset($this->channel); unset($this->server); - unset($this->client_queue); - unset($this->server_queue); } public function testSimpleRequestBody() { @@ -53,55 +50,45 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{ $call = new Grpc\Call($this->channel, 'dummy_method', $deadline); - $tag = 1; - $call->invoke($this->client_queue, $tag, $tag); - $server_tag = 2; - - $call->writes_done($tag); - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type); - $this->assertSame(Grpc\OP_OK, $event->data); - - // check that a server rpc new was received - $this->server->start(); - $this->server->request_call($server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type); - $server_call = $event->call; - $this->assertNotNull($server_call); - $server_call->server_accept($this->server_queue, $server_tag); - - $server_call->server_end_initial_metadata(); + $event = $call->start_batch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true + ]); - // the server sends the status - $server_call->start_write_status(Grpc\STATUS_OK, $status_text, $server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type); - $this->assertSame(Grpc\OP_OK, $event->data); + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); - // the client gets CLIENT_METADATA_READ - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type); + $event = $this->server->request_call(); + $this->assertSame('dummy_method', $event->method); + $this->assertSame([], $event->metadata); + $server_call = $event->call; - // the client gets FINISHED - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISHED, $event->type); - $status = $event->data; + $event = $server_call->start_batch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text + ], + Grpc\OP_RECV_CLOSE_ON_SERVER => true + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_status); + $this->assertFalse($event->cancelled); + + $event = $call->start_batch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true + ]); + + $this->assertSame([], $event->metadata); + $status = $event->status; + $this->assertSame([], $status->metadata); $this->assertSame(Grpc\STATUS_OK, $status->code); $this->assertSame($status_text, $status->details); - // and the server gets FINISHED - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISHED, $event->type); - $status = $event->data; - unset($call); unset($server_call); } @@ -115,79 +102,52 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{ $call = new Grpc\Call($this->channel, 'dummy_method', $deadline); - $tag = 1; - $call->invoke($this->client_queue, $tag, $tag); - $server_tag = 2; + $event = $call->start_batch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, + Grpc\OP_SEND_MESSAGE => $req_text + ]); - // the client writes - $call->start_write($req_text, $tag); - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type); + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); + $this->assertTrue($event->send_message); - // check that a server rpc new was received - $this->server->start(); - $this->server->request_call($server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type); + $event = $this->server->request_call(); + $this->assertSame('dummy_method', $event->method); $server_call = $event->call; - $this->assertNotNull($server_call); - $server_call->server_accept($this->server_queue, $server_tag); - - $server_call->server_end_initial_metadata(); - - // start the server read - $server_call->start_read($server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\READ, $event->type); - $this->assertSame($req_text, $event->data); - - // the server replies - $server_call->start_write($reply_text, $server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type); - - // the client reads the metadata - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type); - - // the client reads the reply - $call->start_read($tag); - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\READ, $event->type); - $this->assertSame($reply_text, $event->data); - - // the client sends writes done - $call->writes_done($tag); - $event = $this->client_queue->next($deadline); - $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type); - $this->assertSame(Grpc\OP_OK, $event->data); - - // the server sends the status - $server_call->start_write_status(GRPC\STATUS_OK, $status_text, $server_tag); - $event = $this->server_queue->next($deadline); - $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type); - $this->assertSame(Grpc\OP_OK, $event->data); - - // the client gets FINISHED - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISHED, $event->type); - $status = $event->data; + + $event = $server_call->start_batch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_MESSAGE => $reply_text, + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text + ], + Grpc\OP_RECV_MESSAGE => true, + Grpc\OP_RECV_CLOSE_ON_SERVER => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_status); + $this->assertTrue($event->send_message); + $this->assertFalse($event->cancelled); + $this->assertSame($req_text, $event->message); + + $event = $call->start_batch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_MESSAGE => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true, + ]); + + $this->assertSame([], $event->metadata); + $this->assertSame($reply_text, $event->message); + $status = $event->status; + $this->assertSame([], $status->metadata); $this->assertSame(Grpc\STATUS_OK, $status->code); $this->assertSame($status_text, $status->details); - // and the server gets FINISHED - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISHED, $event->type); - unset($call); unset($server_call); } diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php index 896afeac49a..2d62fe9d5e6 100755 --- a/src/php/tests/unit_tests/SecureEndToEndTest.php +++ b/src/php/tests/unit_tests/SecureEndToEndTest.php @@ -33,17 +33,16 @@ */ 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); + $this->server = new Grpc\Server(); $port = $this->server->add_secure_http2_port('0.0.0.0:0', $server_credentials); + $this->server->start(); $this->channel = new Grpc\Channel( 'localhost:' . $port, [ @@ -55,70 +54,58 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{ 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; - $call->invoke($this->client_queue, $tag, $tag); - $server_tag = 2; - - $call->writes_done($tag); - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type); - $this->assertSame(Grpc\OP_OK, $event->data); - - // check that a server rpc new was received - $this->server->request_call($server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type); + + $event = $call->start_batch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); + + $event = $this->server->request_call(); + $this->assertSame('dummy_method', $event->method); + $this->assertSame([], $event->metadata); $server_call = $event->call; - $this->assertNotNull($server_call); - $server_call->server_accept($this->server_queue, $server_tag); - - $server_call->server_end_initial_metadata(); - - // the server sends the status - $server_call->start_write_status(Grpc\STATUS_OK, $status_text, $server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type); - $this->assertSame(Grpc\OP_OK, $event->data); - - // the client gets CLIENT_METADATA_READ - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type); - - // the client gets FINISHED - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISHED, $event->type); - $status = $event->data; + + $event = $server_call->start_batch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text + ], + Grpc\OP_RECV_CLOSE_ON_SERVER => true + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_status); + $this->assertFalse($event->cancelled); + + $event = $call->start_batch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true + ]); + + $this->assertSame([], $event->metadata); + $status = $event->status; + $this->assertSame([], $status->metadata); $this->assertSame(Grpc\STATUS_OK, $status->code); $this->assertSame($status_text, $status->details); - // and the server gets FINISHED - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISHED, $event->type); - $status = $event->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'; @@ -127,78 +114,52 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{ $call = new Grpc\Call($this->channel, 'dummy_method', $deadline); - $tag = 1; - $call->invoke($this->client_queue, $tag, $tag); - - $server_tag = 2; - - // the client writes - $call->start_write($req_text, $tag); - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type); - - // check that a server rpc new was received - $this->server->request_call($server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type); + + $event = $call->start_batch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, + Grpc\OP_SEND_MESSAGE => $req_text + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_close); + $this->assertTrue($event->send_message); + + $event = $this->server->request_call(); + $this->assertSame('dummy_method', $event->method); $server_call = $event->call; - $this->assertNotNull($server_call); - $server_call->server_accept($this->server_queue, $server_tag); - - $server_call->server_end_initial_metadata(); - - // start the server read - $server_call->start_read($server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\READ, $event->type); - $this->assertSame($req_text, $event->data); - - // the server replies - $server_call->start_write($reply_text, $server_tag); - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type); - - // the client reads the metadata - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type); - - // the client reads the reply - $call->start_read($tag); - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\READ, $event->type); - $this->assertSame($reply_text, $event->data); - - // the client sends writes done - $call->writes_done($tag); - $event = $this->client_queue->next($deadline); - $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type); - $this->assertSame(Grpc\OP_OK, $event->data); - - // the server sends the status - $server_call->start_write_status(GRPC\STATUS_OK, $status_text, $server_tag); - $event = $this->server_queue->next($deadline); - $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type); - $this->assertSame(Grpc\OP_OK, $event->data); - - // the client gets FINISHED - $event = $this->client_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISHED, $event->type); - $status = $event->data; + + $event = $server_call->start_batch([ + Grpc\OP_SEND_INITIAL_METADATA => [], + Grpc\OP_SEND_MESSAGE => $reply_text, + Grpc\OP_SEND_STATUS_FROM_SERVER => [ + 'metadata' => [], + 'code' => Grpc\STATUS_OK, + 'details' => $status_text + ], + Grpc\OP_RECV_MESSAGE => true, + Grpc\OP_RECV_CLOSE_ON_SERVER => true, + ]); + + $this->assertTrue($event->send_metadata); + $this->assertTrue($event->send_status); + $this->assertTrue($event->send_message); + $this->assertFalse($event->cancelled); + $this->assertSame($req_text, $event->message); + + $event = $call->start_batch([ + Grpc\OP_RECV_INITIAL_METADATA => true, + Grpc\OP_RECV_MESSAGE => true, + Grpc\OP_RECV_STATUS_ON_CLIENT => true, + ]); + + $this->assertSame([], $event->metadata); + $this->assertSame($reply_text, $event->message); + $status = $event->status; + $this->assertSame([], $status->metadata); $this->assertSame(Grpc\STATUS_OK, $status->code); $this->assertSame($status_text, $status->details); - // and the server gets FINISHED - $event = $this->server_queue->next($deadline); - $this->assertNotNull($event); - $this->assertSame(Grpc\FINISHED, $event->type); - unset($call); unset($server_call); } diff --git a/src/ruby/Rakefile b/src/ruby/Rakefile index b27305d16c3..afb354e9228 100755 --- a/src/ruby/Rakefile +++ b/src/ruby/Rakefile @@ -2,14 +2,17 @@ require 'rake/extensiontask' require 'rspec/core/rake_task' require 'rubocop/rake_task' +require 'bundler/gem_tasks' -desc 'Run Rubocop to check for style violations' +# Add rubocop style checking tasks RuboCop::RakeTask.new +# Add the extension compiler task Rake::ExtensionTask.new 'grpc' do |ext| ext.lib_dir = File.join('lib', 'grpc') end +# Define the test suites SPEC_SUITES = [ { id: :wrapper, title: 'wrapper layer', files: %w(spec/*.rb) }, { id: :idiomatic, title: 'idiomatic layer', dir: %w(spec/generic), @@ -19,36 +22,34 @@ SPEC_SUITES = [ { id: :server, title: 'rpc server thread tests', dir: %w(spec/generic), tag: 'server' } ] +namespace :suite do + SPEC_SUITES.each do |suite| + desc "Run all specs in the #{suite[:title]} spec suite" + RSpec::Core::RakeTask.new(suite[:id]) do |t| + spec_files = [] + suite[:files].each { |f| spec_files += Dir[f] } if suite[:files] + + if suite[:dir] + suite[:dir].each { |f| spec_files += Dir["#{f}/**/*_spec.rb"] } + end + helper = 'spec/spec_helper.rb' + spec_files << helper unless spec_files.include?(helper) -desc 'Run all RSpec tests' -namespace :spec do - namespace :suite do - SPEC_SUITES.each do |suite| - desc "Run all specs in #{suite[:title]} spec suite" - RSpec::Core::RakeTask.new(suite[:id]) do |t| - spec_files = [] - suite[:files].each { |f| spec_files += Dir[f] } if suite[:files] - - if suite[:dirs] - suite[:dirs].each { |f| spec_files += Dir["#{f}/**/*_spec.rb"] } - end - - t.pattern = spec_files - t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag] - if suite[:tags] - t.rspec_opts = suite[:tags].map { |x| "--tag #{x}" }.join(' ') - end + t.pattern = spec_files + t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag] + if suite[:tags] + t.rspec_opts = suite[:tags].map { |x| "--tag #{x}" }.join(' ') end end end end -desc 'Compiles the extension then runs all the tests' -task :all +# Define dependencies between the suites. +task 'suite:wrapper' => [:compile, :rubocop] +task 'suite:idiomatic' => 'suite:wrapper' +task 'suite:bidi' => 'suite:wrapper' +task 'suite:server' => 'suite:wrapper' +desc 'Compiles the gRPC extension then runs all the tests' +task all: ['suite:idiomatic', 'suite:bidi', 'suite:server'] task default: :all -task 'spec:suite:wrapper' => [:compile, :rubocop] -task 'spec:suite:idiomatic' => 'spec:suite:wrapper' -task 'spec:suite:bidi' => 'spec:suite:wrapper' -task 'spec:suite:server' => 'spec:suite:wrapper' -task all: ['spec:suite:idiomatic', 'spec:suite:bidi', 'spec:suite:server'] diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 73f2d37e305..0c98fc40d91 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -384,13 +384,7 @@ describe 'ClientStub' do th.join end - # disabled because an unresolved wire-protocol implementation feature - # - # - servers should be able initiate messaging, however, as it stand - # servers don't know if all the client metadata has been sent until - # they receive a message from the client. Without receiving all the - # metadata, the server does not accept the call, so this test hangs. - xit 'supports a server-initiated ping pong', bidi: true do + it 'supports a server-initiated ping pong', bidi: true do server_port = create_test_server host = "localhost:#{server_port}" th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false)