erpc-sdk 0.7.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/README.md +125 -5
- data/lib/erpc_sdk/bridge.rb +1507 -0
- data/lib/erpc_sdk/client.rb +210 -75
- data/lib/erpc_sdk/config.rb +107 -8
- data/lib/erpc_sdk/errors.rb +100 -9
- data/lib/erpc_sdk/generated/bridge_capabilities.rb +9 -0
- data/lib/erpc_sdk/generated/swap_execution_capabilities.rb +11 -0
- data/lib/erpc_sdk/swap.rb +679 -0
- data/lib/erpc_sdk/transport.rb +69 -20
- data/lib/erpc_sdk/version.rb +1 -1
- data/lib/erpc_sdk/websocket.rb +45 -13
- data/lib/erpc_sdk.rb +1 -0
- metadata +5 -2
data/lib/erpc_sdk/transport.rb
CHANGED
|
@@ -18,9 +18,9 @@ module ERPC
|
|
|
18
18
|
response = start(uri, timeout) { |http| http.request(request) }
|
|
19
19
|
HttpResponse.new(status: response.code.to_i, body: response.body.to_s)
|
|
20
20
|
rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout
|
|
21
|
-
raise TimeoutError, timeout
|
|
21
|
+
raise TimeoutError, timeout, cause: nil
|
|
22
22
|
rescue IOError, EOFError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
|
|
23
|
-
raise TransportError, "Unable to reach ERPC"
|
|
23
|
+
raise TransportError, "Unable to reach ERPC", cause: nil
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def stream(url:, headers:, timeout: DEFAULT_TIMEOUT)
|
|
@@ -36,11 +36,11 @@ module ERPC
|
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout
|
|
39
|
-
raise TimeoutError, timeout
|
|
39
|
+
raise TimeoutError, timeout, cause: nil
|
|
40
40
|
rescue HttpError
|
|
41
41
|
raise
|
|
42
42
|
rescue IOError, EOFError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
|
|
43
|
-
raise TransportError, "Unable to reach ERPC"
|
|
43
|
+
raise TransportError, "Unable to reach ERPC", cause: nil
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
@@ -57,20 +57,34 @@ module ERPC
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
class HttpJsonRpcTransport
|
|
60
|
-
attr_reader :
|
|
60
|
+
attr_reader :max_batch_size
|
|
61
61
|
|
|
62
|
-
def initialize(api_key
|
|
62
|
+
def initialize(api_key: nil, endpoint:, headers: {}, timeout:, adapter:, max_batch_size: 256,
|
|
63
|
+
direct: false, redactions: [], unavailable_namespace: nil)
|
|
63
64
|
@api_key = api_key
|
|
64
65
|
@endpoint = endpoint
|
|
65
|
-
@
|
|
66
|
+
@public_endpoint = URLs.public_endpoint(endpoint)
|
|
67
|
+
@headers = headers.to_h.dup.freeze
|
|
66
68
|
@timeout = timeout
|
|
67
69
|
@adapter = adapter
|
|
68
70
|
@max_batch_size = max_batch_size
|
|
71
|
+
@direct = direct
|
|
72
|
+
@redactions = redactions
|
|
73
|
+
@unavailable_namespace = unavailable_namespace
|
|
69
74
|
@next_id = 0
|
|
70
75
|
@id_mutex = Mutex.new
|
|
71
76
|
end
|
|
72
77
|
|
|
78
|
+
def endpoint
|
|
79
|
+
@public_endpoint
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def inspect
|
|
83
|
+
"#<#{self.class} endpoint=#{endpoint.inspect} max_batch_size=#{max_batch_size.inspect}>"
|
|
84
|
+
end
|
|
85
|
+
|
|
73
86
|
def request(method, params = nil)
|
|
87
|
+
ensure_configured
|
|
74
88
|
request_id = next_id
|
|
75
89
|
body = { "jsonrpc" => "2.0", "id" => request_id, "method" => method }
|
|
76
90
|
body["params"] = params unless params.nil?
|
|
@@ -82,6 +96,7 @@ module ERPC
|
|
|
82
96
|
if calls.length > max_batch_size
|
|
83
97
|
raise InvalidResponseError, "A batch may contain at most #{max_batch_size} calls"
|
|
84
98
|
end
|
|
99
|
+
ensure_configured
|
|
85
100
|
|
|
86
101
|
requests = calls.map do |call|
|
|
87
102
|
method = call.fetch(:method) { call.fetch("method") }
|
|
@@ -123,19 +138,28 @@ module ERPC
|
|
|
123
138
|
|
|
124
139
|
private
|
|
125
140
|
|
|
141
|
+
def ensure_configured
|
|
142
|
+
return if @unavailable_namespace.nil?
|
|
143
|
+
|
|
144
|
+
raise NotConfiguredError, @unavailable_namespace
|
|
145
|
+
end
|
|
146
|
+
|
|
126
147
|
def next_id
|
|
127
148
|
@id_mutex.synchronize { @next_id += 1 }
|
|
128
149
|
end
|
|
129
150
|
|
|
130
151
|
def post(body)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
152
|
+
ensure_configured
|
|
153
|
+
uri = URI.parse(@endpoint)
|
|
154
|
+
unless @direct
|
|
155
|
+
query = URI.decode_www_form(uri.query.to_s)
|
|
156
|
+
query << ["api-key", @api_key]
|
|
157
|
+
uri.query = URI.encode_www_form(query)
|
|
158
|
+
end
|
|
135
159
|
response = @adapter.request(
|
|
136
160
|
method: :post,
|
|
137
161
|
url: uri.to_s,
|
|
138
|
-
headers:
|
|
162
|
+
headers: protocol_headers,
|
|
139
163
|
body: JSON.generate(body),
|
|
140
164
|
timeout: @timeout
|
|
141
165
|
)
|
|
@@ -143,7 +167,7 @@ module ERPC
|
|
|
143
167
|
|
|
144
168
|
JSON.parse(response.body)
|
|
145
169
|
rescue JSON::ParserError
|
|
146
|
-
raise InvalidResponseError, "ERPC returned malformed JSON"
|
|
170
|
+
raise InvalidResponseError, "ERPC returned malformed JSON", cause: nil
|
|
147
171
|
end
|
|
148
172
|
|
|
149
173
|
def unwrap(response, expected_id)
|
|
@@ -161,8 +185,17 @@ module ERPC
|
|
|
161
185
|
raise InvalidResponseError, "ERPC returned an invalid RPC error"
|
|
162
186
|
end
|
|
163
187
|
|
|
164
|
-
|
|
165
|
-
|
|
188
|
+
credentials = @direct ? @redactions : @api_key
|
|
189
|
+
data = error.key?("data") ? Redaction.value(error["data"], credentials) : nil
|
|
190
|
+
raise JsonRpcError.new(error["code"], Redaction.text(error["message"], credentials), data)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def protocol_headers
|
|
194
|
+
headers = @headers.dup
|
|
195
|
+
if @direct
|
|
196
|
+
headers.delete_if { |name, _| %w[accept content-type].include?(name.to_s.downcase) }
|
|
197
|
+
end
|
|
198
|
+
headers.merge("accept" => "application/json", "content-type" => "application/json")
|
|
166
199
|
end
|
|
167
200
|
|
|
168
201
|
def valid_id?(value)
|
|
@@ -171,17 +204,26 @@ module ERPC
|
|
|
171
204
|
end
|
|
172
205
|
|
|
173
206
|
class RestTransport
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def initialize(credential:, endpoint:, headers:, timeout:, adapter:)
|
|
207
|
+
def initialize(credential: nil, endpoint:, headers: {}, timeout:, adapter:, unavailable_namespace: nil)
|
|
177
208
|
@credential = credential
|
|
178
209
|
@endpoint = endpoint
|
|
179
|
-
@
|
|
210
|
+
@public_endpoint = URLs.public_endpoint(endpoint)
|
|
211
|
+
@headers = headers.to_h.dup.freeze
|
|
180
212
|
@timeout = timeout
|
|
181
213
|
@adapter = adapter
|
|
214
|
+
@unavailable_namespace = unavailable_namespace
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def endpoint
|
|
218
|
+
@public_endpoint
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def inspect
|
|
222
|
+
"#<#{self.class} endpoint=#{endpoint.inspect}>"
|
|
182
223
|
end
|
|
183
224
|
|
|
184
225
|
def get(path, query = nil)
|
|
226
|
+
ensure_configured
|
|
185
227
|
response = @adapter.request(
|
|
186
228
|
method: :get,
|
|
187
229
|
url: url(path, query),
|
|
@@ -192,10 +234,11 @@ module ERPC
|
|
|
192
234
|
|
|
193
235
|
JSON.parse(response.body)
|
|
194
236
|
rescue JSON::ParserError
|
|
195
|
-
raise InvalidResponseError, "ERPC returned malformed JSON"
|
|
237
|
+
raise InvalidResponseError, "ERPC returned malformed JSON", cause: nil
|
|
196
238
|
end
|
|
197
239
|
|
|
198
240
|
def stream(path, query = nil)
|
|
241
|
+
ensure_configured
|
|
199
242
|
@adapter.stream(
|
|
200
243
|
url: url(path, query),
|
|
201
244
|
headers: @headers.merge("authorization" => "Bearer #{@credential}", "accept" => "text/event-stream"),
|
|
@@ -205,6 +248,12 @@ module ERPC
|
|
|
205
248
|
|
|
206
249
|
private
|
|
207
250
|
|
|
251
|
+
def ensure_configured
|
|
252
|
+
return if @unavailable_namespace.nil?
|
|
253
|
+
|
|
254
|
+
raise NotConfiguredError, @unavailable_namespace
|
|
255
|
+
end
|
|
256
|
+
|
|
208
257
|
def url(path, query)
|
|
209
258
|
uri = URI.parse(URLs.with_path(endpoint, path))
|
|
210
259
|
pairs = []
|
data/lib/erpc_sdk/version.rb
CHANGED
data/lib/erpc_sdk/websocket.rb
CHANGED
|
@@ -22,6 +22,10 @@ module ERPC
|
|
|
22
22
|
connect
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def inspect
|
|
26
|
+
"#<#{self.class} endpoint=#{URLs.public_endpoint(@uri).inspect}>"
|
|
27
|
+
end
|
|
28
|
+
|
|
25
29
|
def write_text(text)
|
|
26
30
|
write_frame(0x1, text.b)
|
|
27
31
|
end
|
|
@@ -84,13 +88,13 @@ module ERPC
|
|
|
84
88
|
handshake
|
|
85
89
|
rescue ::Timeout::Error
|
|
86
90
|
tcp&.close
|
|
87
|
-
raise TimeoutError, @timeout
|
|
91
|
+
raise TimeoutError, @timeout, cause: nil
|
|
88
92
|
rescue ConfigError, TimeoutError
|
|
89
93
|
tcp&.close
|
|
90
94
|
raise
|
|
91
95
|
rescue IOError, EOFError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
|
|
92
96
|
tcp&.close
|
|
93
|
-
raise TransportError, "Unable to reach ERPC WebSocket"
|
|
97
|
+
raise TransportError, "Unable to reach ERPC WebSocket", cause: nil
|
|
94
98
|
end
|
|
95
99
|
|
|
96
100
|
def handshake
|
|
@@ -123,7 +127,7 @@ module ERPC
|
|
|
123
127
|
raise TransportError, "ERPC returned an invalid WebSocket upgrade"
|
|
124
128
|
end
|
|
125
129
|
rescue ::Timeout::Error
|
|
126
|
-
raise TimeoutError, @timeout
|
|
130
|
+
raise TimeoutError, @timeout, cause: nil
|
|
127
131
|
end
|
|
128
132
|
|
|
129
133
|
def read_until(delimiter, limit)
|
|
@@ -176,16 +180,16 @@ module ERPC
|
|
|
176
180
|
Timeout.timeout(@timeout) { @socket.write(prefix + mask + masked) }
|
|
177
181
|
end
|
|
178
182
|
rescue ::Timeout::Error
|
|
179
|
-
raise TimeoutError, @timeout
|
|
183
|
+
raise TimeoutError, @timeout, cause: nil
|
|
180
184
|
rescue IOError, EOFError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
|
|
181
|
-
raise TransportError, "Unable to reach ERPC WebSocket"
|
|
185
|
+
raise TransportError, "Unable to reach ERPC WebSocket", cause: nil
|
|
182
186
|
end
|
|
183
187
|
|
|
184
188
|
def read_exact(length)
|
|
185
189
|
value = +"".b
|
|
186
190
|
while value.bytesize < length
|
|
187
191
|
ready = IO.select([@socket], nil, nil, @timeout)
|
|
188
|
-
raise TimeoutError, @timeout unless ready
|
|
192
|
+
raise TimeoutError, @timeout, cause: nil unless ready
|
|
189
193
|
|
|
190
194
|
chunk = @socket.readpartial(length - value.bytesize)
|
|
191
195
|
raise EOFError if chunk.empty?
|
|
@@ -194,7 +198,7 @@ module ERPC
|
|
|
194
198
|
end
|
|
195
199
|
value
|
|
196
200
|
rescue EOFError, IOError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
|
|
197
|
-
raise TransportError, "ERPC WebSocket connection closed"
|
|
201
|
+
raise TransportError, "ERPC WebSocket connection closed", cause: nil
|
|
198
202
|
end
|
|
199
203
|
|
|
200
204
|
def secure_compare(left, right)
|
|
@@ -205,10 +209,17 @@ module ERPC
|
|
|
205
209
|
end
|
|
206
210
|
|
|
207
211
|
class WebSocketJsonRpcTransport
|
|
208
|
-
|
|
212
|
+
attr_reader :endpoint
|
|
213
|
+
|
|
214
|
+
def initialize(connection_url, credential, timeout, connection_factory: nil, direct: false,
|
|
215
|
+
redactions: [], unavailable_namespace: nil)
|
|
209
216
|
@connection_url = connection_url
|
|
210
217
|
@credential = credential
|
|
211
218
|
@timeout = timeout
|
|
219
|
+
@direct = direct
|
|
220
|
+
@redactions = redactions
|
|
221
|
+
@unavailable_namespace = unavailable_namespace
|
|
222
|
+
@endpoint = URLs.public_endpoint(connection_url)
|
|
212
223
|
@connection_factory = connection_factory || ->(url, seconds) { WebSocketConnection.new(url, seconds) }
|
|
213
224
|
@mutex = Mutex.new
|
|
214
225
|
@connection = nil
|
|
@@ -220,6 +231,10 @@ module ERPC
|
|
|
220
231
|
@closed = false
|
|
221
232
|
end
|
|
222
233
|
|
|
234
|
+
def inspect
|
|
235
|
+
"#<#{self.class} endpoint=#{endpoint.inspect}>"
|
|
236
|
+
end
|
|
237
|
+
|
|
223
238
|
def request(method, params = nil)
|
|
224
239
|
connection = ensure_connection
|
|
225
240
|
request_id = @mutex.synchronize { @next_id += 1 }
|
|
@@ -233,7 +248,7 @@ module ERPC
|
|
|
233
248
|
|
|
234
249
|
unwrap(response, request_id)
|
|
235
250
|
rescue ::Timeout::Error
|
|
236
|
-
raise TimeoutError, @timeout
|
|
251
|
+
raise TimeoutError, @timeout, cause: nil
|
|
237
252
|
ensure
|
|
238
253
|
@mutex.synchronize { @pending.delete(request_id) } if request_id
|
|
239
254
|
end
|
|
@@ -268,6 +283,7 @@ module ERPC
|
|
|
268
283
|
private
|
|
269
284
|
|
|
270
285
|
def ensure_connection
|
|
286
|
+
ensure_configured
|
|
271
287
|
@mutex.synchronize do
|
|
272
288
|
raise TransportError, "WebSocket transport is closed" if @closed
|
|
273
289
|
return @connection if @connection
|
|
@@ -302,7 +318,7 @@ module ERPC
|
|
|
302
318
|
end
|
|
303
319
|
rescue StandardError => error
|
|
304
320
|
@mutex.synchronize { @connection = nil if @connection.equal?(connection) }
|
|
305
|
-
fail_pending(TransportError.new(Redaction.text(error.message,
|
|
321
|
+
fail_pending(TransportError.new(Redaction.text(error.message, redaction_credentials)))
|
|
306
322
|
end
|
|
307
323
|
|
|
308
324
|
def fail_pending(error)
|
|
@@ -319,13 +335,25 @@ module ERPC
|
|
|
319
335
|
unless error.is_a?(Hash) && error["code"].is_a?(Integer) && error["message"].is_a?(String)
|
|
320
336
|
raise InvalidResponseError, "ERPC returned an invalid RPC error"
|
|
321
337
|
end
|
|
322
|
-
|
|
323
|
-
|
|
338
|
+
credentials = redaction_credentials
|
|
339
|
+
data = error.key?("data") ? Redaction.value(error["data"], credentials) : nil
|
|
340
|
+
raise JsonRpcError.new(error["code"], Redaction.text(error["message"], credentials), data)
|
|
324
341
|
end
|
|
325
342
|
raise InvalidResponseError, "ERPC returned an invalid WebSocket response" unless response.key?("result")
|
|
326
343
|
|
|
327
344
|
response["result"]
|
|
328
345
|
end
|
|
346
|
+
|
|
347
|
+
def ensure_configured
|
|
348
|
+
return if @unavailable_namespace.nil?
|
|
349
|
+
|
|
350
|
+
raise NotConfiguredError, @unavailable_namespace
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def redaction_credentials
|
|
354
|
+
@direct ? @redactions : @credential
|
|
355
|
+
end
|
|
356
|
+
|
|
329
357
|
end
|
|
330
358
|
|
|
331
359
|
class RpcSubscription
|
|
@@ -355,7 +383,7 @@ module ERPC
|
|
|
355
383
|
|
|
356
384
|
Timeout.timeout(timeout) { @queue.pop }
|
|
357
385
|
rescue ::Timeout::Error
|
|
358
|
-
raise TimeoutError, timeout
|
|
386
|
+
raise TimeoutError, timeout, cause: nil
|
|
359
387
|
end
|
|
360
388
|
|
|
361
389
|
def unsubscribe
|
|
@@ -372,6 +400,10 @@ module ERPC
|
|
|
372
400
|
@transport = transport
|
|
373
401
|
end
|
|
374
402
|
|
|
403
|
+
def endpoint
|
|
404
|
+
@transport.endpoint
|
|
405
|
+
end
|
|
406
|
+
|
|
375
407
|
def on_notification(listener = nil, &block)
|
|
376
408
|
@transport.on_notification(listener, &block)
|
|
377
409
|
end
|
data/lib/erpc_sdk.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: erpc-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ELSOUL LABO B.V.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -60,11 +60,14 @@ files:
|
|
|
60
60
|
- LICENSE
|
|
61
61
|
- README.md
|
|
62
62
|
- lib/erpc_sdk.rb
|
|
63
|
+
- lib/erpc_sdk/bridge.rb
|
|
63
64
|
- lib/erpc_sdk/client.rb
|
|
64
65
|
- lib/erpc_sdk/config.rb
|
|
65
66
|
- lib/erpc_sdk/dex_catalog.rb
|
|
66
67
|
- lib/erpc_sdk/errors.rb
|
|
68
|
+
- lib/erpc_sdk/generated/bridge_capabilities.rb
|
|
67
69
|
- lib/erpc_sdk/generated/dex_catalog.rb
|
|
70
|
+
- lib/erpc_sdk/generated/swap_execution_capabilities.rb
|
|
68
71
|
- lib/erpc_sdk/generated/token_catalog.rb
|
|
69
72
|
- lib/erpc_sdk/generated/token_rankings.rb
|
|
70
73
|
- lib/erpc_sdk/rest.rb
|