grpc_kit 0.1.3 → 0.1.4

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -1
  3. data/TODO.md +1 -1
  4. data/examples/helloworld_client.rb +5 -1
  5. data/examples/routeguide_client.rb +5 -2
  6. data/lib/grpc_kit/calls/client_client_streamer.rb +29 -0
  7. data/lib/grpc_kit/calls/client_request_response.rb +25 -0
  8. data/lib/grpc_kit/calls/client_server_streamer.rb +29 -0
  9. data/lib/grpc_kit/calls/server_client_streamer.rb +32 -0
  10. data/lib/grpc_kit/calls/server_request_response.rb +32 -0
  11. data/lib/grpc_kit/calls/server_server_streamer.rb +32 -0
  12. data/lib/grpc_kit/calls.rb +39 -0
  13. data/lib/grpc_kit/client.rb +17 -17
  14. data/lib/grpc_kit/grpc_time.rb +100 -0
  15. data/lib/grpc_kit/interceptors/client_client_streamer.rb +19 -0
  16. data/lib/grpc_kit/interceptors/client_request_response.rb +39 -0
  17. data/lib/grpc_kit/interceptors/client_server_streamer.rb +19 -0
  18. data/lib/grpc_kit/interceptors/server_client_streamer.rb +15 -0
  19. data/lib/grpc_kit/interceptors/server_request_response.rb +36 -0
  20. data/lib/grpc_kit/interceptors/server_server_streamer.rb +17 -0
  21. data/lib/grpc_kit/interceptors.rb +64 -5
  22. data/lib/grpc_kit/rpc_desc.rb +18 -2
  23. data/lib/grpc_kit/rpcs/client_bidi_streamer.rb +11 -0
  24. data/lib/grpc_kit/rpcs/client_client_streamer.rb +23 -0
  25. data/lib/grpc_kit/rpcs/client_request_response.rb +31 -0
  26. data/lib/grpc_kit/rpcs/client_server_streamer.rb +19 -0
  27. data/lib/grpc_kit/rpcs/server_bidi_streamer.rb +10 -0
  28. data/lib/grpc_kit/rpcs/server_client_streamer.rb +24 -0
  29. data/lib/grpc_kit/rpcs/server_request_response.rb +26 -0
  30. data/lib/grpc_kit/rpcs/server_server_streamer.rb +26 -0
  31. data/lib/grpc_kit/rpcs.rb +21 -5
  32. data/lib/grpc_kit/server.rb +16 -7
  33. data/lib/grpc_kit/session/headers.rb +2 -2
  34. data/lib/grpc_kit/session/stream.rb +5 -0
  35. data/lib/grpc_kit/{session/client.rb → sessions/client_session.rb} +5 -6
  36. data/lib/grpc_kit/{session/server.rb → sessions/server_session.rb} +21 -8
  37. data/lib/grpc_kit/streams/client_stream.rb +146 -0
  38. data/lib/grpc_kit/streams/server_stream.rb +105 -0
  39. data/lib/grpc_kit/{streams → transport}/packable.rb +2 -2
  40. data/lib/grpc_kit/{streams → transport}/send_buffer.rb +1 -1
  41. data/lib/grpc_kit/transports/client_transport.rb +96 -0
  42. data/lib/grpc_kit/transports/server_transport.rb +68 -0
  43. data/lib/grpc_kit/version.rb +1 -1
  44. metadata +32 -21
  45. data/lib/grpc_kit/interceptors/client_streamer.rb +0 -31
  46. data/lib/grpc_kit/interceptors/request_response.rb +0 -70
  47. data/lib/grpc_kit/interceptors/server_streamer.rb +0 -33
  48. data/lib/grpc_kit/interceptors/streaming.rb +0 -70
  49. data/lib/grpc_kit/rpcs/base.rb +0 -30
  50. data/lib/grpc_kit/rpcs/bidi_streamer.rb +0 -18
  51. data/lib/grpc_kit/rpcs/call.rb +0 -27
  52. data/lib/grpc_kit/rpcs/client_streamer.rb +0 -38
  53. data/lib/grpc_kit/rpcs/error.rb +0 -23
  54. data/lib/grpc_kit/rpcs/request_response.rb +0 -64
  55. data/lib/grpc_kit/rpcs/server_streamer.rb +0 -42
  56. data/lib/grpc_kit/session/duration.rb +0 -97
  57. data/lib/grpc_kit/stream.rb +0 -120
  58. data/lib/grpc_kit/streams/client.rb +0 -113
  59. data/lib/grpc_kit/streams/server.rb +0 -54
@@ -1,9 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'grpc_kit/method_config'
4
- require 'grpc_kit/rpcs'
5
4
  require 'grpc_kit/protobuffer'
6
- require 'grpc_kit/interceptors'
5
+
6
+ require 'grpc_kit/interceptors/client_request_response'
7
+ require 'grpc_kit/interceptors/client_client_streamer'
8
+ require 'grpc_kit/interceptors/client_server_streamer'
9
+ # require 'grpc_kit/client_interceptors/bidi_streamer'
10
+ require 'grpc_kit/rpcs/client_request_response'
11
+ require 'grpc_kit/rpcs/client_client_streamer'
12
+ require 'grpc_kit/rpcs/client_server_streamer'
13
+ require 'grpc_kit/rpcs/client_bidi_streamer'
14
+
15
+ require 'grpc_kit/interceptors/server_request_response'
16
+ require 'grpc_kit/interceptors/server_client_streamer'
17
+ require 'grpc_kit/interceptors/server_server_streamer'
18
+ # require 'grpc_kit/server_interceptors/bidi_streamer'
19
+ require 'grpc_kit/rpcs/server_request_response'
20
+ require 'grpc_kit/rpcs/server_client_streamer'
21
+ require 'grpc_kit/rpcs/server_server_streamer'
22
+ require 'grpc_kit/rpcs/server_bidi_streamer'
7
23
 
8
24
  module GrpcKit
9
25
  class RpcDesc
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs'
4
+
5
+ module GrpcKit
6
+ module Rpcs::Client
7
+ class BidiStreamer < GrpcKit::Rpcs::ClientRpc
8
+ def invoke(session, data, opts = {}); end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs'
4
+ require 'grpc_kit/calls/client_client_streamer'
5
+
6
+ module GrpcKit
7
+ module Rpcs::Client
8
+ class ClientStreamer < GrpcKit::Rpcs::ClientRpc
9
+ def invoke(stream, _request, metadata: {}, timeout: nil)
10
+ call = GrpcKit::Calls::Client::ClientStreamer.new(
11
+ metadata: metadata,
12
+ config: @config,
13
+ timeout: timeout,
14
+ stream: stream,
15
+ )
16
+
17
+ @config.interceptor.intercept(call, metadata) do |s|
18
+ s
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs'
4
+ require 'grpc_kit/calls/client_request_response'
5
+
6
+ module GrpcKit
7
+ module Rpcs::Client
8
+ class RequestResponse < GrpcKit::Rpcs::ClientRpc
9
+ def invoke(stream, request, metadata: {}, timeout: nil)
10
+ call = GrpcKit::Calls::Client::RequestResponse.new(
11
+ metadata: metadata,
12
+ config: @config,
13
+ timeout: timeout,
14
+ stream: stream,
15
+ )
16
+
17
+ @config.interceptor.intercept(request, call, call.metadata) do |r, c, _|
18
+ if timeout
19
+ Timeout.timeout(timeout.to_f, GrpcKit::Errors::DeadlineExceeded) do
20
+ call.send_msg(r, timeout: timeout.to_s, metadata: c.metadata, last: true)
21
+ call.recv(last: true)
22
+ end
23
+ else
24
+ call.send_msg(r, metadata: c.metadata, last: true)
25
+ call.recv(last: true)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs'
4
+ require 'grpc_kit/calls/client_server_streamer'
5
+
6
+ module GrpcKit
7
+ module Rpcs::Client
8
+ class ServerStreamer < GrpcKit::Rpcs::ClientRpc
9
+ def invoke(stream, request, metadata: {}, timeout: nil)
10
+ call = GrpcKit::Calls::Client::ServerStreamer.new(metadata: metadata, config: @config, timeout: timeout, stream: stream)
11
+
12
+ @config.interceptor.intercept(call, metadata) do |c, m|
13
+ c.send_msg(request, metadata: m, last: true)
14
+ c
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs'
4
+
5
+ module GrpcKit
6
+ module Rpcs::Server
7
+ class BidiStreamer < GrpcKit::Rpcs::ServerRpc
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs'
4
+ require 'grpc_kit/calls/server_client_streamer'
5
+
6
+ module GrpcKit
7
+ module Rpcs::Server
8
+ class ClientStreamer < GrpcKit::Rpcs::ServerRpc
9
+ def invoke(stream, metadata: {})
10
+ call = GrpcKit::Calls::Server::ClientStreamer.new(metadata: metadata, config: @config, stream: stream)
11
+
12
+ if @config.interceptor
13
+ @config.interceptor.intercept(call) do |c|
14
+ resp = @handler.send(@config.ruby_style_method_name, c)
15
+ c.send_msg(resp, last: true)
16
+ end
17
+ else
18
+ resp = @handler.send(@config.ruby_style_method_name, call)
19
+ call.send_msg(resp, last: true)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs'
4
+ require 'grpc_kit/calls/server_request_response'
5
+
6
+ module GrpcKit
7
+ module Rpcs::Server
8
+ class RequestResponse < GrpcKit::Rpcs::ServerRpc
9
+ def invoke(stream, metadata: {})
10
+ call = GrpcKit::Calls::Server::RequestResponse.new(metadata: metadata, config: @config, stream: stream)
11
+ request = call.recv(last: true)
12
+
13
+ resp =
14
+ if @config.interceptor
15
+ @config.interceptor.intercept(request, call) do |_, _|
16
+ @handler.send(@config.ruby_style_method_name, request, call)
17
+ end
18
+ else
19
+ @handler.send(@config.ruby_style_method_name, request, call)
20
+ end
21
+
22
+ call.send_msg(resp, last: true)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/rpcs'
4
+ require 'grpc_kit/calls/server_server_streamer'
5
+
6
+ module GrpcKit
7
+ module Rpcs::Server
8
+ class ServerStreamer < GrpcKit::Rpcs::ServerRpc
9
+ def invoke(stream, metadata: {})
10
+ call = GrpcKit::Calls::Server::ServerStreamer.new(metadata: metadata, config: @config, stream: stream)
11
+
12
+ if @config.interceptor
13
+ @config.interceptor.intercept(call) do |c|
14
+ request = c.recv(last: true)
15
+ @handler.send(@config.ruby_style_method_name, request, c)
16
+ end
17
+ else
18
+ request = call.recv(last: true)
19
+ @handler.send(@config.ruby_style_method_name, request, call)
20
+ end
21
+
22
+ stream.send_status
23
+ end
24
+ end
25
+ end
26
+ end
data/lib/grpc_kit/rpcs.rb CHANGED
@@ -1,12 +1,28 @@
1
1
  # frozen_string_literal: true
2
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
- require 'grpc_kit/rpcs/error'
3
+ require 'timeout'
4
+ require 'grpc_kit/errors'
5
+ require 'grpc_kit/status_codes'
8
6
 
9
7
  module GrpcKit
10
8
  module Rpcs
9
+ class ClientRpc
10
+ attr_reader :config
11
+
12
+ def initialize(config)
13
+ @config = config
14
+ end
15
+
16
+ def invoke(stream, request, metadata: {}, timeout: nil); end
17
+ end
18
+
19
+ class ServerRpc
20
+ def initialize(handler, config)
21
+ @handler = handler
22
+ @config = config
23
+ end
24
+
25
+ def invoke(stream, metadata: {}); end
26
+ end
11
27
  end
12
28
  end
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'grpc_kit/session/io'
4
- require 'grpc_kit/session/server'
4
+ require 'grpc_kit/sessions/server_session'
5
5
 
6
6
  module GrpcKit
7
7
  class Server
8
8
  def initialize(interceptors: [])
9
9
  @sessions = []
10
10
  @rpc_descs = {}
11
- @error_rpc = GrpcKit::Rpcs::Server::Error.new
12
11
  @interceptors = interceptors
13
12
  @mutex = Mutex.new
14
13
 
@@ -41,19 +40,29 @@ module GrpcKit
41
40
  end
42
41
  end
43
42
 
44
- def dispatch(stream, session)
45
- rpc = @rpc_descs[stream.headers.path]
43
+ def graceful_shutdown
44
+ @mutex.synchronize do
45
+ @sessions.each(&:drain)
46
+ end
47
+ end
48
+
49
+ # @params path [String]
50
+ # @params stream [GrpcKit::Streams::ServerStream]
51
+ def dispatch(path, stream)
52
+ rpc = @rpc_descs[path]
46
53
  unless rpc
47
- return @error_rpc.send_bad_status(stream, session, GrpcKit::Errors::Unimplemented.new(stream.headers.path))
54
+ e = GrpcKit::Errors::Unimplemented.new(path)
55
+ stream.send_status(status: e.code, msg: e.message)
56
+ return
48
57
  end
49
58
 
50
- rpc.invoke(stream, session)
59
+ stream.invoke(rpc)
51
60
  end
52
61
 
53
62
  private
54
63
 
55
64
  def establish_session(conn)
56
- session = GrpcKit::Session::Server.new(GrpcKit::Session::IO.new(conn), self)
65
+ session = GrpcKit::Sessions::ServerSession.new(GrpcKit::Session::IO.new(conn), self)
57
66
  begin
58
67
  @mutex.synchronize { @sessions << session }
59
68
  yield(session)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'grpc_kit/session/duration'
3
+ require 'grpc_kit/grpc_time'
4
4
 
5
5
  module GrpcKit
6
6
  module Session
@@ -45,7 +45,7 @@ module GrpcKit
45
45
  when 'grpc-status'
46
46
  self.grpc_status = val
47
47
  when 'grpc-timeout'
48
- self.timeout = Duration.decode(val)
48
+ self.timeout = GrpcTime.new(val)
49
49
  when 'grpc-message'
50
50
  self.status_message = val
51
51
  when 'grpc-status-details-bin'
@@ -27,6 +27,11 @@ module GrpcKit
27
27
  @inflight = false
28
28
  @trailer_data = {}
29
29
  @status = GrpcKit::Session::StreamStatus.new
30
+ @draining = false
31
+ end
32
+
33
+ def drain
34
+ @draining = true
30
35
  end
31
36
 
32
37
  def write_trailers_data(tariler)
@@ -1,27 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
4
3
  require 'ds9'
4
+ require 'forwardable'
5
5
  require 'grpc_kit/session/stream'
6
6
 
7
7
  module GrpcKit
8
- module Session
9
- class Client < DS9::Client
8
+ module Sessions
9
+ class ClientSession < DS9::Client
10
10
  extend Forwardable
11
11
 
12
12
  delegate %i[send_event recv_event] => :@io
13
13
 
14
14
  # @params io [GrpcKit::Session::IO]
15
- def initialize(io, handler, opts = {})
15
+ def initialize(io, opts = {})
16
16
  super() # initialize DS9::Session
17
17
 
18
18
  @io = io
19
19
  @streams = {}
20
- @handler = handler
21
20
  @opts = opts
22
21
  end
23
22
 
24
- def start_request(data, headers)
23
+ def send_request(data, headers)
25
24
  stream_id = submit_request(headers, data)
26
25
  stream = GrpcKit::Session::Stream.new(stream_id: stream_id, send_data: data)
27
26
  stream.stream_id = stream_id
@@ -1,24 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
4
3
  require 'ds9'
4
+ require 'forwardable'
5
5
  require 'grpc_kit/session/stream'
6
+ require 'grpc_kit/streams/server_stream'
7
+ require 'grpc_kit/transports/server_transport'
6
8
 
7
9
  module GrpcKit
8
- module Session
9
- class Server < DS9::Server
10
+ module Sessions
11
+ class ServerSession < DS9::Server
10
12
  extend Forwardable
11
13
 
12
14
  delegate %i[send_event recv_event] => :@io
13
15
 
14
16
  # @params io [GrpcKit::Session::IO]
15
- def initialize(io, handler)
17
+ # @params dispatcher [GrpcKit::Server]
18
+ def initialize(io, dispatcher)
16
19
  super() # initialize DS9::Session
17
20
 
18
21
  @io = io
19
22
  @streams = {}
20
23
  @stop = false
21
- @handler = handler
24
+ @dispatcher = dispatcher
22
25
  @peer_shutdowned = false
23
26
  @inflights = []
24
27
  end
@@ -26,7 +29,7 @@ module GrpcKit
26
29
  def start
27
30
  @io.wait_readable
28
31
  loop do
29
- invoke_handler
32
+ invoke
30
33
 
31
34
  if !want_read? && !want_write?
32
35
  break
@@ -53,6 +56,14 @@ module GrpcKit
53
56
  end
54
57
  end
55
58
 
59
+ def drain
60
+ # could be race condition
61
+ @streams.each do |s|
62
+ GrpcKit.logger.debug("#{s.stream_id} is draining")
63
+ s.drain
64
+ end
65
+ end
66
+
56
67
  def finish
57
68
  stop
58
69
  @io.close
@@ -64,9 +75,11 @@ module GrpcKit
64
75
  @stop = true
65
76
  end
66
77
 
67
- def invoke_handler
78
+ def invoke
68
79
  while (stream = @inflights.pop)
69
- @handler.dispatch(stream, self)
80
+ t = GrpcKit::Transports::ServerTransport.new(self, stream)
81
+ th = GrpcKit::Streams::ServerStream.new(t)
82
+ @dispatcher.dispatch(stream.headers.path, th)
70
83
  end
71
84
  end
72
85
 
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/status_codes'
4
+
5
+ module GrpcKit
6
+ module Streams
7
+ class ClientStream
8
+ # @params transport [GrpcKit::Transports::ClientTransport]
9
+ # @params config [GrpcKit::MethodConfig]
10
+ # @params authority [String]
11
+ def initialize(transport, config, authority:, timeout: nil)
12
+ @transport = transport
13
+ @config = config
14
+
15
+ @authority = authority
16
+ @timeout = timeout
17
+
18
+ @sent_first_msg = false
19
+ end
20
+
21
+ def send_msg(data, metadata: {}, timeout: nil, last: false)
22
+ buf =
23
+ begin
24
+ @config.protobuf.encode(data)
25
+ rescue ArgumentError => e
26
+ raise GrpcKit::Errors::Internal, "Error while encoding in client: #{e}"
27
+ end
28
+
29
+ limit_size = @config.max_send_message_size
30
+ if limit_size && buf.bytesize > limit_size
31
+ raise GrpcKit::Errors::ResourceExhausted, "Sending message is too large: send=#{req.bytesize}, max=#{limit_size}"
32
+ end
33
+
34
+ if @sent_first_msg
35
+ # unless metadata.empty?
36
+ # raise 'You can attach metadata at first send_msg' # XXX
37
+ # end
38
+ @transport.write_data(buf, last: last)
39
+ else
40
+ headers = build_headers(metadata: metadata)
41
+ @transport.send_request(buf, headers, last: last)
42
+ @sent_first_msg = true
43
+ end
44
+ end
45
+
46
+ def each
47
+ validate_if_request_start!
48
+
49
+ loop { yield(do_recv) }
50
+ end
51
+
52
+ def recv_msg(last: false)
53
+ validate_if_request_start!
54
+
55
+ do_recv(last: last)
56
+ end
57
+
58
+ def close_and_recv
59
+ validate_if_request_start!
60
+
61
+ @transport.close_and_flush
62
+ check_status!
63
+
64
+ data = []
65
+ loop { data.push(do_recv) }
66
+ data
67
+ end
68
+
69
+ private
70
+
71
+ def validate_if_request_start!
72
+ unless @sent_first_msg
73
+ raise 'You should call `send_msg` method to send data'
74
+ end
75
+ end
76
+
77
+ def do_recv(last: false)
78
+ data = @transport.read_data(last: last)
79
+
80
+ if data.nil?
81
+ check_status!
82
+ raise StopIteration
83
+ end
84
+
85
+ compressed, size, buf = *data
86
+
87
+ unless size == buf.size
88
+ raise "inconsistent data: #{buf}"
89
+ end
90
+
91
+ limit_size = @config.max_receive_message_size
92
+ if limit_size && size > limit_size
93
+ raise GrpcKit::Errors::ResourceExhausted, "Receving message is too large: recevied=#{size}, max=#{limit_size}"
94
+ end
95
+
96
+ if compressed
97
+ raise 'compress option is unsupported'
98
+ end
99
+
100
+ raise StopIteration if buf.nil?
101
+
102
+ begin
103
+ @config.protobuf.decode(buf)
104
+ rescue ArgumentError => e
105
+ raise GrpcKit::Errors::Internal, "Error while decoding in Client: #{e}"
106
+ end
107
+ end
108
+
109
+ def check_status!
110
+ headers = @transport.recv_headers
111
+
112
+ if headers.grpc_status != GrpcKit::StatusCodes::OK
113
+ raise GrpcKit::Errors.from_status_code(headers.grpc_status, headers.status_message)
114
+ else
115
+ GrpcKit.logger.debug('request is success')
116
+ end
117
+ end
118
+
119
+ def build_headers(metadata: {}, **headers)
120
+ # TODO: an order of Headers is important?
121
+ hdrs = {
122
+ ':method' => 'POST',
123
+ ':scheme' => 'http',
124
+ ':path' => @config.path,
125
+ ':authority' => @authority,
126
+ 'grpc-timeout' => @timeout,
127
+ 'te' => 'trailers',
128
+ 'content-type' => 'application/grpc',
129
+ 'user-agent' => "grpc-ruby/#{GrpcKit::VERSION} (grpc_kit)",
130
+ 'grpc-accept-encoding' => 'identity,deflate,gzip',
131
+ }.merge(headers)
132
+
133
+ metadata.each do |k, v|
134
+ if k.start_with?('grpc-')
135
+ # https://github.com/grpc/grpc/blob/ffac9d90b18cb076b1c952faa55ce4e049cbc9a6/doc/PROTOCOL-HTTP2.md
136
+ GrpcKit.logger.info("metadata name wich starts with 'grpc-' is reserved for future GRPC")
137
+ else
138
+ hdrs[k] = v
139
+ end
140
+ end
141
+
142
+ hdrs.compact
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit/status_codes'
4
+
5
+ module GrpcKit
6
+ module Streams
7
+ class ServerStream
8
+ # @params transport [GrpcKit::transports::ServerTransport]
9
+ def initialize(transport)
10
+ @transport = transport
11
+ @sent_first_msg = false
12
+ end
13
+
14
+ def invoke(rpc)
15
+ rpc.invoke(self, metadata: @transport.recv_headers.metadata)
16
+ rescue GrpcKit::Errors::BadStatus => e
17
+ GrpcKit.logger.debug(e)
18
+ send_status(status: e.code, msg: e.reason, metadata: {}) # TODO: metadata should be set
19
+ rescue StandardError => e
20
+ GrpcKit.logger.debug(e)
21
+ send_status(status: GrpcKit::StatusCodes::UNKNOWN, msg: e.message, metadata: {})
22
+ end
23
+
24
+ def send_msg(data, protobuf, last: false, limit_size: nil)
25
+ if last
26
+ send_trailer # TODO: pass trailer metadata
27
+ end
28
+
29
+ buf =
30
+ begin
31
+ protobuf.encode(data)
32
+ rescue ArgumentError => e
33
+ raise GrpcKit::Errors::Internal, "Error while encoding in server: #{e}"
34
+ end
35
+
36
+ if limit_size && buf.bytesize > limit_size
37
+ raise GrpcKit::Errors::ResourceExhausted, "Sending message is too large: send=#{req.bytesize}, max=#{limit_size}"
38
+ end
39
+
40
+ @transport.write_data(buf, last: last)
41
+ return if @sent_first_msg
42
+
43
+ send_response({})
44
+ @sent_first_msg = true
45
+ end
46
+
47
+ def recv_msg(protobuf, last: false, limit_size: nil)
48
+ data = @transport.read_data(last: last)
49
+
50
+ raise StopIteration if data.nil?
51
+
52
+ compressed, size, buf = *data
53
+
54
+ unless size == buf.size
55
+ raise "inconsistent data: #{buf}"
56
+ end
57
+
58
+ if limit_size && size > limit_size
59
+ raise GrpcKit::Errors::ResourceExhausted, "Receving message is too large: recevied=#{size}, max=#{limit_size}"
60
+ end
61
+
62
+ if compressed
63
+ raise 'compress option is unsupported'
64
+ end
65
+
66
+ raise StopIteration if buf.nil?
67
+
68
+ begin
69
+ protobuf.decode(buf)
70
+ rescue ArgumentError => e
71
+ raise GrpcKit::Errors::Internal, "Error while decoding in Server: #{e}"
72
+ end
73
+ end
74
+
75
+ def each
76
+ loop { yield(recv) }
77
+ end
78
+
79
+ def send_status(status: GrpcKit::StatusCodes::INTERNAL, msg: nil, metadata: {})
80
+ send_trailer(status: status, msg: msg, metadata: metadata)
81
+ return if @sent_first_msg
82
+
83
+ send_response({})
84
+ @sent_first_msg = true
85
+ end
86
+
87
+ def send_trailer(status: GrpcKit::StatusCodes::OK, msg: nil, metadata: {})
88
+ trailer = metadata.dup
89
+ trailer['grpc-status'] = status.to_s
90
+ if msg
91
+ trailer['grpc-message'] = msg
92
+ end
93
+
94
+ @transport.write_trailers_data(trailer)
95
+ end
96
+
97
+ def send_response(headers)
98
+ h = { ':status' => '200', 'content-type' => 'application/grpc' }.merge(headers)
99
+ h['accept-encoding'] = 'identity'
100
+
101
+ @transport.send_response(h)
102
+ end
103
+ end
104
+ end
105
+ end