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