clamo 0.6.0 → 0.8.0
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 +9 -0
- data/CHANGELOG.md +39 -0
- data/LICENSE +21 -0
- data/README.md +73 -6
- data/lib/clamo/jsonrpc.rb +28 -20
- data/lib/clamo/server.rb +89 -32
- data/lib/clamo/version.rb +1 -1
- data/lib/clamo.rb +0 -1
- metadata +6 -4
- data/sig/clamo.rbs +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 97084b2761bd6af3549fd2444f981da0a23ce6f1ebbc740f4c2fb237e90ee1fe
|
|
4
|
+
data.tar.gz: dde0cc4f7187bc58aeb2d1be4169f3cc6331d4008c7a10539317cb80e2a68480
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 18a87542a9340025ff18f60594ae32e941bca85f4f268c2dd99ca207dc2c4296c74f2809531e7e43034f27219b4d43fec4f380f61def8e37af6477fa979c273e
|
|
7
|
+
data.tar.gz: 976d81d554ff643ddfcbbaa5185094fda802657b5adee586d60e7c31e7aee27b0f6f141263f23dc8ebbc4d7b0a288beb3e1dc78a41b4209c18c266f2c64931a8
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,45 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [0.8.0] - 2026-03-14
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `before_dispatch` and `after_dispatch` hooks — run around every method call (requests and notifications). Raise in `before_dispatch` to halt execution; `after_dispatch` fires only on success with `(method, params, result)`.
|
|
12
|
+
- Per-call configuration — `timeout`, `on_error`, `before_dispatch`, and `after_dispatch` can be passed as keyword arguments to `handle`, `unparsed_dispatch_to_object`, and `parsed_dispatch_to_object`, overriding module-level defaults.
|
|
13
|
+
- `Clamo::Server::Config` — immutable `Data` struct that snapshots configuration at the start of each dispatch, eliminating race conditions from concurrent mutations to module-level settings.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Internal error responses no longer include `e.message` in the `data` field, preventing leakage of internal details to clients. Exceptions are routed through `on_error` instead.
|
|
18
|
+
- `parsed_dispatch_to_object` normalizes request keys to strings at the boundary, fixing silent dispatch failures when callers pass symbol-key hashes.
|
|
19
|
+
- `on_error` is now called for request dispatch errors (previously only for notification errors).
|
|
20
|
+
- Test suite expanded to 95 tests / 138 assertions.
|
|
21
|
+
|
|
22
|
+
## [0.7.0] - 2026-03-14
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- `Clamo::Server.timeout` — per-dispatch timeout with 30-second default; returns `-32000 Server error` on timeout for requests, calls `on_error` for notifications. Set to `nil` to disable.
|
|
27
|
+
- MIT LICENSE file and `spec.license` in gemspec
|
|
28
|
+
- Indifferent key access in JSONRPC validators (symbol and string keys both accepted)
|
|
29
|
+
- Tests for string ids, arity mismatch, single-item batches, and handle+timeout (77 tests / 105 assertions)
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- `proper_pragma?`, `proper_method?`, `proper_id_if_any?` moved from public to private API on `Clamo::JSONRPC`
|
|
34
|
+
- Notifications with invalid params type now return `nil` instead of an error response (spec compliance)
|
|
35
|
+
- `parsed_dispatch_to_object` now validates `object:` argument (raises `ArgumentError` if nil)
|
|
36
|
+
- Single-item batches skip `Parallel.map` overhead
|
|
37
|
+
- Gemspec description expanded (no longer identical to summary)
|
|
38
|
+
- README updated with `Server.handle`, `timeout`, and `on_error` documentation
|
|
39
|
+
|
|
40
|
+
### Removed
|
|
41
|
+
|
|
42
|
+
- `Clamo::Error` base exception class (unused)
|
|
43
|
+
- `sig/clamo.rbs` type signatures (misleadingly incomplete)
|
|
44
|
+
- Dead `else` branch in `dispatch_to_ruby`
|
|
45
|
+
|
|
7
46
|
## [0.6.0] - 2026-03-14
|
|
8
47
|
|
|
9
48
|
### Added
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Andriy Tyurnikov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
|
@@ -26,15 +26,30 @@ module MyService
|
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
request:
|
|
29
|
+
# JSON string in, JSON string out — the primary entry point for HTTP/socket integrations.
|
|
30
|
+
# Returns nil for notifications (no response expected).
|
|
31
|
+
json_response = Clamo::Server.handle(
|
|
32
|
+
request: '{"jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": 1}',
|
|
33
33
|
object: MyService
|
|
34
34
|
)
|
|
35
|
+
# => '{"jsonrpc":"2.0","result":3,"id":1}'
|
|
36
|
+
```
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
If you need the parsed hash instead of a JSON string, use the lower-level methods:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
# From a JSON string
|
|
42
|
+
response = Clamo::Server.unparsed_dispatch_to_object(
|
|
43
|
+
request: '{"jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": 1}',
|
|
44
|
+
object: MyService
|
|
45
|
+
)
|
|
37
46
|
# => {jsonrpc: "2.0", result: 3, id: 1}
|
|
47
|
+
|
|
48
|
+
# From a pre-parsed hash
|
|
49
|
+
response = Clamo::Server.parsed_dispatch_to_object(
|
|
50
|
+
request: { "jsonrpc" => "2.0", "method" => "add", "params" => [1, 2], "id" => 1 },
|
|
51
|
+
object: MyService
|
|
52
|
+
)
|
|
38
53
|
```
|
|
39
54
|
|
|
40
55
|
### Handling Different Parameter Types
|
|
@@ -113,11 +128,63 @@ Clamo follows the JSON-RPC 2.0 specification for error handling:
|
|
|
113
128
|
| -32603 | Internal error | Internal JSON-RPC error |
|
|
114
129
|
| -32000 | Server error | Reserved for implementation-defined server errors |
|
|
115
130
|
|
|
131
|
+
## Configuration
|
|
132
|
+
|
|
133
|
+
### Timeout
|
|
134
|
+
|
|
135
|
+
Every method dispatch is wrapped in a timeout. The default is 30 seconds. Timed-out requests return a `-32000 Server error` response.
|
|
136
|
+
|
|
137
|
+
```ruby
|
|
138
|
+
Clamo::Server.timeout = 10 # seconds
|
|
139
|
+
Clamo::Server.timeout = nil # disable timeout
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Error Callback
|
|
143
|
+
|
|
144
|
+
Errors during dispatch are reported through `on_error`. Notifications are silent by default (no response is sent); requests return a generic `-32603 Internal error` without leaking exception details. Use `on_error` to capture the full exception for logging:
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
Clamo::Server.on_error = ->(exception, method, params) {
|
|
148
|
+
Rails.logger.error("#{method} failed: #{exception.message}")
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Dispatch Hooks
|
|
153
|
+
|
|
154
|
+
`before_dispatch` and `after_dispatch` run around every method call (requests and notifications). Raise in `before_dispatch` to halt execution:
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
Clamo::Server.before_dispatch = ->(method, params) {
|
|
158
|
+
raise "unauthorized" unless allowed?(method)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
Clamo::Server.after_dispatch = ->(method, params, result) {
|
|
162
|
+
Rails.logger.info("#{method} completed")
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Per-Call Configuration
|
|
167
|
+
|
|
168
|
+
All configuration options can be overridden per-call. Module-level settings serve as defaults:
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
Clamo::Server.handle(
|
|
172
|
+
request: body,
|
|
173
|
+
object: MyService,
|
|
174
|
+
timeout: 5,
|
|
175
|
+
on_error: ->(e, method, params) { MyLogger.error(e) },
|
|
176
|
+
before_dispatch: ->(method, params) { authorize!(method) },
|
|
177
|
+
after_dispatch: ->(method, params, result) { track(method) }
|
|
178
|
+
)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Per-call config is snapshotted at the start of each dispatch, so concurrent mutations to module-level settings cannot affect in-flight requests.
|
|
182
|
+
|
|
116
183
|
## Advanced Features
|
|
117
184
|
|
|
118
185
|
### Parallel Processing
|
|
119
186
|
|
|
120
|
-
Batch requests are processed in parallel using the [parallel](https://github.com/grosser/parallel) gem. You can pass options to `Parallel.map
|
|
187
|
+
Batch requests are processed in parallel using the [parallel](https://github.com/grosser/parallel) gem. You can pass options to `Parallel.map`:
|
|
121
188
|
|
|
122
189
|
```ruby
|
|
123
190
|
Clamo::Server.parsed_dispatch_to_object(
|
data/lib/clamo/jsonrpc.rb
CHANGED
|
@@ -14,27 +14,10 @@ module Clamo
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
class << self
|
|
17
|
-
def proper_pragma?(request)
|
|
18
|
-
request["jsonrpc"] == "2.0"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def proper_method?(request)
|
|
22
|
-
request["method"].is_a?(String)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def proper_id_if_any?(request)
|
|
26
|
-
if request.key?("id")
|
|
27
|
-
request["id"].is_a?(String) ||
|
|
28
|
-
request["id"].is_a?(Integer) ||
|
|
29
|
-
request["id"].is_a?(NilClass)
|
|
30
|
-
else
|
|
31
|
-
true
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
17
|
def proper_params_if_any?(request)
|
|
36
|
-
if
|
|
37
|
-
|
|
18
|
+
if key_indifferent?(request, "params")
|
|
19
|
+
params = fetch_indifferent(request, "params")
|
|
20
|
+
params.is_a?(Array) || params.is_a?(Hash)
|
|
38
21
|
else
|
|
39
22
|
true
|
|
40
23
|
end
|
|
@@ -96,11 +79,36 @@ module Clamo
|
|
|
96
79
|
|
|
97
80
|
private
|
|
98
81
|
|
|
82
|
+
def proper_pragma?(request)
|
|
83
|
+
fetch_indifferent(request, "jsonrpc") == "2.0"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def proper_method?(request)
|
|
87
|
+
fetch_indifferent(request, "method").is_a?(String)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def proper_id_if_any?(request)
|
|
91
|
+
if key_indifferent?(request, "id")
|
|
92
|
+
id = fetch_indifferent(request, "id")
|
|
93
|
+
id.is_a?(String) || id.is_a?(Integer) || id.is_a?(NilClass)
|
|
94
|
+
else
|
|
95
|
+
true
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
99
|
def validate_params_type!(params)
|
|
100
100
|
return if params.is_a?(Array) || params.is_a?(Hash)
|
|
101
101
|
|
|
102
102
|
raise ArgumentError, "params must be an Array or Hash"
|
|
103
103
|
end
|
|
104
|
+
|
|
105
|
+
def fetch_indifferent(hash, key)
|
|
106
|
+
hash.fetch(key.to_s) { hash.fetch(key.to_sym, nil) }
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def key_indifferent?(hash, key)
|
|
110
|
+
hash.key?(key.to_s) || hash.key?(key.to_sym)
|
|
111
|
+
end
|
|
104
112
|
end
|
|
105
113
|
end
|
|
106
114
|
end
|
data/lib/clamo/server.rb
CHANGED
|
@@ -2,17 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "parallel"
|
|
5
|
+
require "timeout"
|
|
5
6
|
|
|
6
7
|
module Clamo
|
|
7
8
|
module Server
|
|
9
|
+
Config = Data.define(:timeout, :on_error, :before_dispatch, :after_dispatch)
|
|
10
|
+
|
|
8
11
|
class << self
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
# Module-level defaults. These are snapshotted at the start of each
|
|
13
|
+
# dispatch call, so mutations mid-request do not affect in-flight work.
|
|
14
|
+
# All four can be overridden per-call via keyword arguments.
|
|
15
|
+
attr_accessor :on_error, :before_dispatch, :after_dispatch
|
|
16
|
+
attr_writer :timeout
|
|
17
|
+
|
|
18
|
+
def timeout
|
|
19
|
+
return @timeout if defined?(@timeout)
|
|
20
|
+
|
|
21
|
+
30
|
|
22
|
+
end
|
|
16
23
|
|
|
17
24
|
# JSON string in, JSON string out. Full round-trip for HTTP/socket integrations.
|
|
18
25
|
#
|
|
@@ -39,39 +46,60 @@ module Clamo
|
|
|
39
46
|
parsed_dispatch_to_object(request: parsed, object: object, **)
|
|
40
47
|
end
|
|
41
48
|
|
|
42
|
-
def parsed_dispatch_to_object(request:, object:,
|
|
43
|
-
|
|
49
|
+
def parsed_dispatch_to_object(request:, object:,
|
|
50
|
+
timeout: self.timeout,
|
|
51
|
+
on_error: self.on_error,
|
|
52
|
+
before_dispatch: self.before_dispatch,
|
|
53
|
+
after_dispatch: self.after_dispatch,
|
|
54
|
+
**opts)
|
|
55
|
+
raise ArgumentError, "object is required" unless object
|
|
56
|
+
|
|
57
|
+
request = normalize_request_keys(request)
|
|
58
|
+
config = Config.new(timeout: timeout, on_error: on_error,
|
|
59
|
+
before_dispatch: before_dispatch, after_dispatch: after_dispatch)
|
|
60
|
+
|
|
61
|
+
response_for(request: request, object: object, config: config, **opts) do |method, params|
|
|
44
62
|
dispatch_to_ruby(object: object, method: method, params: params)
|
|
45
63
|
end
|
|
46
64
|
end
|
|
47
65
|
|
|
48
66
|
private
|
|
49
67
|
|
|
68
|
+
def normalize_request_keys(request)
|
|
69
|
+
case request
|
|
70
|
+
when Hash then request.transform_keys(&:to_s)
|
|
71
|
+
when Array then request.map { |r| r.is_a?(Hash) ? r.transform_keys(&:to_s) : r }
|
|
72
|
+
else request
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
50
76
|
def method_known?(object:, method:)
|
|
51
77
|
object.public_methods(false).map(&:to_sym).include?(method.to_sym)
|
|
52
78
|
end
|
|
53
79
|
|
|
54
80
|
def dispatch_to_ruby(object:, method:, params:)
|
|
55
81
|
case params
|
|
56
|
-
when Array
|
|
57
|
-
when Hash
|
|
58
|
-
when NilClass
|
|
59
|
-
else raise ArgumentError, "Unsupported params type: #{params.class}"
|
|
82
|
+
when Array then object.public_send(method.to_sym, *params)
|
|
83
|
+
when Hash then object.public_send(method.to_sym, **params.transform_keys(&:to_sym))
|
|
84
|
+
when NilClass then object.public_send(method.to_sym)
|
|
60
85
|
end
|
|
61
86
|
end
|
|
62
87
|
|
|
63
|
-
|
|
88
|
+
# Extra keyword arguments (**) are forwarded to response_for_batch only,
|
|
89
|
+
# where they become options for Parallel.map (e.g., in_processes: 4).
|
|
90
|
+
# For single requests they are silently ignored.
|
|
91
|
+
def response_for(request:, object:, config:, **, &block)
|
|
64
92
|
case request
|
|
65
93
|
when Array
|
|
66
|
-
response_for_batch(request: request, object: object, block: block, **)
|
|
94
|
+
response_for_batch(request: request, object: object, block: block, config: config, **)
|
|
67
95
|
when Hash
|
|
68
|
-
response_for_single_request(request: request, object: object, block: block)
|
|
96
|
+
response_for_single_request(request: request, object: object, block: block, config: config)
|
|
69
97
|
else
|
|
70
98
|
JSONRPC.build_error_response_from(id: nil, descriptor: JSONRPC::ProtocolErrors::INVALID_REQUEST)
|
|
71
99
|
end
|
|
72
100
|
end
|
|
73
101
|
|
|
74
|
-
def response_for_single_request(request:, object:, block:)
|
|
102
|
+
def response_for_single_request(request:, object:, block:, config:)
|
|
75
103
|
error = validate_request_structure(request)
|
|
76
104
|
return error if error
|
|
77
105
|
|
|
@@ -79,18 +107,23 @@ module Clamo
|
|
|
79
107
|
return request.key?("id") ? method_not_found_error(request) : nil
|
|
80
108
|
end
|
|
81
109
|
|
|
82
|
-
return dispatch_notification(request, block) unless request.key?("id")
|
|
110
|
+
return dispatch_notification(request, block, config) unless request.key?("id")
|
|
83
111
|
|
|
84
|
-
dispatch_request(request, block)
|
|
112
|
+
dispatch_request(request, block, config)
|
|
85
113
|
end
|
|
86
114
|
|
|
87
|
-
def response_for_batch(request:, object:, block:, **opts)
|
|
115
|
+
def response_for_batch(request:, object:, block:, config:, **opts)
|
|
88
116
|
if request.empty?
|
|
89
117
|
return JSONRPC.build_error_response_from(id: nil, descriptor: JSONRPC::ProtocolErrors::INVALID_REQUEST)
|
|
90
118
|
end
|
|
91
119
|
|
|
120
|
+
if request.size == 1
|
|
121
|
+
result = response_for_single_request(request: request.first, object: object, block: block, config: config)
|
|
122
|
+
return result ? [result] : nil
|
|
123
|
+
end
|
|
124
|
+
|
|
92
125
|
result = Parallel.map(request, **opts) do |item|
|
|
93
|
-
response_for_single_request(request: item, object: object, block: block)
|
|
126
|
+
response_for_single_request(request: item, object: object, block: block, config: config)
|
|
94
127
|
end.compact
|
|
95
128
|
result.empty? ? nil : result
|
|
96
129
|
end
|
|
@@ -105,6 +138,9 @@ module Clamo
|
|
|
105
138
|
|
|
106
139
|
return if JSONRPC.proper_params_if_any?(request)
|
|
107
140
|
|
|
141
|
+
# Notifications must never produce a response, even for invalid params
|
|
142
|
+
return nil unless request.key?("id")
|
|
143
|
+
|
|
108
144
|
JSONRPC.build_error_response_from(id: request["id"], descriptor: JSONRPC::ProtocolErrors::INVALID_PARAMS)
|
|
109
145
|
end
|
|
110
146
|
|
|
@@ -112,29 +148,50 @@ module Clamo
|
|
|
112
148
|
JSONRPC.build_error_response_from(id: request["id"], descriptor: JSONRPC::ProtocolErrors::METHOD_NOT_FOUND)
|
|
113
149
|
end
|
|
114
150
|
|
|
115
|
-
def dispatch_notification(request, block)
|
|
116
|
-
|
|
151
|
+
def dispatch_notification(request, block, config)
|
|
152
|
+
method = request["method"]
|
|
153
|
+
params = request["params"]
|
|
154
|
+
config.before_dispatch&.call(method, params)
|
|
155
|
+
with_timeout(config.timeout) { block.yield(method, params) }
|
|
156
|
+
config.after_dispatch&.call(method, params, nil)
|
|
117
157
|
nil
|
|
118
158
|
rescue StandardError => e
|
|
119
|
-
on_error&.call(e,
|
|
159
|
+
config.on_error&.call(e, method, params)
|
|
120
160
|
nil
|
|
121
161
|
end
|
|
122
162
|
|
|
123
|
-
def dispatch_request(request, block)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
)
|
|
163
|
+
def dispatch_request(request, block, config)
|
|
164
|
+
method = request["method"]
|
|
165
|
+
params = request["params"]
|
|
166
|
+
config.before_dispatch&.call(method, params)
|
|
167
|
+
result = with_timeout(config.timeout) { block.yield(method, params) }
|
|
168
|
+
config.after_dispatch&.call(method, params, result)
|
|
169
|
+
JSONRPC.build_result_response(id: request["id"], result: result)
|
|
170
|
+
rescue Timeout::Error
|
|
171
|
+
timeout_error(request)
|
|
128
172
|
rescue StandardError => e
|
|
173
|
+
config.on_error&.call(e, method, params)
|
|
174
|
+
JSONRPC.build_error_response_from(id: request["id"], descriptor: JSONRPC::ProtocolErrors::INTERNAL_ERROR)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def timeout_error(request)
|
|
129
178
|
JSONRPC.build_error_response(
|
|
130
179
|
id: request["id"],
|
|
131
180
|
error: {
|
|
132
|
-
code: JSONRPC::ProtocolErrors::
|
|
133
|
-
message: JSONRPC::ProtocolErrors::
|
|
134
|
-
data:
|
|
181
|
+
code: JSONRPC::ProtocolErrors::SERVER_ERROR.code,
|
|
182
|
+
message: JSONRPC::ProtocolErrors::SERVER_ERROR.message,
|
|
183
|
+
data: "Request timed out"
|
|
135
184
|
}
|
|
136
185
|
)
|
|
137
186
|
end
|
|
187
|
+
|
|
188
|
+
def with_timeout(seconds, &block)
|
|
189
|
+
if seconds
|
|
190
|
+
Timeout.timeout(seconds, &block)
|
|
191
|
+
else
|
|
192
|
+
block.call
|
|
193
|
+
end
|
|
194
|
+
end
|
|
138
195
|
end
|
|
139
196
|
end
|
|
140
197
|
end
|
data/lib/clamo/version.rb
CHANGED
data/lib/clamo.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: clamo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andriy Tyurnikov
|
|
@@ -23,7 +23,8 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '1.27'
|
|
26
|
-
description: JSON-RPC 2.0 server
|
|
26
|
+
description: Minimal, spec-compliant JSON-RPC 2.0 server for Ruby with request validation,
|
|
27
|
+
method dispatch, batch processing, and notification support.
|
|
27
28
|
email:
|
|
28
29
|
- Andriy.Tyurnikov@gmail.com
|
|
29
30
|
executables: []
|
|
@@ -32,15 +33,16 @@ extra_rdoc_files: []
|
|
|
32
33
|
files:
|
|
33
34
|
- ".rubocop.yml"
|
|
34
35
|
- CHANGELOG.md
|
|
36
|
+
- LICENSE
|
|
35
37
|
- README.md
|
|
36
38
|
- Rakefile
|
|
37
39
|
- lib/clamo.rb
|
|
38
40
|
- lib/clamo/jsonrpc.rb
|
|
39
41
|
- lib/clamo/server.rb
|
|
40
42
|
- lib/clamo/version.rb
|
|
41
|
-
- sig/clamo.rbs
|
|
42
43
|
homepage: https://github.com/rubakas/clamo
|
|
43
|
-
licenses:
|
|
44
|
+
licenses:
|
|
45
|
+
- MIT
|
|
44
46
|
metadata:
|
|
45
47
|
homepage_uri: https://github.com/rubakas/clamo
|
|
46
48
|
source_code_uri: https://github.com/rubakas/clamo
|
data/sig/clamo.rbs
DELETED