Module: GRPC::GenericService::Dsl

Defined in:
src/ruby/lib/grpc/generic/service.rb

Overview

Provides a simple DSL to describe RPC services.

E.g, a Maths service that uses the serializable messages DivArgs, DivReply and Num might define its endpoint uses the following way:

rpc :div DivArgs, DivReply # single request, single response rpc :sum stream(Num), Num # streamed input, single response rpc :fib FibArgs, stream(Num) # single request, streamed response rpc :div_many stream(DivArgs), stream(DivReply)

# streamed req and resp

Each 'rpc' adds an RpcDesc to classes including this module, and #assert_rpc_descs_have_methods is used to ensure the including class provides methods with signatures that support all the descriptors.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#marshal_class_methodObject

the name of the instance method used to marshal events to a byte stream.


124
125
126
# File 'src/ruby/lib/grpc/generic/service.rb', line 124

def marshal_class_method
  @marshal_class_method ||= :marshal
end

#service_nameObject

This allows configuration of the service name.


92
93
94
# File 'src/ruby/lib/grpc/generic/service.rb', line 92

def service_name
  @service_name
end

#unmarshal_class_methodObject

the name of the class method used to unmarshal from a byte stream.


129
130
131
# File 'src/ruby/lib/grpc/generic/service.rb', line 129

def unmarshal_class_method
  @unmarshal_class_method ||= :unmarshal
end

Instance Method Details

#assert_can_marshal(cls) ⇒ Object


133
134
135
136
137
138
139
140
141
142
# File 'src/ruby/lib/grpc/generic/service.rb', line 133

def assert_can_marshal(cls)
  cls = cls.type if cls.is_a? RpcDesc::Stream
  mth = unmarshal_class_method
  unless cls.methods.include? mth
    fail(ArgumentError, "#{cls} needs #{cls}.#{mth}")
  end
  mth = marshal_class_method
  return if cls.methods.include? mth
  fail(ArgumentError, "#{cls} needs #{cls}.#{mth}")
end

#assert_rpc_descs_have_methodsObject

Asserts that the appropriate methods are defined for each added rpc spec. Is intended to aid verifying that server classes are correctly implemented.


206
207
208
209
210
211
212
213
214
# File 'src/ruby/lib/grpc/generic/service.rb', line 206

def assert_rpc_descs_have_methods
  rpc_descs.each_pair do |m, spec|
    mth_name = GenericService.underscore(m.to_s).to_sym
    unless instance_methods.include?(mth_name)
      fail "#{self} does not provide instance method '#{mth_name}'"
    end
    spec.assert_arity_matches(instance_method(mth_name))
  end
end

#inherited(subclass) ⇒ Object


115
116
117
118
119
120
# File 'src/ruby/lib/grpc/generic/service.rb', line 115

def inherited(subclass)
  # Each subclass should have a distinct class variable with its own
  # rpc_descs
  subclass.rpc_descs.merge!(rpc_descs)
  subclass.service_name = service_name
end

#rpc(name, input, output) ⇒ Object

Adds an RPC spec.

Takes the RPC name and the classes representing the types to be serialized, and adds them to the including classes rpc_desc hash.

input and output should both have the methods #marshal and #unmarshal that are responsible for writing and reading an object instance from a byte buffer respectively.

Parameters:

  • name (String)

    the name of the rpc

  • input (Object)

    the input parameter's class

  • output (Object)

    the output parameter's class


106
107
108
109
110
111
112
113
# File 'src/ruby/lib/grpc/generic/service.rb', line 106

def rpc(name, input, output)
  fail(DuplicateRpcName, name) if rpc_descs.key? name
  assert_can_marshal(input)
  assert_can_marshal(output)
  rpc_descs[name] = RpcDesc.new(name, input, output,
                                marshal_class_method,
                                unmarshal_class_method)
end

#rpc_descsObject

the RpcDescs defined for this GenericService, keyed by name.


152
153
154
# File 'src/ruby/lib/grpc/generic/service.rb', line 152

def rpc_descs
  @rpc_descs ||= {}
end

#rpc_stub_classObject

Creates a rpc client class with methods for accessing the methods currently in rpc_descs.


158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'src/ruby/lib/grpc/generic/service.rb', line 158

def rpc_stub_class
  descs = rpc_descs
  route_prefix = service_name
  Class.new(ClientStub) do
    # @param host [String] the host the stub connects to
    # @param creds [Core::ChannelCredentials|Symbol] The channel
    #     credentials to use, or :this_channel_is_insecure otherwise
    # @param kw [KeywordArgs] the channel arguments, plus any optional
    #                         args for configuring the client's channel
    def initialize(host, creds, **kw)
      super(host, Core::CompletionQueue.new, creds, **kw)
    end

    # Used define_method to add a method for each rpc_desc.  Each method
    # calls the base class method for the given descriptor.
    descs.each_pair do |name, desc|
      mth_name = GenericService.underscore(name.to_s).to_sym
      marshal = desc.marshal_proc
      unmarshal = desc.unmarshal_proc(:output)
      route = "/#{route_prefix}/#{name}"
      if desc.request_response?
        define_method(mth_name) do |req, **kw|
          GRPC.logger.debug("calling #{@host}:#{route}")
          request_response(route, req, marshal, unmarshal, **kw)
        end
      elsif desc.client_streamer?
        define_method(mth_name) do |reqs, **kw|
          GRPC.logger.debug("calling #{@host}:#{route}")
          client_streamer(route, reqs, marshal, unmarshal, **kw)
        end
      elsif desc.server_streamer?
        define_method(mth_name) do |req, **kw, &blk|
          GRPC.logger.debug("calling #{@host}:#{route}")
          server_streamer(route, req, marshal, unmarshal, **kw, &blk)
        end
      else  # is a bidi_stream
        define_method(mth_name) do |reqs, **kw, &blk|
          GRPC.logger.debug("calling #{@host}:#{route}")
          bidi_streamer(route, reqs, marshal, unmarshal, **kw, &blk)
        end
      end
    end
  end
end

#stream(cls) ⇒ Object

Returns cls wrapped in a RpcDesc::Stream

Parameters:

  • cls (Class)

    the class of a serializable type

Returns:

  • cls wrapped in a RpcDesc::Stream


146
147
148
149
# File 'src/ruby/lib/grpc/generic/service.rb', line 146

def stream(cls)
  assert_can_marshal(cls)
  RpcDesc::Stream.new(cls)
end