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.
- 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
|