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
@@ -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
|
data/lib/grpc_kit/rpc_desc.rb
CHANGED
@@ -1,65 +1,141 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'grpc_kit/
|
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:,
|
10
|
+
def initialize(name:, marshal:, unmarshal:, marshal_method:, unmarshal_method:, service_name:)
|
8
11
|
@name = name
|
9
|
-
@
|
10
|
-
@
|
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
|
16
|
-
|
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
|
-
|
28
|
-
|
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
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
42
|
-
"/#{service_name}/#{@name}"
|
49
|
+
def path
|
50
|
+
@path ||= "/#{@service_name}/#{@name}"
|
43
51
|
end
|
44
52
|
|
45
53
|
def request_response?
|
46
|
-
!@
|
54
|
+
!@marshal.is_a?(GrpcKit::GRPC::Stream) && !@unmarshal.is_a?(GrpcKit::GRPC::Stream)
|
47
55
|
end
|
48
56
|
|
49
57
|
def client_streamer?
|
50
|
-
@
|
58
|
+
@marshal.is_a?(GrpcKit::GRPC::Stream) && !@unmarshal.is_a?(GrpcKit::GRPC::Stream)
|
51
59
|
end
|
52
60
|
|
53
61
|
def server_streamer?
|
54
|
-
!@
|
62
|
+
!@marshal.is_a?(GrpcKit::GRPC::Stream) && @unmarshal.is_a?(GrpcKit::GRPC::Stream)
|
55
63
|
end
|
56
64
|
|
57
65
|
def bidi_streamer?
|
58
|
-
@
|
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,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
|
data/lib/grpc_kit/server.rb
CHANGED
@@ -1,76 +1,57 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'grpc_kit/io
|
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
|
-
|
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 #{
|
18
|
+
raise "Duplicated method registered #{path}, class: #{handler}"
|
22
19
|
end
|
23
20
|
|
24
|
-
@rpc_descs[path] =
|
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
|
-
|
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
|
40
|
-
session = GrpcKit::Session::Server.new(
|
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
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
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
|