grpc_kit 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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