substrate_client.rb 0.1.4 → 0.1.5
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/Gemfile.lock +3 -3
- data/lib/substrate_client.rb +54 -53
- data/lib/substrate_client/version.rb +1 -1
- data/lib/timeout_queue.rb +34 -0
- data/lib/websocket.rb +79 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ffef7ed87e2488047c796e8a77cc3e0789f532891a69283f6339b9dc55e899d
|
4
|
+
data.tar.gz: '08806295aaf4ced6714042496be2a54408fc4c1ba8d5bebbfe352b431407ec02'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ede3bdec9f513b5586f8d9404c2f55e8ab70d53cb70e8f87920da8ecaab5f605542bf1f5fef4137d267088f11591abf1b1624530f9e97f01d779c60015c876ff
|
7
|
+
data.tar.gz: 967fa99d7887a30bade8a3914cfed8496a0a821f9ffc101405608b941fb406418fcacbd95be499ed6cd28960b0eadc9b1c98e733828783814e58f5ea44b18336
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
substrate_client.rb (0.1.
|
4
|
+
substrate_client.rb (0.1.5)
|
5
5
|
activesupport (~> 5.2.4)
|
6
6
|
eventmachine (~> 1.2.7)
|
7
7
|
faye-websocket (~> 0.10.9)
|
@@ -10,7 +10,7 @@ PATH
|
|
10
10
|
GEM
|
11
11
|
remote: https://rubygems.org/
|
12
12
|
specs:
|
13
|
-
activesupport (5.2.4.
|
13
|
+
activesupport (5.2.4.3)
|
14
14
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
15
|
i18n (>= 0.7, < 2)
|
16
16
|
minitest (~> 5.1)
|
@@ -28,7 +28,7 @@ GEM
|
|
28
28
|
concurrent-ruby (~> 1.0)
|
29
29
|
json (2.3.0)
|
30
30
|
method_source (0.9.2)
|
31
|
-
minitest (5.14.
|
31
|
+
minitest (5.14.1)
|
32
32
|
pry (0.12.2)
|
33
33
|
coderay (~> 1.1.0)
|
34
34
|
method_source (~> 0.9.0)
|
data/lib/substrate_client.rb
CHANGED
@@ -1,29 +1,41 @@
|
|
1
1
|
require "substrate_client/version"
|
2
2
|
|
3
|
+
require "logger"
|
3
4
|
require "scale.rb"
|
4
|
-
require "faye/websocket"
|
5
|
-
require "eventmachine"
|
6
5
|
require "json"
|
7
6
|
require "active_support"
|
8
7
|
require "active_support/core_ext/string"
|
8
|
+
require "websocket"
|
9
|
+
require "timeout_queue"
|
9
10
|
|
10
11
|
class SubstrateClient
|
11
12
|
class RpcError < StandardError; end
|
13
|
+
class RpcTimeout < StandardError; end
|
14
|
+
class << self
|
15
|
+
attr_accessor :logger
|
16
|
+
end
|
17
|
+
SubstrateClient.logger = Logger.new(STDOUT)
|
18
|
+
SubstrateClient.logger.level = Logger::INFO
|
12
19
|
|
13
20
|
attr_accessor :spec_name, :spec_version, :metadata
|
14
|
-
|
21
|
+
attr_accessor :ws
|
15
22
|
|
16
|
-
def initialize(url: ,
|
23
|
+
def initialize(url, spec_name: nil, onopen: nil)
|
17
24
|
@url = url
|
18
25
|
@request_id = 1
|
19
26
|
@spec_name = spec_name
|
27
|
+
@onopen = onopen
|
20
28
|
Scale::TypeRegistry.instance.load(spec_name)
|
21
29
|
|
22
30
|
init_ws
|
23
31
|
end
|
24
32
|
|
33
|
+
def close
|
34
|
+
@ws.close
|
35
|
+
end
|
36
|
+
|
25
37
|
def request(method, params, subscription_callback=nil)
|
26
|
-
queue =
|
38
|
+
queue = TimeoutQueue.new
|
27
39
|
|
28
40
|
payload = {
|
29
41
|
"jsonrpc" => "2.0",
|
@@ -35,7 +47,7 @@ class SubstrateClient
|
|
35
47
|
@callbacks[@request_id] = proc { |data| queue << data }
|
36
48
|
@ws.send(payload.to_json)
|
37
49
|
@request_id += 1
|
38
|
-
data = queue.pop
|
50
|
+
data = queue.pop(true, 5)
|
39
51
|
|
40
52
|
if not subscription_callback.nil? && data["result"]
|
41
53
|
@subscription_callbacks[data["result"]] = subscription_callback
|
@@ -46,6 +58,8 @@ class SubstrateClient
|
|
46
58
|
else
|
47
59
|
data["result"]
|
48
60
|
end
|
61
|
+
rescue ThreadError => ex
|
62
|
+
raise RpcTimeout
|
49
63
|
end
|
50
64
|
|
51
65
|
def init_runtime(block_hash: nil, block_id: nil)
|
@@ -232,13 +246,13 @@ class SubstrateClient
|
|
232
246
|
begin
|
233
247
|
callback.call result
|
234
248
|
rescue => ex
|
235
|
-
|
236
|
-
|
249
|
+
SubstrateClient.logger.error ex.message
|
250
|
+
SubstrateClient.logger.error ex.backtrace.join("\n")
|
237
251
|
end
|
238
252
|
},
|
239
253
|
|
240
254
|
proc { |e|
|
241
|
-
|
255
|
+
SubstrateClient.logger.error e
|
242
256
|
}
|
243
257
|
|
244
258
|
)
|
@@ -289,7 +303,13 @@ class SubstrateClient
|
|
289
303
|
hasher2,
|
290
304
|
metadata.value.value[:metadata][:version]
|
291
305
|
)
|
292
|
-
|
306
|
+
|
307
|
+
p module_name
|
308
|
+
p storage_name
|
309
|
+
p params
|
310
|
+
p hasher
|
311
|
+
p hasher2
|
312
|
+
p metadata.value.value[:metadata][:version]
|
293
313
|
result = self.state_get_storage(storage_hash, block_hash)
|
294
314
|
return unless result
|
295
315
|
Scale::Types.get(return_type).decode(Scale::Bytes.new(result))
|
@@ -367,55 +387,36 @@ class SubstrateClient
|
|
367
387
|
|
368
388
|
private
|
369
389
|
def init_ws
|
370
|
-
|
371
|
-
|
372
|
-
Thread.new do
|
373
|
-
EM.run do
|
374
|
-
start_connection
|
375
|
-
queue << "ok"
|
376
|
-
end
|
377
|
-
end
|
378
|
-
|
379
|
-
if queue.pop
|
380
|
-
Thread.new do
|
381
|
-
loop do
|
382
|
-
if @ws && @ws.ready_state == 3
|
383
|
-
puts "try to reconnect"
|
384
|
-
start_connection
|
385
|
-
end
|
386
|
-
|
387
|
-
sleep(3)
|
388
|
-
end
|
389
|
-
end
|
390
|
-
end
|
391
|
-
end
|
390
|
+
@ws = Websocket.new(@url,
|
392
391
|
|
393
|
-
|
394
|
-
|
395
|
-
|
392
|
+
onopen: proc do |event|
|
393
|
+
@callbacks = {}
|
394
|
+
@subscription_callbacks = {}
|
395
|
+
@onopen.call event if not @onopen.nil?
|
396
|
+
end,
|
396
397
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
398
|
+
onmessage: proc do |event|
|
399
|
+
if event.data.include?("jsonrpc")
|
400
|
+
begin
|
401
|
+
data = JSON.parse event.data
|
402
|
+
|
403
|
+
if data["params"]
|
404
|
+
if @subscription_callbacks[data["params"]["subscription"]]
|
405
|
+
@subscription_callbacks[data["params"]["subscription"]].call data
|
406
|
+
end
|
407
|
+
else
|
408
|
+
@callbacks[data["id"]].call data
|
409
|
+
@callbacks.delete(data["id"])
|
407
410
|
end
|
408
|
-
else
|
409
|
-
@callbacks[data["id"]].call data
|
410
|
-
@callbacks.delete(data["id"])
|
411
|
-
end
|
412
411
|
|
413
|
-
|
414
|
-
|
415
|
-
|
412
|
+
rescue => ex
|
413
|
+
SubstrateClient.logger.error ex.message
|
414
|
+
SubstrateClient.logger.error ex.backtrace.join("\n")
|
415
|
+
end
|
416
416
|
end
|
417
417
|
end
|
418
|
-
|
418
|
+
|
419
|
+
)
|
419
420
|
end
|
420
421
|
|
421
422
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# https://vaneyckt.io/posts/ruby_concurrency_building_a_timeout_queue/
|
2
|
+
class TimeoutQueue
|
3
|
+
def initialize
|
4
|
+
@elems = []
|
5
|
+
@mutex = Mutex.new
|
6
|
+
@cond_var = ConditionVariable.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def <<(elem)
|
10
|
+
@mutex.synchronize do
|
11
|
+
@elems << elem
|
12
|
+
@cond_var.signal
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def pop(blocking = true, timeout = nil)
|
17
|
+
@mutex.synchronize do
|
18
|
+
if blocking
|
19
|
+
if timeout.nil?
|
20
|
+
while @elems.empty?
|
21
|
+
@cond_var.wait(@mutex)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
timeout_time = Time.now.to_f + timeout
|
25
|
+
while @elems.empty? && (remaining_time = timeout_time - Time.now.to_f) > 0
|
26
|
+
@cond_var.wait(@mutex, remaining_time)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
raise ThreadError, 'queue empty' if @elems.empty?
|
31
|
+
@elems.shift
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/websocket.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require "faye/websocket"
|
2
|
+
require "eventmachine"
|
3
|
+
|
4
|
+
class SubstrateClient::Websocket
|
5
|
+
HEARTBEAT_INTERVAL = 3
|
6
|
+
RECONNECT_INTERVAL = 3
|
7
|
+
|
8
|
+
def initialize(url, onopen: nil, onmessage: nil)
|
9
|
+
@url = url
|
10
|
+
@onopen = onopen || proc { p [:open] }
|
11
|
+
@onmessage = onmessage || proc { |event| p [:message, event.data] }
|
12
|
+
|
13
|
+
@thread = Thread.new do
|
14
|
+
EM.run do
|
15
|
+
start_connection
|
16
|
+
end
|
17
|
+
SubstrateClient.logger.info "Event loop stopped"
|
18
|
+
end
|
19
|
+
@heartbeat_thread = start_heartbeat
|
20
|
+
end
|
21
|
+
|
22
|
+
def start_connection
|
23
|
+
SubstrateClient.logger.info "Start to connect"
|
24
|
+
@close = false
|
25
|
+
@missed_heartbeats = 0
|
26
|
+
@ping_id = 0
|
27
|
+
@ws = Faye::WebSocket::Client.new(@url)
|
28
|
+
@ws.on :open do |event|
|
29
|
+
@do_heartbeat = true
|
30
|
+
@onopen.call event
|
31
|
+
end
|
32
|
+
|
33
|
+
@ws.on :message do |event|
|
34
|
+
@onmessage.call event
|
35
|
+
end
|
36
|
+
|
37
|
+
@ws.on :close do |event|
|
38
|
+
# p [:close, event.code, event.reason]
|
39
|
+
if @close == false
|
40
|
+
@do_heartbeat = false
|
41
|
+
sleep RECONNECT_INTERVAL
|
42
|
+
start_connection
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def start_heartbeat
|
49
|
+
Thread.new do
|
50
|
+
loop do
|
51
|
+
send_heartbeat if @do_heartbeat
|
52
|
+
sleep HEARTBEAT_INTERVAL
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def send_heartbeat
|
58
|
+
if @missed_heartbeats < 2
|
59
|
+
# puts "ping_#{@ping_id}"
|
60
|
+
@ws.ping @ping_id.to_s do
|
61
|
+
# puts "pong"
|
62
|
+
@missed_heartbeats -= 1
|
63
|
+
end
|
64
|
+
@missed_heartbeats += 1
|
65
|
+
@ping_id += 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def send(message)
|
70
|
+
@ws.send message
|
71
|
+
end
|
72
|
+
|
73
|
+
def close
|
74
|
+
@close = true
|
75
|
+
Thread.kill @heartbeat_thread
|
76
|
+
Thread.kill @thread
|
77
|
+
@ws = nil
|
78
|
+
end
|
79
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: substrate_client.rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wu Minzhe
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-05-
|
11
|
+
date: 2020-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faye-websocket
|
@@ -144,6 +144,8 @@ files:
|
|
144
144
|
- exe/metadata
|
145
145
|
- lib/substrate_client.rb
|
146
146
|
- lib/substrate_client/version.rb
|
147
|
+
- lib/timeout_queue.rb
|
148
|
+
- lib/websocket.rb
|
147
149
|
- substrate_client.gemspec
|
148
150
|
homepage: https://github.com/itering/substrate_client.rb
|
149
151
|
licenses:
|