Module: Magicprotorb::ServiceBuilder

Defined in:
lib/magicprotorb/service_builder.rb

Overview

Synthesizes gRPC Service/Stub classes from the service descriptors in a FileDescriptorProto — the runtime equivalent of a generated ‘*_services_pb.rb`. Requires the optional `grpc` gem, loaded lazily so that message-only users never pay for it.

Class Method Summary collapse

Class Method Details

.build(file) ⇒ Object



11
12
13
14
15
# File 'lib/magicprotorb/service_builder.rb', line 11

def build(file)
  require "grpc"
  package = file.package
  file.service.each { |service| build_service(package, service) }
end

.build_service(package, service) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/magicprotorb/service_builder.rb', line 17

def build_service(package, service)
  # Use to_h to read the repeated `method` field: ServiceDescriptorProto#method
  # collides with Ruby's Object#method.
  descriptor = service.to_h
  name = descriptor[:name]
  full_name = qualify(package, name)

  service_class = define_service_class(full_name, descriptor[:method] || [])

  mod = Registrar.ensure_module(Naming.package_modules(package) + [Naming.constant_name(name)])
  mod.const_set(:Service, service_class) unless mod.const_defined?(:Service, false)
  mod.const_set(:Stub, service_class.rpc_stub_class) unless mod.const_defined?(:Stub, false)
end

.define_service_class(full_name, methods) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/magicprotorb/service_builder.rb', line 31

def define_service_class(full_name, methods)
  pool = Google::Protobuf::DescriptorPool.generated_pool

  Class.new do
    include GRPC::GenericService

    self.marshal_class_method = :encode
    self.unmarshal_class_method = :decode
    self.service_name = full_name

    methods.each do |method|
      request = pool.lookup(ServiceBuilder.strip(method[:input_type])).msgclass
      response = pool.lookup(ServiceBuilder.strip(method[:output_type])).msgclass
      # stream(...) is provided by GenericService's DSL inside the class body.
      request = stream(request) if method[:client_streaming]
      response = stream(response) if method[:server_streaming]
      rpc method[:name].to_sym, request, response
    end
  end
end

.qualify(package, name) ⇒ Object



52
53
54
# File 'lib/magicprotorb/service_builder.rb', line 52

def qualify(package, name)
  package.nil? || package.empty? ? name : "#{package}.#{name}"
end

.strip(type_name) ⇒ Object

Descriptor type references are fully-qualified with a leading dot (“.greet.HelloRequest”); the pool is keyed without it.



58
59
60
# File 'lib/magicprotorb/service_builder.rb', line 58

def strip(type_name)
  type_name.sub(/\A\./, "")
end