/* call-seq: cq = CompletionQueue.new tag = Object.new timeout = 10 server.request_call(cqueue, tag, timeout) Requests notification of a new call on a server. */ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, VALUE tag_new, VALUE timeout) { grpc_rb_server *s = NULL; grpc_call *call = NULL; grpc_event ev; grpc_call_error err; request_call_stack st; VALUE result; gpr_timespec deadline; TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "destroyed!"); return Qnil; } else { grpc_request_call_stack_init(&st); /* call grpc_server_request_call, then wait for it to complete using * pluck_event */ err = grpc_server_request_call( s->wrapped, &call, &st.details, &st.md_ary, grpc_rb_get_wrapped_completion_queue(cqueue), grpc_rb_get_wrapped_completion_queue(cqueue), ROBJECT(tag_new)); if (err != GRPC_CALL_OK) { grpc_request_call_stack_cleanup(&st); rb_raise(grpc_rb_eCallError, "grpc_server_request_call failed: %s (code=%d)", grpc_call_error_detail_of(err), err); return Qnil; } ev = grpc_rb_completion_queue_pluck_event(cqueue, tag_new, timeout); if (ev.type == GRPC_QUEUE_TIMEOUT) { grpc_request_call_stack_cleanup(&st); return Qnil; } if (!ev.success) { grpc_request_call_stack_cleanup(&st); rb_raise(grpc_rb_eCallError, "request_call completion failed"); return Qnil; } /* build the NewServerRpc struct result */ deadline = gpr_convert_clock_type(st.details.deadline, GPR_CLOCK_REALTIME); result = rb_struct_new( grpc_rb_sNewServerRpc, rb_str_new2(st.details.method), rb_str_new2(st.details.host), rb_funcall(rb_cTime, id_at, 2, INT2NUM(deadline.tv_sec), INT2NUM(deadline.tv_nsec)), grpc_rb_md_ary_to_h(&st.md_ary), grpc_rb_wrap_call(call), NULL); grpc_request_call_stack_cleanup(&st); return result; } return Qnil; }
/* Watch for a change in connectivity state. Once the channel connectivity state is different from the last observed state, tag will be enqueued on cq with success=1 If deadline expires BEFORE the state is changed, tag will be enqueued on the completion queue with success=0 */ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, VALUE cqueue, VALUE deadline, VALUE tag) { grpc_rb_channel *wrapper = NULL; grpc_channel *ch = NULL; grpc_completion_queue *cq = NULL; cq = grpc_rb_get_wrapped_completion_queue(cqueue); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } grpc_channel_watch_connectivity_state( ch, (grpc_connectivity_state)NUM2LONG(last_state), grpc_rb_time_timeval(deadline, /* absolute time */ 0), cq, ROBJECT(tag)); return Qnil; }
/* call-seq: cq = CompletionQueue.new server = Server.new(cq, {'arg1': 'value1'}) ... // do stuff with server ... ... // to shutdown the server server.destroy(cq) ... // to shutdown the server with a timeout server.destroy(cq, timeout) Destroys server instances. */ static VALUE grpc_rb_server_destroy(int argc, VALUE *argv, VALUE self) { VALUE cqueue = Qnil; VALUE timeout = Qnil; grpc_completion_queue *cq = NULL; grpc_event ev; grpc_rb_server *s = NULL; /* "11" == 1 mandatory args, 1 (timeout) is optional */ rb_scan_args(argc, argv, "11", &cqueue, &timeout); cq = grpc_rb_get_wrapped_completion_queue(cqueue); TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped != NULL) { grpc_server_shutdown_and_notify(s->wrapped, cq, NULL); ev = grpc_rb_completion_queue_pluck_event(cqueue, Qnil, timeout); if (!ev.success) { rb_warn("server shutdown failed, cancelling the calls, objects may leak"); grpc_server_cancel_all_calls(s->wrapped); return Qfalse; } grpc_server_destroy(s->wrapped); s->wrapped = NULL; } return Qtrue; }
/* call-seq: cq = CompletionQueue.new server = Server.new(cq, {'arg1': 'value1'}) Initializes server instances. */ static VALUE grpc_rb_server_init(VALUE self, VALUE cqueue, VALUE channel_args) { grpc_completion_queue *cq = NULL; grpc_rb_server *wrapper = NULL; grpc_server *srv = NULL; grpc_channel_args args; MEMZERO(&args, grpc_channel_args, 1); cq = grpc_rb_get_wrapped_completion_queue(cqueue); TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, wrapper); grpc_rb_hash_convert_to_channel_args(channel_args, &args); srv = grpc_server_create(&args, NULL); if (args.args != NULL) { xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ } if (srv == NULL) { rb_raise(rb_eRuntimeError, "could not create a gRPC server, not sure why"); } grpc_server_register_completion_queue(srv, cq, NULL); wrapper->wrapped = srv; /* Add the cq as the server's mark object. This ensures the ruby cq can't be GCed before the server */ wrapper->mark = cqueue; return self; }
/* call-seq: call.invoke(completion_queue, tag, flags=nil) Invoke the RPC. Starts sending metadata and request headers on the wire. flags is a bit-field combination of the write flags defined above. REQUIRES: Can be called at most once per call. Can only be called on the client. Produces a GRPC_INVOKE_ACCEPTED event on completion. */ static VALUE grpc_rb_call_invoke(int argc, VALUE *argv, VALUE self) { VALUE cqueue = Qnil; VALUE metadata_read_tag = Qnil; VALUE finished_tag = Qnil; VALUE flags = Qnil; grpc_call *call = NULL; grpc_completion_queue *cq = NULL; grpc_call_error err; /* "31" == 3 mandatory args, 1 (flags) is optional */ rb_scan_args(argc, argv, "31", &cqueue, &metadata_read_tag, &finished_tag, &flags); if (NIL_P(flags)) { flags = UINT2NUM(0); /* Default to no flags */ } cq = grpc_rb_get_wrapped_completion_queue(cqueue); Data_Get_Struct(self, grpc_call, call); err = grpc_call_invoke_old(call, cq, ROBJECT(metadata_read_tag), ROBJECT(finished_tag), NUM2UINT(flags)); if (err != GRPC_CALL_OK) { rb_raise(rb_eCallError, "invoke failed: %s (code=%d)", grpc_call_error_detail_of(err), err); } /* Add the completion queue as an instance attribute, prevents it from being * GCed until this call object is GCed */ rb_ivar_set(self, id_cq, cqueue); return Qnil; }
/* call-seq: cq = CompletionQueue.new tag = Object.new timeout = 10 server.request_call(cqueue, tag, timeout) Requests notification of a new call on a server. */ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, VALUE tag_new, VALUE timeout) { grpc_rb_server *s = NULL; grpc_call *call = NULL; grpc_event *ev = NULL; grpc_call_error err; request_call_stack st; VALUE result; Data_Get_Struct(self, grpc_rb_server, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } else { grpc_request_call_stack_init(&st); /* call grpc_server_request_call, then wait for it to complete using * pluck_event */ err = grpc_server_request_call( s->wrapped, &call, &st.details, &st.md_ary, grpc_rb_get_wrapped_completion_queue(cqueue), ROBJECT(tag_new)); if (err != GRPC_CALL_OK) { grpc_request_call_stack_cleanup(&st); rb_raise(grpc_rb_eCallError, "grpc_server_request_call failed: %s (code=%d)", grpc_call_error_detail_of(err), err); return Qnil; } ev = grpc_rb_completion_queue_pluck_event(cqueue, tag_new, timeout); if (ev == NULL) { grpc_request_call_stack_cleanup(&st); return Qnil; } if (ev->data.op_complete != GRPC_OP_OK) { grpc_request_call_stack_cleanup(&st); grpc_event_finish(ev); rb_raise(grpc_rb_eCallError, "request_call completion failed: (code=%d)", ev->data.op_complete); return Qnil; } /* build the NewServerRpc struct result */ result = rb_struct_new( grpc_rb_sNewServerRpc, rb_str_new2(st.details.method), rb_str_new2(st.details.host), rb_funcall(rb_cTime, id_at, 2, INT2NUM(st.details.deadline.tv_sec), INT2NUM(st.details.deadline.tv_nsec)), grpc_rb_md_ary_to_h(&st.md_ary), grpc_rb_wrap_call(call), NULL); grpc_event_finish(ev); grpc_request_call_stack_cleanup(&st); return result; } return Qnil; }
/* Create a call given a grpc_channel, in order to call method. The request is not sent until grpc_call_invoke is called. */ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE parent, VALUE mask, VALUE method, VALUE host, VALUE deadline) { VALUE res = Qnil; grpc_rb_channel *wrapper = NULL; grpc_call *call = NULL; grpc_call *parent_call = NULL; grpc_channel *ch = NULL; grpc_completion_queue *cq = NULL; int flags = GRPC_PROPAGATE_DEFAULTS; char *method_chars = StringValueCStr(method); char *host_chars = NULL; if (host != Qnil) { host_chars = StringValueCStr(host); } if (mask != Qnil) { flags = NUM2UINT(mask); } if (parent != Qnil) { parent_call = grpc_rb_get_wrapped_call(parent); } cq = grpc_rb_get_wrapped_completion_queue(cqueue); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } call = grpc_channel_create_call(ch, parent_call, flags, cq, method_chars, host_chars, grpc_rb_time_timeval( deadline, /* absolute time */ 0), NULL); if (call == NULL) { rb_raise(rb_eRuntimeError, "cannot create call with method %s", method_chars); return Qnil; } res = grpc_rb_wrap_call(call); /* Make this channel an instance attribute of the call so that it is not GCed * before the call. */ rb_ivar_set(res, id_channel, self); /* Make the completion queue an instance attribute of the call so that it is * not GCed before the call. */ rb_ivar_set(res, id_cqueue, cqueue); return res; }
/* call-seq: call.server_accept(completion_queue, finished_tag) Accept an incoming RPC, binding a completion queue to it. To be called before sending or receiving messages. REQUIRES: Can be called at most once per call. Can only be called on the server. Produces a GRPC_FINISHED event with finished_tag when the call has been completed (there may be other events for the call pending at this time) */ static VALUE grpc_rb_call_server_accept(VALUE self, VALUE cqueue, VALUE finished_tag) { grpc_call *call = NULL; grpc_completion_queue *cq = grpc_rb_get_wrapped_completion_queue(cqueue); grpc_call_error err; Data_Get_Struct(self, grpc_call, call); err = grpc_call_server_accept_old(call, cq, ROBJECT(finished_tag)); if (err != GRPC_CALL_OK) { rb_raise(rb_eCallError, "server_accept failed: %s (code=%d)", grpc_call_error_detail_of(err), err); } /* Add the completion queue as an instance attribute, prevents it from being * GCed until this call object is GCed */ rb_ivar_set(self, id_cq, cqueue); return Qnil; }