istox_gruf 2.7.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 +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
|