substrate_client.rb 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f0802284ca7abb1fd02f502506a00ba67ef2c0d436a1bede7012fc7746196c9
4
- data.tar.gz: 2b76f455d30a57c0b36eceecc5cf19e720126e9f071e3899b054a151bb1b122c
3
+ metadata.gz: 6ffef7ed87e2488047c796e8a77cc3e0789f532891a69283f6339b9dc55e899d
4
+ data.tar.gz: '08806295aaf4ced6714042496be2a54408fc4c1ba8d5bebbfe352b431407ec02'
5
5
  SHA512:
6
- metadata.gz: 392f72952f9822de5dff8b6c5df89b7eab52e7bdf38c988f0ea4448c8f6439f74dd06e415dd1fc33c627ed4c74e494c8838c452d3975e1f92c89a8b86e4e68a9
7
- data.tar.gz: eda7bacb9cb728d254c3582ef99696689fe03d387b14ad38ad4196b1c4a2ed10eb3f806a8c01c1da9c9143ffe00a15e1597b534c2df9ac1876d62fd63a1be230
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)
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.2)
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.0)
31
+ minitest (5.14.1)
32
32
  pry (0.12.2)
33
33
  coderay (~> 1.1.0)
34
34
  method_source (~> 0.9.0)
@@ -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
- attr_reader :ws
21
+ attr_accessor :ws
15
22
 
16
- def initialize(url: , spec_name: nil)
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 = Queue.new
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
- puts ex.message
236
- puts ex.backtrace.join("\n")
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
- puts e
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
- queue = Queue.new
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
- def start_connection
394
- @callbacks = {}
395
- @subscription_callbacks = {}
392
+ onopen: proc do |event|
393
+ @callbacks = {}
394
+ @subscription_callbacks = {}
395
+ @onopen.call event if not @onopen.nil?
396
+ end,
396
397
 
397
- @ws = Faye::WebSocket::Client.new(@url)
398
- @ws.on :message do |event|
399
- # p [:message, event.data]
400
- if event.data.include?("jsonrpc")
401
- begin
402
- data = JSON.parse event.data
403
-
404
- if data["params"]
405
- if @subscription_callbacks[data["params"]["subscription"]]
406
- @subscription_callbacks[data["params"]["subscription"]].call data
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
- rescue => ex
414
- puts ex.message
415
- puts ex.backtrace.join("\n")
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
- end
418
+
419
+ )
419
420
  end
420
421
 
421
422
  end
@@ -1,3 +1,3 @@
1
1
  class SubstrateClient
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  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
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-14 00:00:00.000000000 Z
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: