Example #1
0
/* 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;
}
Example #2
0
/* 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;
}
Example #3
0
/*
  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;
}
Example #4
0
/*
  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;
}
Example #5
0
/*
  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;
}
Example #6
0
/* 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;
}
Example #7
0
/* 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;
}
Example #8
0
/* 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;
}