istox_gruf 2.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +246 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/README.md +544 -0
- data/bin/gruf +29 -0
- data/lib/gruf.rb +50 -0
- data/lib/gruf/cli/executor.rb +99 -0
- data/lib/gruf/client.rb +217 -0
- data/lib/gruf/client/error.rb +66 -0
- data/lib/gruf/client/error_factory.rb +105 -0
- data/lib/gruf/configuration.rb +137 -0
- data/lib/gruf/controllers/base.rb +102 -0
- data/lib/gruf/controllers/request.rb +121 -0
- data/lib/gruf/controllers/service_binder.rb +117 -0
- data/lib/gruf/error.rb +230 -0
- data/lib/gruf/errors/debug_info.rb +56 -0
- data/lib/gruf/errors/field.rb +56 -0
- data/lib/gruf/errors/helpers.rb +44 -0
- data/lib/gruf/hooks/base.rb +34 -0
- data/lib/gruf/hooks/executor.rb +47 -0
- data/lib/gruf/hooks/registry.rb +159 -0
- data/lib/gruf/instrumentable_grpc_server.rb +64 -0
- data/lib/gruf/integrations/rails/railtie.rb +10 -0
- data/lib/gruf/interceptors/active_record/connection_reset.rb +48 -0
- data/lib/gruf/interceptors/authentication/basic.rb +87 -0
- data/lib/gruf/interceptors/base.rb +53 -0
- data/lib/gruf/interceptors/client_interceptor.rb +125 -0
- data/lib/gruf/interceptors/context.rb +56 -0
- data/lib/gruf/interceptors/instrumentation/output_metadata_timer.rb +61 -0
- data/lib/gruf/interceptors/instrumentation/request_logging/formatters/base.rb +41 -0
- data/lib/gruf/interceptors/instrumentation/request_logging/formatters/logstash.rb +43 -0
- data/lib/gruf/interceptors/instrumentation/request_logging/formatters/plain.rb +48 -0
- data/lib/gruf/interceptors/instrumentation/request_logging/interceptor.rb +225 -0
- data/lib/gruf/interceptors/instrumentation/statsd.rb +82 -0
- data/lib/gruf/interceptors/registry.rb +161 -0
- data/lib/gruf/interceptors/server_interceptor.rb +34 -0
- data/lib/gruf/interceptors/timer.rb +85 -0
- data/lib/gruf/loggable.rb +30 -0
- data/lib/gruf/logging.rb +53 -0
- data/lib/gruf/outbound/request_context.rb +71 -0
- data/lib/gruf/response.rb +71 -0
- data/lib/gruf/serializers/errors/base.rb +57 -0
- data/lib/gruf/serializers/errors/json.rb +43 -0
- data/lib/gruf/server.rb +294 -0
- data/lib/gruf/synchronized_client.rb +97 -0
- data/lib/gruf/timer.rb +78 -0
- data/lib/gruf/version.rb +20 -0
- metadata +203 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
6
|
+
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
7
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
8
|
+
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
11
|
+
# Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
14
|
+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
15
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
16
|
+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
17
|
+
#
|
18
|
+
module Gruf
|
19
|
+
module Outbound
|
20
|
+
##
|
21
|
+
# Encapsulates the context of an outbound client request
|
22
|
+
#
|
23
|
+
class RequestContext
|
24
|
+
# @var [Symbol]
|
25
|
+
attr_reader :type
|
26
|
+
# @var [Enumerable] requests
|
27
|
+
attr_reader :requests
|
28
|
+
# @var [GRPC::ActiveCall]
|
29
|
+
attr_reader :call
|
30
|
+
# @var [Method] method
|
31
|
+
attr_reader :method
|
32
|
+
# @var [Hash] metadata
|
33
|
+
attr_reader :metadata
|
34
|
+
|
35
|
+
##
|
36
|
+
# Initialize the new request context
|
37
|
+
#
|
38
|
+
# @param [Symbol] type The type of request
|
39
|
+
# @param [Enumerable] requests An enumerable of requests being sent
|
40
|
+
# @param [GRPC::ActiveCall] call The GRPC ActiveCall object
|
41
|
+
# @param [Method] method The method being called
|
42
|
+
# @param [Hash] metadata A hash of outgoing metadata
|
43
|
+
#
|
44
|
+
def initialize(type:, requests:, call:, method:, metadata:)
|
45
|
+
@type = type
|
46
|
+
@requests = requests
|
47
|
+
@call = call
|
48
|
+
@method = method
|
49
|
+
@metadata = metadata
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Return the name of the method being called, e.g. GetThing
|
54
|
+
#
|
55
|
+
# @return [String]
|
56
|
+
#
|
57
|
+
def method_name
|
58
|
+
@method.to_s.split('/').last
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Return the proper routing key for the request
|
63
|
+
#
|
64
|
+
# @return [String]
|
65
|
+
#
|
66
|
+
def route_key
|
67
|
+
@method[1..-1].underscore.tr('/', '.')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
6
|
+
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
7
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
8
|
+
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
11
|
+
# Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
14
|
+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
15
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
16
|
+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
17
|
+
#
|
18
|
+
module Gruf
|
19
|
+
##
|
20
|
+
# Wraps the active call operation to provide metadata and timing around the request
|
21
|
+
#
|
22
|
+
class Response
|
23
|
+
# @return [GRPC::ActiveCall::Operation] The operation that was executed for the given request
|
24
|
+
attr_reader :operation
|
25
|
+
# @return [Hash] The metadata that was attached to the operation
|
26
|
+
attr_reader :metadata
|
27
|
+
# @return [Hash] The trailing metadata that the service returned
|
28
|
+
attr_reader :trailing_metadata
|
29
|
+
# @return [Time] The set deadline on the call
|
30
|
+
attr_reader :deadline
|
31
|
+
# @return [Boolean] Whether or not the operation was cancelled
|
32
|
+
attr_reader :cancelled
|
33
|
+
# @return [Float] The time that the request took to execute
|
34
|
+
attr_reader :execution_time
|
35
|
+
|
36
|
+
##
|
37
|
+
# Initialize a response object with the given gRPC operation
|
38
|
+
#
|
39
|
+
# @param [GRPC::ActiveCall::Operation] operation The given operation for the current call
|
40
|
+
# @param [StdClass] message
|
41
|
+
# @param [Float] execution_time The amount of time that the response took to occur
|
42
|
+
#
|
43
|
+
def initialize(operation:, message:, execution_time: nil)
|
44
|
+
@operation = operation
|
45
|
+
@message = message
|
46
|
+
@metadata = operation.metadata
|
47
|
+
@trailing_metadata = operation.trailing_metadata
|
48
|
+
@deadline = operation.deadline
|
49
|
+
@cancelled = operation.cancelled?
|
50
|
+
@execution_time = execution_time || 0.0
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Return the message returned by the request
|
55
|
+
#
|
56
|
+
# @return [Object] The protobuf response message
|
57
|
+
#
|
58
|
+
def message
|
59
|
+
@message ||= @operation.execute
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Return execution time of the call internally on the server in ms
|
64
|
+
#
|
65
|
+
# @return [Float] The execution time of the response
|
66
|
+
#
|
67
|
+
def internal_execution_time
|
68
|
+
trailing_metadata['timer'].to_f
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
6
|
+
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
7
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
8
|
+
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
11
|
+
# Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
14
|
+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
15
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
16
|
+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
17
|
+
#
|
18
|
+
module Gruf
|
19
|
+
module Serializers
|
20
|
+
module Errors
|
21
|
+
##
|
22
|
+
# Base class for serialization of errors for transport across the grpc protocol
|
23
|
+
#
|
24
|
+
class Base
|
25
|
+
# @return [Gruf::Error|String] The error being serialized
|
26
|
+
attr_reader :error
|
27
|
+
|
28
|
+
##
|
29
|
+
# @param [Gruf::Error|String] err The error to serialize
|
30
|
+
#
|
31
|
+
def initialize(err)
|
32
|
+
@error = err
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Must be implemented in a derived class. This method should serialize the error into a transportable String
|
37
|
+
# that can be pushed into GRPC metadata across the wire.
|
38
|
+
#
|
39
|
+
# @return [String] The serialized error
|
40
|
+
#
|
41
|
+
def serialize
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Must be implemented in a derived class. This method should deserialize the error object that is transported
|
47
|
+
# over the gRPC trailing metadata payload.
|
48
|
+
#
|
49
|
+
# @return [Object|Hash] The deserialized error object
|
50
|
+
#
|
51
|
+
def deserialize
|
52
|
+
raise NotImplementedError
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
6
|
+
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
7
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
8
|
+
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
11
|
+
# Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
14
|
+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
15
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
16
|
+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
17
|
+
#
|
18
|
+
require 'json'
|
19
|
+
|
20
|
+
module Gruf
|
21
|
+
module Serializers
|
22
|
+
module Errors
|
23
|
+
##
|
24
|
+
# Serializes the error via JSON for transport
|
25
|
+
#
|
26
|
+
class Json < Base
|
27
|
+
##
|
28
|
+
# @return [String] The serialized JSON string
|
29
|
+
#
|
30
|
+
def serialize
|
31
|
+
@error.to_h.to_json
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# @return [Hash] A hash deserialized from the inputted JSON
|
36
|
+
#
|
37
|
+
def deserialize
|
38
|
+
JSON.parse(@error)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/gruf/server.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
6
|
+
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
7
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
8
|
+
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
11
|
+
# Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
14
|
+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
15
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
16
|
+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
17
|
+
#
|
18
|
+
module Gruf
|
19
|
+
##
|
20
|
+
# Represents a gRPC server. Automatically loads and augments gRPC handlers and services
|
21
|
+
# based on configuration values.
|
22
|
+
#
|
23
|
+
class Server
|
24
|
+
class ServerAlreadyStartedError < StandardError; end
|
25
|
+
|
26
|
+
include Gruf::Loggable
|
27
|
+
|
28
|
+
# @return [Integer] The port the server is bound to
|
29
|
+
attr_reader :port
|
30
|
+
# @return [Hash] Hash of options passed into the server
|
31
|
+
attr_reader :options
|
32
|
+
|
33
|
+
##
|
34
|
+
# Initialize the server and load and setup the services
|
35
|
+
#
|
36
|
+
# @param [Hash] opts
|
37
|
+
#
|
38
|
+
def initialize(opts = {})
|
39
|
+
init(opts)
|
40
|
+
end
|
41
|
+
|
42
|
+
def init(opts = {})
|
43
|
+
@options = opts || {}
|
44
|
+
@interceptors = opts.fetch(:interceptor_registry, Gruf.interceptors)
|
45
|
+
@interceptors = Gruf::Interceptors::Registry.new unless @interceptors.is_a?(Gruf::Interceptors::Registry)
|
46
|
+
@services = []
|
47
|
+
@started = false
|
48
|
+
@stop_server = false
|
49
|
+
@stop_server_cv = ConditionVariable.new
|
50
|
+
@stop_server_mu = Monitor.new
|
51
|
+
@server_mu = Monitor.new
|
52
|
+
@hostname = opts.fetch(:hostname, Gruf.server_binding_url)
|
53
|
+
@event_listener_proc = opts.fetch(:event_listener_proc, Gruf.event_listener_proc)
|
54
|
+
setup
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# @return [GRPC::RpcServer] The GRPC server running
|
59
|
+
#
|
60
|
+
def server
|
61
|
+
@server_mu.synchronize do
|
62
|
+
@server ||= begin
|
63
|
+
# For backward compatibility, we allow these options to be passed directly
|
64
|
+
# in the Gruf::Server options, or via Gruf.rpc_server_options.
|
65
|
+
server_options = {
|
66
|
+
pool_size: options.fetch(:pool_size, Gruf.rpc_server_options[:pool_size]),
|
67
|
+
max_waiting_requests: options.fetch(:max_waiting_requests, Gruf.rpc_server_options[:max_waiting_requests]),
|
68
|
+
poll_period: options.fetch(:poll_period, Gruf.rpc_server_options[:poll_period]),
|
69
|
+
pool_keep_alive: options.fetch(:pool_keep_alive, Gruf.rpc_server_options[:pool_keep_alive]),
|
70
|
+
connect_md_proc: options.fetch(:connect_md_proc, Gruf.rpc_server_options[:connect_md_proc]),
|
71
|
+
server_args: options.fetch(:server_args, Gruf.rpc_server_options[:server_args])
|
72
|
+
}
|
73
|
+
|
74
|
+
server = if @event_listener_proc
|
75
|
+
server_options[:event_listener_proc] = @event_listener_proc
|
76
|
+
Gruf::InstrumentableGrpcServer.new(server_options)
|
77
|
+
else
|
78
|
+
GRPC::RpcServer.new(server_options)
|
79
|
+
end
|
80
|
+
|
81
|
+
@port = server.add_http2_port(@hostname, ssl_credentials)
|
82
|
+
@services.each { |s| server.handle(s) }
|
83
|
+
server
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Start the gRPC server
|
90
|
+
#
|
91
|
+
# :nocov:
|
92
|
+
def start!
|
93
|
+
update_proc_title(:starting)
|
94
|
+
|
95
|
+
server_thread = Thread.new do
|
96
|
+
logger.info { "Starting gruf server at #{@hostname}..." }
|
97
|
+
server.run
|
98
|
+
end
|
99
|
+
|
100
|
+
stop_server_thread = Thread.new do
|
101
|
+
loop do
|
102
|
+
break if @stop_server
|
103
|
+
|
104
|
+
@stop_server_mu.synchronize { @stop_server_cv.wait(@stop_server_mu, 2) }
|
105
|
+
end
|
106
|
+
logger.info { 'Shutting down...' }
|
107
|
+
server.stop
|
108
|
+
end
|
109
|
+
|
110
|
+
server.wait_till_running
|
111
|
+
@started = true
|
112
|
+
update_proc_title(:serving)
|
113
|
+
stop_server_thread.join
|
114
|
+
server_thread.join
|
115
|
+
@started = false
|
116
|
+
|
117
|
+
update_proc_title(:stopped)
|
118
|
+
logger.info { 'Goodbye!' }
|
119
|
+
end
|
120
|
+
|
121
|
+
def init_restart
|
122
|
+
logger.info { 'Restarting gruf...' }
|
123
|
+
@restart = true
|
124
|
+
@stop_server = true
|
125
|
+
end
|
126
|
+
|
127
|
+
def required_restart
|
128
|
+
@restart
|
129
|
+
end
|
130
|
+
|
131
|
+
# :nocov:
|
132
|
+
|
133
|
+
##
|
134
|
+
# Add a gRPC service stub to be served by gruf
|
135
|
+
#
|
136
|
+
# @param [Class] klass
|
137
|
+
# @raise [ServerAlreadyStartedError] if the server is already started
|
138
|
+
#
|
139
|
+
def add_service(klass)
|
140
|
+
raise ServerAlreadyStartedError if @started
|
141
|
+
|
142
|
+
@services << klass unless @services.include?(klass)
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# Add an interceptor to the server
|
147
|
+
#
|
148
|
+
# @param [Class] klass The Interceptor to add to the registry
|
149
|
+
# @param [Hash] opts A hash of options for the interceptor
|
150
|
+
# @raise [ServerAlreadyStartedError] if the server is already started
|
151
|
+
#
|
152
|
+
def add_interceptor(klass, opts = {})
|
153
|
+
raise ServerAlreadyStartedError if @started
|
154
|
+
|
155
|
+
@interceptors.use(klass, opts)
|
156
|
+
end
|
157
|
+
|
158
|
+
##
|
159
|
+
# Insert an interceptor before another in the currently registered order of execution
|
160
|
+
#
|
161
|
+
# @param [Class] before_class The interceptor that you want to add the new interceptor before
|
162
|
+
# @param [Class] interceptor_class The Interceptor to add to the registry
|
163
|
+
# @param [Hash] opts A hash of options for the interceptor
|
164
|
+
#
|
165
|
+
def insert_interceptor_before(before_class, interceptor_class, opts = {})
|
166
|
+
raise ServerAlreadyStartedError if @started
|
167
|
+
|
168
|
+
@interceptors.insert_before(before_class, interceptor_class, opts)
|
169
|
+
end
|
170
|
+
|
171
|
+
##
|
172
|
+
# Insert an interceptor after another in the currently registered order of execution
|
173
|
+
#
|
174
|
+
# @param [Class] after_class The interceptor that you want to add the new interceptor after
|
175
|
+
# @param [Class] interceptor_class The Interceptor to add to the registry
|
176
|
+
# @param [Hash] opts A hash of options for the interceptor
|
177
|
+
#
|
178
|
+
def insert_interceptor_after(after_class, interceptor_class, opts = {})
|
179
|
+
raise ServerAlreadyStartedError if @started
|
180
|
+
|
181
|
+
@interceptors.insert_after(after_class, interceptor_class, opts)
|
182
|
+
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# Return the current list of added interceptor classes
|
186
|
+
#
|
187
|
+
# @return [Array<Class>]
|
188
|
+
#
|
189
|
+
def list_interceptors
|
190
|
+
@interceptors.list
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# Remove an interceptor from the server
|
195
|
+
#
|
196
|
+
# @param [Class] klass
|
197
|
+
#
|
198
|
+
def remove_interceptor(klass)
|
199
|
+
raise ServerAlreadyStartedError if @started
|
200
|
+
|
201
|
+
@interceptors.remove(klass)
|
202
|
+
end
|
203
|
+
|
204
|
+
##
|
205
|
+
# Clear the interceptor registry of interceptors
|
206
|
+
#
|
207
|
+
def clear_interceptors
|
208
|
+
raise ServerAlreadyStartedError if @started
|
209
|
+
|
210
|
+
@interceptors.clear
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
|
215
|
+
##
|
216
|
+
# Setup server
|
217
|
+
#
|
218
|
+
# :nocov:
|
219
|
+
def setup
|
220
|
+
setup_signal_handlers
|
221
|
+
load_controllers
|
222
|
+
end
|
223
|
+
# :nocov:
|
224
|
+
|
225
|
+
##
|
226
|
+
# Register signal handlers
|
227
|
+
#
|
228
|
+
# :nocov:
|
229
|
+
def setup_signal_handlers
|
230
|
+
Signal.trap('INT') do
|
231
|
+
@stop_server = true
|
232
|
+
@stop_server_cv.broadcast
|
233
|
+
end
|
234
|
+
|
235
|
+
Signal.trap('TERM') do
|
236
|
+
@stop_server = true
|
237
|
+
@stop_server_cv.broadcast
|
238
|
+
end
|
239
|
+
end
|
240
|
+
# :nocov:
|
241
|
+
|
242
|
+
##
|
243
|
+
# Auto-load all gRPC handlers
|
244
|
+
#
|
245
|
+
# :nocov:
|
246
|
+
def load_controllers
|
247
|
+
return unless File.directory?(controllers_path)
|
248
|
+
|
249
|
+
path = File.realpath(controllers_path)
|
250
|
+
$LOAD_PATH.unshift(path)
|
251
|
+
Dir["#{path}/**/*.rb"].each do |f|
|
252
|
+
next if f.include?('_pb') # exclude if people include proto generated files in app/rpc
|
253
|
+
|
254
|
+
logger.info "- Loading gRPC service file: #{f}"
|
255
|
+
load File.realpath(f)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
# :nocov:
|
259
|
+
|
260
|
+
##
|
261
|
+
# @param [String]
|
262
|
+
#
|
263
|
+
def controllers_path
|
264
|
+
options.fetch(:controllers_path, Gruf.controllers_path)
|
265
|
+
end
|
266
|
+
|
267
|
+
##
|
268
|
+
# Load the SSL/TLS credentials for this server
|
269
|
+
#
|
270
|
+
# @return [GRPC::Core::ServerCredentials|Symbol]
|
271
|
+
#
|
272
|
+
# :nocov:
|
273
|
+
def ssl_credentials
|
274
|
+
return :this_port_is_insecure unless options.fetch(:use_ssl, Gruf.use_ssl)
|
275
|
+
|
276
|
+
private_key = File.read(options.fetch(:ssl_key_file, Gruf.ssl_key_file))
|
277
|
+
cert_chain = File.read(options.fetch(:ssl_crt_file, Gruf.ssl_crt_file))
|
278
|
+
certs = [nil, [{ private_key: private_key, cert_chain: cert_chain }], false]
|
279
|
+
GRPC::Core::ServerCredentials.new(*certs)
|
280
|
+
end
|
281
|
+
# :nocov:
|
282
|
+
|
283
|
+
##
|
284
|
+
# Updates proc name/title
|
285
|
+
#
|
286
|
+
# @param [Symbol] state
|
287
|
+
#
|
288
|
+
# :nocov:
|
289
|
+
def update_proc_title(state)
|
290
|
+
Process.setproctitle("gruf #{Gruf::VERSION} -- #{state}")
|
291
|
+
end
|
292
|
+
# :nocov:
|
293
|
+
end
|
294
|
+
end
|