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.
- checksums.yaml +4 -4
- data/.rubocop.yml +22 -6
- data/examples/interceptors/client_logging_interceptor.rb +48 -0
- data/examples/interceptors/server_logging_interceptor.rb +44 -0
- data/examples/routeguide_client.rb +63 -3
- data/examples/routeguide_server.rb +86 -3
- data/grpc_kit.gemspec +1 -1
- data/lib/grpc.rb +1 -0
- data/lib/grpc_kit/client.rb +31 -79
- data/lib/grpc_kit/errors.rb +18 -8
- data/lib/grpc_kit/grpc/dsl.rb +19 -21
- data/lib/grpc_kit/grpc/generic_service.rb +1 -1
- data/lib/grpc_kit/grpc/interceptor.rb +57 -0
- data/lib/grpc_kit/grpc/logger.rb +17 -0
- data/lib/grpc_kit/interceptors.rb +11 -0
- data/lib/grpc_kit/interceptors/client_streamer.rb +31 -0
- data/lib/grpc_kit/interceptors/request_response.rb +70 -0
- data/lib/grpc_kit/interceptors/server_streamer.rb +33 -0
- data/lib/grpc_kit/interceptors/streaming.rb +70 -0
- data/lib/grpc_kit/method_config.rb +34 -0
- data/lib/grpc_kit/protobuffer.rb +20 -0
- data/lib/grpc_kit/rpc_desc.rb +103 -27
- data/lib/grpc_kit/rpcs.rb +11 -0
- data/lib/grpc_kit/rpcs/base.rb +30 -0
- data/lib/grpc_kit/rpcs/bidi_streamer.rb +18 -0
- data/lib/grpc_kit/rpcs/call.rb +27 -0
- data/lib/grpc_kit/rpcs/client_streamer.rb +38 -0
- data/lib/grpc_kit/rpcs/request_response.rb +50 -0
- data/lib/grpc_kit/rpcs/server_streamer.rb +42 -0
- data/lib/grpc_kit/server.rb +19 -38
- data/lib/grpc_kit/session/buffer.rb +58 -0
- data/lib/grpc_kit/session/client.rb +100 -52
- data/lib/grpc_kit/session/duration.rb +96 -0
- data/lib/grpc_kit/session/headers.rb +65 -0
- data/lib/grpc_kit/session/io.rb +56 -0
- data/lib/grpc_kit/session/server.rb +107 -68
- data/lib/grpc_kit/session/stream.rb +32 -40
- data/lib/grpc_kit/stream.rb +71 -0
- data/lib/grpc_kit/streams/client.rb +87 -0
- data/lib/grpc_kit/streams/packable.rb +60 -0
- data/lib/grpc_kit/streams/send_buffer.rb +48 -0
- data/lib/grpc_kit/streams/server.rb +36 -0
- data/lib/grpc_kit/streams/stream.rb +58 -0
- data/lib/grpc_kit/version.rb +1 -1
- metadata +32 -5
- data/lib/grpc_kit/io/basic.rb +0 -35
@@ -1,31 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'forwardable'
|
3
4
|
require 'ds9'
|
4
5
|
require 'grpc_kit/session/stream'
|
5
6
|
|
6
7
|
module GrpcKit
|
7
8
|
module Session
|
8
9
|
class Server < DS9::Server
|
9
|
-
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
delegate %i[send_event recv_event] => :@io
|
13
|
+
|
14
|
+
# @params io [GrpcKit::Session::IO]
|
10
15
|
def initialize(io, handler)
|
11
|
-
super() # initialize DS9::
|
16
|
+
super() # initialize DS9::Session
|
12
17
|
|
13
18
|
@io = io
|
14
19
|
@streams = {}
|
15
20
|
@stop = false
|
16
21
|
@handler = handler
|
22
|
+
@peer_shutdowned = false
|
23
|
+
@inflights = []
|
17
24
|
end
|
18
25
|
|
19
26
|
def start
|
20
27
|
@io.wait_readable
|
21
|
-
|
22
|
-
|
23
|
-
send
|
24
|
-
end
|
28
|
+
loop do
|
29
|
+
invoke_handler
|
25
30
|
|
26
|
-
if want_read?
|
27
|
-
|
31
|
+
if !want_read? && !want_write?
|
32
|
+
break
|
33
|
+
elsif @peer_shutdowned && !want_write?
|
34
|
+
break
|
28
35
|
end
|
36
|
+
|
37
|
+
run_once
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def run_once
|
42
|
+
return if @stop
|
43
|
+
|
44
|
+
if want_read?
|
45
|
+
do_read
|
46
|
+
end
|
47
|
+
|
48
|
+
if want_write?
|
49
|
+
send
|
29
50
|
end
|
30
51
|
end
|
31
52
|
|
@@ -33,79 +54,103 @@ module GrpcKit
|
|
33
54
|
@stop = true
|
34
55
|
end
|
35
56
|
|
57
|
+
def finish
|
58
|
+
stop
|
59
|
+
@io.close
|
60
|
+
end
|
61
|
+
|
36
62
|
private
|
37
63
|
|
38
|
-
|
39
|
-
|
64
|
+
def invoke_handler
|
65
|
+
while (stream = @inflights.pop)
|
66
|
+
@handler.dispatch(stream, self)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def do_read
|
71
|
+
receive
|
72
|
+
rescue IOError => e
|
73
|
+
finish
|
74
|
+
raise e
|
75
|
+
rescue DS9::Exception => e
|
76
|
+
finish
|
77
|
+
if DS9::ERR_EOF == e.code
|
78
|
+
@peer_shutdowned = true
|
79
|
+
return
|
80
|
+
# raise EOFError
|
81
|
+
end
|
82
|
+
|
83
|
+
raise e
|
84
|
+
end
|
85
|
+
|
86
|
+
# `provider` for nghttp2_submit_response
|
40
87
|
def on_data_source_read(stream_id, length)
|
41
88
|
GrpcKit.logger.debug("on_data_source_read #{stream_id}, lenght=#{length}")
|
42
89
|
|
43
|
-
|
44
|
-
|
90
|
+
stream = @streams[stream_id]
|
91
|
+
data = @streams[stream_id].pending_send_data.read(length)
|
92
|
+
if data.empty? && stream.end_write?
|
93
|
+
# TODO
|
45
94
|
submit_trailer(stream_id, 'grpc-status' => '0')
|
46
|
-
|
95
|
+
|
96
|
+
false # means EOF and END_STREAM
|
47
97
|
else
|
48
98
|
data
|
49
99
|
end
|
50
100
|
end
|
51
101
|
|
52
|
-
#
|
53
|
-
# override
|
54
|
-
def send_event(string)
|
55
|
-
GrpcKit.logger.debug('send_event')
|
56
|
-
|
57
|
-
@io.write(string)
|
58
|
-
end
|
59
|
-
|
60
|
-
# for nghttp2_session_callbacks_set_recv_callback
|
61
|
-
# override
|
62
|
-
def recv_event(length)
|
63
|
-
# GrpcKit.logger.debug("recv_event #{length}")
|
64
|
-
@io.read(length)
|
65
|
-
end
|
66
|
-
|
67
|
-
# for nghttp2_session_callbacks_set_on_frame_send_callback
|
102
|
+
# nghttp2_session_callbacks_set_on_frame_recv_callback
|
68
103
|
def on_frame_recv(frame)
|
69
104
|
GrpcKit.logger.debug("on_frame_recv #{frame}")
|
105
|
+
|
70
106
|
case frame
|
71
107
|
when DS9::Frames::Data
|
72
|
-
|
108
|
+
|
73
109
|
stream = @streams[frame.stream_id]
|
74
|
-
|
75
|
-
|
76
|
-
|
110
|
+
|
111
|
+
if frame.end_stream?
|
112
|
+
stream.remote_end_stream = true
|
77
113
|
end
|
78
114
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
115
|
+
unless stream.inflight
|
116
|
+
stream.inflight = true
|
117
|
+
@inflights << stream
|
118
|
+
end
|
119
|
+
when DS9::Frames::Headers
|
120
|
+
stream = @streams[frame.stream_id]
|
121
|
+
|
122
|
+
if frame.end_stream?
|
123
|
+
stream.remote_end_stream = true
|
124
|
+
end
|
125
|
+
|
126
|
+
# when DS9::Frames::Goaway
|
127
|
+
# when DS9::Frames::RstStream
|
91
128
|
end
|
92
129
|
|
93
130
|
true
|
94
131
|
end
|
95
132
|
|
96
|
-
#
|
133
|
+
# nghttp2_session_callbacks_set_on_frame_send_callback
|
97
134
|
def on_frame_send(frame)
|
98
135
|
GrpcKit.logger.debug("on_frame_send #{frame}")
|
136
|
+
case frame
|
137
|
+
when DS9::Frames::Data, DS9::Frames::Headers
|
138
|
+
stream = @streams[frame.stream_id]
|
139
|
+
if frame.end_stream?
|
140
|
+
stream.local_end_stream = true
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
99
144
|
true
|
100
145
|
end
|
101
146
|
|
102
|
-
#
|
147
|
+
# nghttp2_session_callbacks_set_on_frame_not_send_callback
|
103
148
|
def on_frame_not_send(frame, reason)
|
104
149
|
GrpcKit.logger.debug("on_frame_not_send frame=#{frame}, reason=#{reason}")
|
105
150
|
true
|
106
151
|
end
|
107
152
|
|
108
|
-
#
|
153
|
+
# nghttp2_session_callbacks_set_on_begin_headers_callback
|
109
154
|
def on_begin_headers(header)
|
110
155
|
stream_id = header.stream_id
|
111
156
|
GrpcKit.logger.debug("on_begin_header stream_id=#{stream_id}")
|
@@ -117,38 +162,32 @@ module GrpcKit
|
|
117
162
|
@streams[stream_id] = GrpcKit::Session::Stream.new(stream_id: stream_id)
|
118
163
|
end
|
119
164
|
|
120
|
-
#
|
165
|
+
# nghttp2_session_callbacks_set_on_header_callback
|
121
166
|
def on_header(name, value, frame, _flags)
|
122
|
-
@streams[frame.stream_id]
|
123
|
-
|
124
|
-
|
125
|
-
# for nghttp2_session_callbacks_set_on_begin_frame_callback
|
126
|
-
def on_begin_frame(frame_header)
|
127
|
-
GrpcKit.logger.debug("on_begin_frame #{frame_header}")
|
128
|
-
true
|
167
|
+
stream = @streams[frame.stream_id]
|
168
|
+
stream.add_header(name, value)
|
129
169
|
end
|
130
170
|
|
131
|
-
# for nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
|
132
171
|
def on_invalid_frame_recv(frame, error_code)
|
133
|
-
GrpcKit.logger.debug("on_invalid_frame_recv #{error_code}")
|
172
|
+
GrpcKit.logger.debug("on_invalid_frame_recv #{frame} error_code=#{error_code}")
|
134
173
|
true
|
135
174
|
end
|
136
175
|
|
137
|
-
#
|
176
|
+
# nghttp2_session_callbacks_set_on_stream_close_callback
|
138
177
|
def on_stream_close(stream_id, error_code)
|
139
178
|
GrpcKit.logger.debug("on_stream_close stream_id=#{stream_id}, error_code=#{error_code}")
|
140
|
-
@streams.delete(stream_id)
|
141
|
-
|
179
|
+
stream = @streams.delete(stream_id)
|
180
|
+
return unless stream
|
142
181
|
|
143
|
-
|
144
|
-
def on_data_chunk_recv(stream_id, data, _flags)
|
145
|
-
@handler.on_data_chunk_recv(@streams[stream_id], data)
|
182
|
+
stream.end_stream
|
146
183
|
end
|
147
184
|
|
148
|
-
#
|
149
|
-
def
|
150
|
-
|
151
|
-
|
185
|
+
# nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
186
|
+
def on_data_chunk_recv(stream_id, data, _flags)
|
187
|
+
stream = @streams[stream_id]
|
188
|
+
if stream
|
189
|
+
stream.pending_recv_data.write(data)
|
190
|
+
end
|
152
191
|
end
|
153
192
|
end
|
154
193
|
end
|
@@ -1,67 +1,59 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'forwardable'
|
4
|
+
require 'grpc_kit/session/buffer'
|
5
|
+
require 'grpc_kit/session/headers'
|
4
6
|
|
5
7
|
module GrpcKit
|
6
8
|
module Session
|
7
9
|
class Stream
|
8
|
-
|
9
|
-
attr_accessor :data
|
10
|
+
extend Forwardable
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
@end_read_stream = end_read_stream
|
14
|
-
@end_write_stream = end_write_stream
|
15
|
-
@end_stream = false
|
16
|
-
@headers = {}
|
17
|
-
|
18
|
-
@data = ''
|
19
|
-
@write_data = StringIO.new
|
20
|
-
end
|
12
|
+
delegate end_write: :@pending_send_data
|
13
|
+
delegate end_read: :@pending_recv_data
|
21
14
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
15
|
+
attr_reader :headers, :pending_send_data, :pending_recv_data
|
16
|
+
attr_accessor :local_end_stream, :remote_end_stream, :inflight, :stream_id
|
25
17
|
|
26
|
-
def
|
27
|
-
@
|
28
|
-
|
18
|
+
def initialize(stream_id:, send_data: GrpcKit::Session::Buffer.new)
|
19
|
+
@stream_id = stream_id
|
20
|
+
@end_read_stream = false
|
21
|
+
@headers = GrpcKit::Session::Headers.new
|
22
|
+
@pending_send_data = send_data
|
23
|
+
@pending_recv_data = GrpcKit::Session::Buffer.new
|
29
24
|
|
30
|
-
|
31
|
-
@
|
25
|
+
@local_end_stream = false
|
26
|
+
@remote_end_stream = false
|
27
|
+
@inflight = false
|
32
28
|
end
|
33
29
|
|
34
|
-
def
|
35
|
-
|
30
|
+
def write_send_data(data, last: false)
|
31
|
+
@pending_send_data.write(data, last: last)
|
36
32
|
end
|
37
33
|
|
38
|
-
def
|
39
|
-
@
|
34
|
+
def read_recv_data(last: false)
|
35
|
+
@pending_recv_data.read(last: last)
|
40
36
|
end
|
41
37
|
|
42
|
-
|
43
|
-
|
44
|
-
@data << data
|
38
|
+
def end_write?
|
39
|
+
@local_end_stream || @pending_send_data.end_write?
|
45
40
|
end
|
46
41
|
|
47
|
-
|
48
|
-
|
49
|
-
@write_data = data
|
50
|
-
# @write_data.write(data)
|
42
|
+
def end_read?
|
43
|
+
@remote_end_stream || @pending_recv_data.end_read?
|
51
44
|
end
|
52
45
|
|
53
|
-
|
54
|
-
|
55
|
-
# @write_data.rewind
|
56
|
-
@write_data.read(len)
|
46
|
+
def end_stream?
|
47
|
+
end_read? && end_write?
|
57
48
|
end
|
58
49
|
|
59
|
-
def
|
60
|
-
|
50
|
+
def end_stream
|
51
|
+
end_read
|
52
|
+
end_write
|
61
53
|
end
|
62
54
|
|
63
|
-
def
|
64
|
-
@
|
55
|
+
def add_header(name, value)
|
56
|
+
@headers.add(name, value)
|
65
57
|
end
|
66
58
|
end
|
67
59
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'grpc_kit/streams/packable'
|
5
|
+
|
6
|
+
module GrpcKit
|
7
|
+
class Stream
|
8
|
+
include GrpcKit::Streams::Packable
|
9
|
+
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
delegate %i[stream_id end_write end_read end_write? end_read?] => :@stream
|
13
|
+
|
14
|
+
# @params protobuf [GrpcKit::Protobuffer]
|
15
|
+
# @params session [GrpcKit::Session::Server|GrpcKit::Session::Client]
|
16
|
+
# @params stream [GrpcKit::Session::Stream] primitive H2 stream id
|
17
|
+
def initialize(protobuf:, session:, stream:)
|
18
|
+
@protobuf = protobuf
|
19
|
+
@session = session
|
20
|
+
@stream = stream
|
21
|
+
end
|
22
|
+
|
23
|
+
def each
|
24
|
+
loop { yield(recv) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def send(data, last: false)
|
28
|
+
req = @protobuf.encode(data)
|
29
|
+
@stream.write_send_data(pack(req), last: last)
|
30
|
+
end
|
31
|
+
|
32
|
+
def recv(last: false)
|
33
|
+
data = unpack(read(last: last))
|
34
|
+
|
35
|
+
unless data
|
36
|
+
raise StopIteration
|
37
|
+
end
|
38
|
+
|
39
|
+
compressed, size, buf = *data
|
40
|
+
|
41
|
+
unless size == buf.size
|
42
|
+
raise "inconsistent data: #{buf}"
|
43
|
+
end
|
44
|
+
|
45
|
+
if compressed
|
46
|
+
raise 'compress option is unsupported'
|
47
|
+
end
|
48
|
+
|
49
|
+
@protobuf.decode(buf)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def read(last: false)
|
55
|
+
loop do
|
56
|
+
data = @stream.read_recv_data(last: last)
|
57
|
+
if data.empty?
|
58
|
+
# Consider `end_read` is set in this invocation
|
59
|
+
if @stream.end_read? && !last
|
60
|
+
return nil
|
61
|
+
end
|
62
|
+
|
63
|
+
@session.run_once
|
64
|
+
redo
|
65
|
+
end
|
66
|
+
|
67
|
+
return data
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'grpc_kit/stream'
|
4
|
+
require 'grpc_kit/streams/send_buffer'
|
5
|
+
|
6
|
+
module GrpcKit
|
7
|
+
module Streams
|
8
|
+
class Client
|
9
|
+
def initialize(path:, protobuf:, session:, authority:)
|
10
|
+
@path = path
|
11
|
+
@session = session
|
12
|
+
@protobuf = protobuf
|
13
|
+
@stream = nil
|
14
|
+
@authority = authority
|
15
|
+
end
|
16
|
+
|
17
|
+
def send_msg(data, metadata: {}, timeout: nil, last: false)
|
18
|
+
if @stream
|
19
|
+
unless @stream.end_write?
|
20
|
+
@session.resume_data(@stream.stream_id)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
headers = build_headers(metadata: metadata, timeout: timeout)
|
24
|
+
stream = @session.start_request(GrpcKit::Streams::SendBuffer.new, headers)
|
25
|
+
@stream = GrpcKit::Stream.new(protobuf: @protobuf, session: @session, stream: stream)
|
26
|
+
end
|
27
|
+
|
28
|
+
@stream.send(data, last: last)
|
29
|
+
@session.run_once
|
30
|
+
end
|
31
|
+
|
32
|
+
def each(&block)
|
33
|
+
unless @stream
|
34
|
+
raise 'You should call `send` method to send data'
|
35
|
+
end
|
36
|
+
|
37
|
+
@stream.each(&block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def recv(last: false)
|
41
|
+
unless @stream
|
42
|
+
raise 'You should call `send` method to send data'
|
43
|
+
end
|
44
|
+
|
45
|
+
@stream.recv(last: last)
|
46
|
+
end
|
47
|
+
|
48
|
+
def close_and_recv
|
49
|
+
unless @stream
|
50
|
+
raise 'You should call `send` method to send data'
|
51
|
+
end
|
52
|
+
|
53
|
+
unless @stream.end_write?
|
54
|
+
@session.resume_data(@stream.stream_id)
|
55
|
+
end
|
56
|
+
|
57
|
+
@stream.end_write
|
58
|
+
@session.start(@stream.stream_id)
|
59
|
+
@stream.end_read
|
60
|
+
|
61
|
+
data = []
|
62
|
+
@stream.each { |d| data.push(d) }
|
63
|
+
data
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def build_headers(metadata: {}, timeout: nil, **headers)
|
69
|
+
hdrs = metadata.merge(headers).merge(
|
70
|
+
':method' => 'POST',
|
71
|
+
':scheme' => 'http',
|
72
|
+
':path' => @path,
|
73
|
+
':authority' => @authority,
|
74
|
+
'te' => 'trailers',
|
75
|
+
'content-type' => 'application/grpc',
|
76
|
+
'user-agent' => "grpc-ruby/#{GrpcKit::VERSION} (grpc_kit)",
|
77
|
+
'grpc-accept-encoding' => 'identity,deflate,gzip',
|
78
|
+
)
|
79
|
+
if timeout
|
80
|
+
hdrs['grpc-timeout'] = timeout
|
81
|
+
end
|
82
|
+
|
83
|
+
hdrs
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|