grpc_kit 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +22 -6
  3. data/examples/interceptors/client_logging_interceptor.rb +48 -0
  4. data/examples/interceptors/server_logging_interceptor.rb +44 -0
  5. data/examples/routeguide_client.rb +63 -3
  6. data/examples/routeguide_server.rb +86 -3
  7. data/grpc_kit.gemspec +1 -1
  8. data/lib/grpc.rb +1 -0
  9. data/lib/grpc_kit/client.rb +31 -79
  10. data/lib/grpc_kit/errors.rb +18 -8
  11. data/lib/grpc_kit/grpc/dsl.rb +19 -21
  12. data/lib/grpc_kit/grpc/generic_service.rb +1 -1
  13. data/lib/grpc_kit/grpc/interceptor.rb +57 -0
  14. data/lib/grpc_kit/grpc/logger.rb +17 -0
  15. data/lib/grpc_kit/interceptors.rb +11 -0
  16. data/lib/grpc_kit/interceptors/client_streamer.rb +31 -0
  17. data/lib/grpc_kit/interceptors/request_response.rb +70 -0
  18. data/lib/grpc_kit/interceptors/server_streamer.rb +33 -0
  19. data/lib/grpc_kit/interceptors/streaming.rb +70 -0
  20. data/lib/grpc_kit/method_config.rb +34 -0
  21. data/lib/grpc_kit/protobuffer.rb +20 -0
  22. data/lib/grpc_kit/rpc_desc.rb +103 -27
  23. data/lib/grpc_kit/rpcs.rb +11 -0
  24. data/lib/grpc_kit/rpcs/base.rb +30 -0
  25. data/lib/grpc_kit/rpcs/bidi_streamer.rb +18 -0
  26. data/lib/grpc_kit/rpcs/call.rb +27 -0
  27. data/lib/grpc_kit/rpcs/client_streamer.rb +38 -0
  28. data/lib/grpc_kit/rpcs/request_response.rb +50 -0
  29. data/lib/grpc_kit/rpcs/server_streamer.rb +42 -0
  30. data/lib/grpc_kit/server.rb +19 -38
  31. data/lib/grpc_kit/session/buffer.rb +58 -0
  32. data/lib/grpc_kit/session/client.rb +100 -52
  33. data/lib/grpc_kit/session/duration.rb +96 -0
  34. data/lib/grpc_kit/session/headers.rb +65 -0
  35. data/lib/grpc_kit/session/io.rb +56 -0
  36. data/lib/grpc_kit/session/server.rb +107 -68
  37. data/lib/grpc_kit/session/stream.rb +32 -40
  38. data/lib/grpc_kit/stream.rb +71 -0
  39. data/lib/grpc_kit/streams/client.rb +87 -0
  40. data/lib/grpc_kit/streams/packable.rb +60 -0
  41. data/lib/grpc_kit/streams/send_buffer.rb +48 -0
  42. data/lib/grpc_kit/streams/server.rb +36 -0
  43. data/lib/grpc_kit/streams/stream.rb +58 -0
  44. data/lib/grpc_kit/version.rb +1 -1
  45. metadata +32 -5
  46. data/lib/grpc_kit/io/basic.rb +0 -35
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrpcKit
4
+ class ProtoBuffer
5
+ def initialize(encoder:, decoder:, encode_method:, decode_method:)
6
+ @encoder = encoder
7
+ @decoder = decoder
8
+ @encode_method = encode_method
9
+ @decode_method = decode_method
10
+ end
11
+
12
+ def encode(data)
13
+ @encoder.send(@encode_method, data)
14
+ end
15
+
16
+ def decode(data)
17
+ @decoder.send(@decode_method, data)
18
+ end
19
+ end
20
+ end
@@ -1,65 +1,141 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'grpc_kit/grpc/stream'
3
+ require 'grpc_kit/method_config'
4
+ require 'grpc_kit/rpcs'
5
+ require 'grpc_kit/protobuffer'
6
+ require 'grpc_kit/interceptors'
4
7
 
5
8
  module GrpcKit
6
9
  class RpcDesc
7
- def initialize(name:, input:, output:, marshal_method:, unmarshal_method:)
10
+ def initialize(name:, marshal:, unmarshal:, marshal_method:, unmarshal_method:, service_name:)
8
11
  @name = name
9
- @input = input
10
- @output = output
12
+ @marshal = marshal
13
+ @unmarshal = unmarshal
11
14
  @marshal_method = marshal_method
12
15
  @unmarshal_method = unmarshal_method
16
+ @service_name = service_name
13
17
  end
14
18
 
15
- def encode(val)
16
- @output.send(@marshal_method, val)
17
- end
18
-
19
- def decode(val)
20
- @input.send(@unmarshal_method, val)
21
- end
22
-
23
- def encode2(val)
24
- @input.send(@marshal_method, val)
25
- end
19
+ def build_server(handler, interceptors: [])
20
+ inter = interceptors.empty? ? nil : server_interceptor.new(interceptors)
26
21
 
27
- def decode2(val)
28
- @output.send(@unmarshal_method, val)
22
+ config = GrpcKit::MethodConfig.build_for_server(
23
+ path: path,
24
+ ruby_style_method_name: ruby_style_name,
25
+ protobuf: server_protobuf,
26
+ service_name: @server_name,
27
+ method_name: @name,
28
+ interceptor: inter,
29
+ )
30
+ server.new(handler, config)
29
31
  end
30
32
 
31
- def invoke(rpc, val)
32
- args = decode(val)
33
- ret = rpc.send(to_underscore(@name), args, nil) # nil is GRPC::Call object
34
- encode(ret)
33
+ def build_client
34
+ config = GrpcKit::MethodConfig.build_for_client(
35
+ path: path,
36
+ ruby_style_method_name: ruby_style_name,
37
+ protobuf: client_protobuf,
38
+ service_name: @server_name,
39
+ method_name: @name,
40
+ interceptor: client_interceptor.new,
41
+ )
42
+ client.new(config)
35
43
  end
36
44
 
37
45
  def ruby_style_name
38
46
  @ruby_style_name ||= to_underscore(@name).to_sym
39
47
  end
40
48
 
41
- def path(service_name)
42
- "/#{service_name}/#{@name}".to_sym
49
+ def path
50
+ @path ||= "/#{@service_name}/#{@name}"
43
51
  end
44
52
 
45
53
  def request_response?
46
- !@input.is_a?(GrpcKit::GRPC::Stream) && !@output.is_a?(GrpcKit::GRPC::Stream)
54
+ !@marshal.is_a?(GrpcKit::GRPC::Stream) && !@unmarshal.is_a?(GrpcKit::GRPC::Stream)
47
55
  end
48
56
 
49
57
  def client_streamer?
50
- @input.is_a?(GrpcKit::GRPC::Stream) && !@output.is_a?(GrpcKit::GRPC::Stream)
58
+ @marshal.is_a?(GrpcKit::GRPC::Stream) && !@unmarshal.is_a?(GrpcKit::GRPC::Stream)
51
59
  end
52
60
 
53
61
  def server_streamer?
54
- !@input.is_a?(GrpcKit::GRPC::Stream) && @output.is_a?(GrpcKit::GRPC::Stream)
62
+ !@marshal.is_a?(GrpcKit::GRPC::Stream) && @unmarshal.is_a?(GrpcKit::GRPC::Stream)
55
63
  end
56
64
 
57
65
  def bidi_streamer?
58
- @input.is_a?(GrpcKit::GRPC::Stream) && @output.is_a?(GrpcKit::GRPC::Stream)
66
+ @marshal.is_a?(GrpcKit::GRPC::Stream) && @unmarshal.is_a?(GrpcKit::GRPC::Stream)
59
67
  end
60
68
 
61
69
  private
62
70
 
71
+ def server
72
+ @server ||=
73
+ if request_response?
74
+ GrpcKit::Rpcs::Server::RequestResponse
75
+ elsif client_streamer?
76
+ GrpcKit::Rpcs::Server::ClientStreamer
77
+ elsif server_streamer?
78
+ GrpcKit::Rpcs::Server::ServerStreamer
79
+ elsif bidi_streamer?
80
+ GrpcKit::Rpcs::Server::BidiStreamer
81
+ end
82
+ end
83
+
84
+ def client
85
+ @client ||=
86
+ if request_response?
87
+ GrpcKit::Rpcs::Client::RequestResponse
88
+ elsif client_streamer?
89
+ GrpcKit::Rpcs::Client::ClientStreamer
90
+ elsif server_streamer?
91
+ GrpcKit::Rpcs::Client::ServerStreamer
92
+ elsif bidi_streamer?
93
+ GrpcKit::Rpcs::Client::BidiStreamer
94
+ end
95
+ end
96
+
97
+ def server_protobuf
98
+ @server_protobuf ||= ProtoBuffer.new(
99
+ encoder: @unmarshal,
100
+ decoder: @marshal,
101
+ encode_method: @marshal_method,
102
+ decode_method: @unmarshal_method,
103
+ )
104
+ end
105
+
106
+ def client_protobuf
107
+ @client_protobuf ||= ProtoBuffer.new(
108
+ encoder: @marshal,
109
+ decoder: @unmarshal,
110
+ encode_method: @marshal_method,
111
+ decode_method: @unmarshal_method,
112
+ )
113
+ end
114
+
115
+ def server_interceptor
116
+ if request_response?
117
+ GrpcKit::Interceptors::Server::RequestResponse
118
+ elsif client_streamer?
119
+ GrpcKit::Interceptors::Server::ClientStreamer
120
+ elsif server_streamer?
121
+ GrpcKit::Interceptors::Server::ServerStreamer
122
+ elsif bidi_streamer?
123
+ GrpcKit::Interceptors::Server::RequestResponse # TODO
124
+ end
125
+ end
126
+
127
+ def client_interceptor
128
+ if request_response?
129
+ GrpcKit::Interceptors::Client::RequestResponse
130
+ elsif client_streamer?
131
+ GrpcKit::Interceptors::Client::ClientStreamer
132
+ elsif server_streamer?
133
+ GrpcKit::Interceptors::Client::ServerStreamer
134
+ elsif bidi_streamer?
135
+ GrpcKit::Interceptors::Client::RequestResponse # TODO
136
+ end
137
+ end
138
+
63
139
  def to_underscore(val)
64
140
  val
65
141
  .to_s
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs/request_response'
4
+ require 'grpc_kit/rpcs/client_streamer'
5
+ require 'grpc_kit/rpcs/server_streamer'
6
+ require 'grpc_kit/rpcs/bidi_streamer'
7
+
8
+ module GrpcKit
9
+ module Rpcs
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'timeout'
4
+
5
+ require 'grpc_kit/errors'
6
+ require 'grpc_kit/rpcs/call'
7
+ require 'grpc_kit/streams/server'
8
+ require 'grpc_kit/streams/client'
9
+
10
+ module GrpcKit
11
+ module Rpcs
12
+ module Client
13
+ class Base
14
+ attr_reader :config
15
+ def initialize(config)
16
+ @config = config
17
+ end
18
+ end
19
+ end
20
+
21
+ module Server
22
+ class Base
23
+ def initialize(handler, config)
24
+ @handler = handler
25
+ @config = config
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs/base'
4
+
5
+ module GrpcKit
6
+ module Rpcs
7
+ module Client
8
+ class BidiStreamer < Base
9
+ def invoke(session, data, opts = {}); end
10
+ end
11
+ end
12
+
13
+ module Server
14
+ class BidiStreamer < Base
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module GrpcKit
6
+ module Rpcs
7
+ # compatible for grpc gem
8
+ class Call
9
+ extend Forwardable
10
+
11
+ delegate %i[recv send_msg close_and_recv each].freeze => :@stream
12
+
13
+ Name = Struct.new(:name, :receiver)
14
+ Reciver = Struct.new(:class)
15
+ Klass = Struct.new(:service_name)
16
+
17
+ attr_reader :metadata, :method
18
+
19
+ def initialize(metadata, method_name, service_name, stream)
20
+ @metadata = metadata
21
+ klass = Klass.new(service_name)
22
+ @method = Name.new(method_name, Reciver.new(klass))
23
+ @stream = stream
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs/base'
4
+
5
+ module GrpcKit
6
+ module Rpcs
7
+ module Client
8
+ class ClientStreamer < Base
9
+ def invoke(session, _request, authority:, metadata: {}, timeout: nil, **opts)
10
+ cs = GrpcKit::Streams::Client.new(path: @config.path, protobuf: @config.protobuf, session: session, authority: authority)
11
+ call = GrpcKit::Rpcs::Call.new(metadata, @config.method_name, @config.service_name, cs)
12
+ @config.interceptor.intercept(call) do |s|
13
+ s
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ module Server
20
+ class ClientStreamer < Base
21
+ def invoke(stream, session)
22
+ ss = GrpcKit::Streams::Server.new(stream: stream, protobuf: @config.protobuf, session: session)
23
+ call = GrpcKit::Rpcs::Call.new(stream.headers.metadata, @config.method_name, @config.service_name, ss)
24
+
25
+ if @config.interceptor
26
+ @config.interceptor.intercept(call) do |c|
27
+ resp = @handler.send(@config.ruby_style_method_name, c)
28
+ c.send_msg(resp, last: true)
29
+ end
30
+ else
31
+ resp = @handler.send(@config.ruby_style_method_name, call)
32
+ call.send_msg(resp, last: true)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs/base'
4
+
5
+ module GrpcKit
6
+ module Rpcs
7
+ module Client
8
+ class RequestResponse < Base
9
+ def invoke(session, request, authority:, metadata: {}, timeout: nil, **opts)
10
+ cs = GrpcKit::Streams::Client.new(path: @config.path, protobuf: @config.protobuf, session: session, authority: authority)
11
+
12
+ call = GrpcKit::Rpcs::Call.new(metadata, @config.method_name, @config.service_name, cs)
13
+ @config.interceptor.intercept(request, call, metadata) do |r, c, m|
14
+ if timeout
15
+ # XXX: when timeout.to_timeout is 0
16
+ Timeout.timeout(timeout.to_timeout, GrpcKit::Errors::DeadlienExceeded) do
17
+ c.send_msg(r, timeout: timeout.to_s, metadata: m, last: true)
18
+ c.recv(last: true)
19
+ end
20
+ else
21
+ c.send_msg(r, metadata: m, last: true)
22
+ c.recv(last: true)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ module Server
30
+ class RequestResponse < Base
31
+ def invoke(stream, session)
32
+ ss = GrpcKit::Streams::Server.new(stream: stream, protobuf: @config.protobuf, session: session)
33
+ call = GrpcKit::Rpcs::Call.new(stream.headers.metadata, @config.method_name, @config.service_name, ss)
34
+
35
+ request = ss.recv(last: true)
36
+ resp =
37
+ if @config.interceptor
38
+ @config.interceptor.intercept(request, call) do |req, c|
39
+ @handler.send(@config.ruby_style_method_name, req, c)
40
+ end
41
+ else
42
+ @handler.send(@config.ruby_style_method_name, request, call)
43
+ end
44
+
45
+ ss.send_msg(resp, last: true)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs/base'
4
+
5
+ module GrpcKit
6
+ module Rpcs
7
+ module Client
8
+ class ServerStreamer < Base
9
+ def invoke(session, request, authority:, metadata: {}, timeout: nil, **opts)
10
+ cs = GrpcKit::Streams::Client.new(path: @config.path, protobuf: @config.protobuf, session: session, authority: authority)
11
+ call = GrpcKit::Rpcs::Call.new(metadata, @config.method_name, @config.service_name, cs)
12
+
13
+ @config.interceptor.intercept(call) do |c|
14
+ c.send_msg(request, last: true)
15
+ c
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ module Server
22
+ class ServerStreamer < Base
23
+ def invoke(stream, session)
24
+ ss = GrpcKit::Streams::Server.new(stream: stream, protobuf: @config.protobuf, session: session)
25
+ call = GrpcKit::Rpcs::Call.new(stream.headers.metadata, @config.method_name, @config.service_name, ss)
26
+
27
+ if @config.interceptor
28
+ @config.interceptor.intercept(call) do |c|
29
+ request = c.recv(last: true)
30
+ @handler.send(@config.ruby_style_method_name, request, c)
31
+ end
32
+ else
33
+ request = call.recv(last: true)
34
+ @handler.send(@config.ruby_style_method_name, request, call)
35
+ end
36
+
37
+ stream.end_write
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,76 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'grpc_kit/io/basic'
3
+ require 'grpc_kit/session/io'
4
4
  require 'grpc_kit/session/server'
5
5
 
6
6
  module GrpcKit
7
7
  class Server
8
- def initialize
8
+ def initialize(interceptors: [])
9
9
  @sessions = []
10
- @handler = {}
11
10
  @rpc_descs = {}
11
+ @interceptors = interceptors
12
12
  end
13
13
 
14
14
  # @params handler [object]
15
15
  def handle(handler)
16
- klass = handler.class
17
-
18
- klass.rpc_descs.values.each do |rpc_desc|
19
- path = rpc_desc.path(klass.service_name)
16
+ handler.class.rpc_descs.each do |path, rpc_desc|
20
17
  if @rpc_descs[path]
21
- raise "Duplicated method registered #{key}, class: #{handler}"
18
+ raise "Duplicated method registered #{path}, class: #{handler}"
22
19
  end
23
20
 
24
- @rpc_descs[path] = [rpc_desc, handler]
21
+ @rpc_descs[path] = rpc_desc.build_server(handler, interceptors: @interceptors)
25
22
  end
26
23
  end
27
24
 
28
25
  def run
29
26
  GrpcKit.logger.info("Start grpc_kit v#{GrpcKit::VERSION}")
30
- # XXX
27
+
28
+ @rpc_descs.freeze
31
29
  end
32
30
 
33
31
  def stop
34
32
  GrpcKit.logger.info('Stop grpc_kit')
35
-
36
33
  @sessions.each(&:stop)
37
34
  end
38
35
 
39
- def session_start(conn, io = GrpcKit::IO::Basic)
40
- session = GrpcKit::Session::Server.new(io.new(conn, conn), self) # TODO: change self to proper object
36
+ def session_start(conn)
37
+ session = GrpcKit::Session::Server.new(
38
+ GrpcKit::Session::IO.new(conn),
39
+ self,
40
+ )
41
41
  @sessions << session
42
42
 
43
43
  session.submit_settings([])
44
44
  session.start # blocking
45
+ session.finish
45
46
  end
46
47
 
47
- def on_data_chunk_recv(stream, data)
48
- compressed, length, buf = data.unpack('CNa*')
49
- if compressed == 0 # TODO: not
50
- if length != buf.size
51
- raise 'recived data inconsistent'
52
- end
53
-
54
- stream.recv(buf)
55
- else
56
- raise 'not supported'
48
+ def dispatch(stream, session)
49
+ rpc = @rpc_descs[stream.headers.path]
50
+ unless rpc
51
+ raise "Unkown path #{path}"
57
52
  end
58
- end
59
53
 
60
- def on_frame_data_recv(stream)
61
- return unless stream.exist_data?
62
-
63
- path = stream.headers[':path']
64
- rpc = @rpc_descs[path.to_sym]
65
- if rpc
66
- resp = rpc[0].invoke(rpc[1], stream.data)
67
- buf = [0, resp.length, resp].pack('CNa*')
68
- stream.data = ''
69
- stream.send(StringIO.new(buf))
70
- else
71
- # TODO: 404
72
- raise "unkown path #{path}"
73
- end
54
+ rpc.invoke(stream, session)
74
55
  end
75
56
  end
76
57
  end