substrate_client.rb 0.1.3 → 0.1.4

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: 5248291da5b3db7dcdcdf913842fceef276c31481346f6da8141960e7d81afdb
4
- data.tar.gz: ffafc99e20d6321c4ab9c6231a3bf706ade3cbb17ba0c043c4401fbf45769c76
3
+ metadata.gz: 5f0802284ca7abb1fd02f502506a00ba67ef2c0d436a1bede7012fc7746196c9
4
+ data.tar.gz: 2b76f455d30a57c0b36eceecc5cf19e720126e9f071e3899b054a151bb1b122c
5
5
  SHA512:
6
- metadata.gz: bb06f911fe64f6e7e6425bfb4921427b5b49aabab86dfa57c4b2d48aeb2a2e057bfb33256762d316be30ff87f11d21a3cd89efd25c7d78985cc7cdf001038fb6
7
- data.tar.gz: e3199b2b0b72423984d7d2baa6160d5c17565b3fd5563375e59661a246c7ba1b80c7ffc82b963cc836e4486f0a48c6f1d070d7ebc48a9803a630b8c04f4f4a7b
6
+ metadata.gz: 392f72952f9822de5dff8b6c5df89b7eab52e7bdf38c988f0ea4448c8f6439f74dd06e415dd1fc33c627ed4c74e494c8838c452d3975e1f92c89a8b86e4e68a9
7
+ data.tar.gz: eda7bacb9cb728d254c3582ef99696689fe03d387b14ad38ad4196b1c4a2ed10eb3f806a8c01c1da9c9143ffe00a15e1597b534c2df9ac1876d62fd63a1be230
@@ -1,12 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- substrate_client.rb (0.1.3)
4
+ substrate_client.rb (0.1.4)
5
5
  activesupport (~> 5.2.4)
6
6
  eventmachine (~> 1.2.7)
7
7
  faye-websocket (~> 0.10.9)
8
- scale.rb (~> 0.2.2)
9
- substrate_common.rb (~> 0.1.8)
8
+ scale.rb (~> 0.2.5)
10
9
 
11
10
  GEM
12
11
  remote: https://rubygems.org/
@@ -47,7 +46,7 @@ GEM
47
46
  diff-lcs (>= 1.2.0, < 2.0)
48
47
  rspec-support (~> 3.9.0)
49
48
  rspec-support (3.9.2)
50
- scale.rb (0.2.2)
49
+ scale.rb (0.2.5)
51
50
  activesupport (>= 4.0.0)
52
51
  json (~> 2.3.0)
53
52
  substrate_common.rb (~> 0.1.8)
data/README.md CHANGED
@@ -20,7 +20,9 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- ### Api list
23
+ ### Supported rpc methods
24
+
25
+ #### rpc method list
24
26
 
25
27
  ```ruby
26
28
  require "substrate_client"
@@ -28,15 +30,177 @@ require "substrate_client"
28
30
  client = SubstrateClient.new("wss://kusama-rpc.polkadot.io/")
29
31
  puts client.method_list
30
32
  ```
31
- The rpc api methods is dynamically generated, so the methods returned by this method can be called.
33
+ The rpc methods can be dynamically called by its name, so the methods returned by this method can all be used.
34
+
35
+ #### hard-coded rpc method
36
+
37
+ But, in order to show the parameters more clearly, some important or frequently used methods are hard-coded:
38
+
39
+ - chain_get_finalised_head
40
+
41
+ Get hash of the last finalized block in the canon chain
42
+
43
+
44
+
45
+ - chain_get_head
46
+
47
+ - chain_get_header(block_hash = nil)
48
+
49
+ Retrieves the header for a specific block
50
+
51
+
52
+
53
+ - chain_get_block(block_hash = nil)
54
+
55
+ Get header and body of a relay chain block
56
+
57
+
58
+
59
+ - chain_get_block_hash(block_id)
60
+
61
+ Get the block hash for a specific block
62
+
63
+
64
+
65
+ - chain_get_runtime_version(block_hash = nil)
66
+
67
+ Get the runtime version for a specific block
68
+
69
+
70
+
71
+ - state_get_metadata(block_hash = nil)
72
+
73
+ Returns the runtime metadata by block
74
+
75
+
76
+
77
+ - state_get_storage(storage_key, block_hash = nil)
78
+
79
+ Retrieves the storage for a key
80
+
81
+
82
+
83
+ - system_name
84
+
85
+ - system_version
86
+
87
+
88
+
89
+ - chain_subscribe_all_heads(&callback)
90
+
91
+ Retrieves the newest header via subscription. This will return data continuously until you unsubscribe the subscription.
92
+
93
+ ```ruby
94
+ subscription = client.chain_subscribe_new_heads do |data|
95
+ p data
96
+ end
97
+ ```
98
+
99
+ - chain_unsubscribe_all_heads(subscription)
100
+
101
+ Unsubscribe newest header subscription.
102
+
103
+ ```ruby
104
+ client.chain_unsubscribe_all_heads(subscription)
105
+ ```
106
+
107
+
108
+
109
+ - chain_subscribe_new_heads(&callback)
110
+
111
+ Retrieves the best header via subscription. This will return data continuously until you unsubscribe the subscription.
112
+
113
+ ```ruby
114
+ subscription = client.chain_subscribe_new_heads do |data|
115
+ p data
116
+ end
117
+ ```
118
+
119
+ - chain_unsubscribe_new_heads(subscription)
120
+
121
+ Unsubscribe the best header subscription.
122
+
123
+ ```ruby
124
+ client.chain_unsubscribe_new_heads(subscription)
125
+ ```
126
+
127
+
128
+
129
+ - chain_subscribe_finalized_heads(&callback)
130
+
131
+ Retrieves the best finalized header via subscription. This will return data continuously until you unsubscribe the subscription.
132
+
133
+ ```ruby
134
+ subscription = client.chain_subscribe_finalized_heads do |data|
135
+ p data
136
+ end
137
+ ```
138
+
139
+ - chain_unsubscribe_finalized_heads(subscription)
140
+
141
+ Unsubscribe the best finalized header subscription.
142
+
143
+ ```ruby
144
+ client.chain_unsubscribe_finalized_heads(subscription)
145
+ ```
146
+
147
+
148
+
149
+ - state_subscribe_runtime_version(&callback)
150
+
151
+ Retrieves the runtime version via subscription.
152
+
153
+ - state_unsubscribe_runtime_version(subscription)
154
+
155
+ Unsubscribe the runtime version subscription.
156
+
157
+
158
+
159
+ - state_subscribe_storage(keys, &callback)
160
+
161
+ Subscribes to storage changes for the provided keys until unsubscribe.
162
+
163
+ ```ruby
164
+ subscription = client.state_subscribe_storage ["0x26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7"] do |data|
165
+ p data
166
+ end
167
+ ```
168
+
169
+ - state_unsubscribe_storage(subscription)
170
+
171
+ Unsubscribe storage changes.
172
+
173
+
174
+ ### Cutom methods based on rpc methods
175
+
176
+ These methods will encode the parameters and decode the returned data
177
+
178
+ - get_block_number(block_hash)
179
+
180
+ - get_metadata(block_hash)
181
+
182
+ - get_block(block_hash=nil)
183
+
184
+ - get_block_events(block_hash)
185
+
186
+ - subscribe_block_events(&callback)
187
+
188
+ - get_storage(module_name, storage_name, params = nil, block_hash = nil)
189
+
190
+ ```ruby
191
+ client.get_storage("Sudo", "Key")
192
+ client.get_storage("Balances", "TotalIssuance")
193
+ client.get_storage("System", "Account", ["0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"])
194
+ client.get_storage("ImOnline", "AuthoredBlocks", [2818, "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b757"])
195
+ ```
196
+
197
+ - compose_call(module_name, call_name, params, block_hash=nil)
198
+
199
+ ```ruby
200
+ compose_call "Balances", "Transfer", { dest: "0x586cb27c291c813ce74e86a60dad270609abf2fc8bee107e44a80ac00225c409", value: 1_000_000_000_000 }
201
+ ```
32
202
 
33
- ## TODO
34
203
 
35
- - [x] ws wss request support
36
- - [ ] http request support
37
- - [x] generate storage key
38
- - [x] call any api supported by substrate node with ruby's method missing function
39
- - [ ] metadata caching
40
204
 
41
205
  ## Development
42
206
 
@@ -9,4 +9,5 @@ block_hash = ARGV[1]
9
9
 
10
10
  client = SubstrateClient.new(url)
11
11
  client.init(block_hash)
12
- puts JSON.pretty_generate(client.metadata.value.value)
12
+ metadata = client.get_metadata(block_hash)
13
+ puts JSON.pretty_generate(metadata.value)
@@ -1,109 +1,263 @@
1
1
  require "substrate_client/version"
2
2
 
3
- require "substrate_common"
4
- require "scale"
5
-
3
+ require "scale.rb"
6
4
  require "faye/websocket"
7
5
  require "eventmachine"
8
6
  require "json"
9
7
  require "active_support"
10
8
  require "active_support/core_ext/string"
11
9
 
12
- def ws_request(url, payload)
13
- result = nil
14
-
15
- EM.run do
16
- ws = Faye::WebSocket::Client.new(url)
17
-
18
- ws.on :open do |event|
19
- # p [:open]
20
- ws.send(payload.to_json)
21
- end
22
-
23
- ws.on :message do |event|
24
- # p [:message, event.data]
25
- if event.data.include?("jsonrpc")
26
- result = JSON.parse event.data
27
- ws.close(3001, "data received")
28
- EM.stop
29
- end
30
- end
31
-
32
- ws.on :close do |event|
33
- # p [:close, event.code, event.reason]
34
- ws = nil
35
- end
36
- end
37
-
38
- result
39
- end
40
-
41
10
  class SubstrateClient
11
+ class RpcError < StandardError; end
12
+
42
13
  attr_accessor :spec_name, :spec_version, :metadata
14
+ attr_reader :ws
43
15
 
44
- def initialize(url)
16
+ def initialize(url: , spec_name: nil)
45
17
  @url = url
46
18
  @request_id = 1
19
+ @spec_name = spec_name
20
+ Scale::TypeRegistry.instance.load(spec_name)
21
+
22
+ init_ws
47
23
  end
48
24
 
49
- # TODO: error
50
- def request(method, params)
25
+ def request(method, params, subscription_callback=nil)
26
+ queue = Queue.new
27
+
51
28
  payload = {
52
29
  "jsonrpc" => "2.0",
53
30
  "method" => method,
54
31
  "params" => params,
55
32
  "id" => @request_id
56
33
  }
34
+
35
+ @callbacks[@request_id] = proc { |data| queue << data }
36
+ @ws.send(payload.to_json)
57
37
  @request_id += 1
58
- ws_request(@url, payload)
38
+ data = queue.pop
39
+
40
+ if not subscription_callback.nil? && data["result"]
41
+ @subscription_callbacks[data["result"]] = subscription_callback
42
+ end
43
+
44
+ if data["error"]
45
+ raise RpcError, data["error"]
46
+ else
47
+ data["result"]
48
+ end
49
+ end
50
+
51
+ def init_runtime(block_hash: nil, block_id: nil)
52
+ if block_hash.nil?
53
+ if not block_id.nil?
54
+ block_hash = self.chain_get_block_hash(block_id)
55
+ else
56
+ block_hash = self.chain_get_head
57
+ end
58
+ end
59
+
60
+ # set current runtime spec version
61
+ runtime_version = self.state_get_runtime_version(block_hash)
62
+ @spec_version = runtime_version["specVersion"]
63
+ Scale::TypeRegistry.instance.spec_version = @spec_version
64
+
65
+ # set current metadata
66
+ @metadata = self.get_metadata(block_hash)
67
+ Scale::TypeRegistry.instance.metadata = @metadata.value
68
+ true
69
+ end
70
+
71
+ def invoke(method, *params)
72
+ # params.reject! { |param| param.nil? }
73
+ request(method, params)
59
74
  end
60
75
 
61
- # ############################
62
- # native rpc methods support
63
- # ############################
76
+ def rpc_method(method_name)
77
+ SubstrateClient.real_method_name(method_name.to_s)
78
+ end
79
+
80
+ # ################################################
81
+ # origin rpc methods
82
+ # ################################################
64
83
  def method_missing(method, *args)
65
- data = request(SubstrateClient.real_method_name(method), args)
66
- data["result"]
84
+ rpc_method = SubstrateClient.real_method_name(method)
85
+ invoke rpc_method, *args
86
+ end
87
+
88
+ def rpc_methods
89
+ invoke rpc_method(__method__)
90
+ end
91
+
92
+ def chain_get_head
93
+ invoke rpc_method(__method__)
94
+ end
95
+
96
+ def chain_get_finalised_head
97
+ invoke rpc_method(__method__)
98
+ end
99
+
100
+ def chain_get_header(block_hash = nil)
101
+ invoke rpc_method(__method__), block_hash
102
+ end
103
+
104
+ def chain_get_block(block_hash = nil)
105
+ invoke rpc_method(__method__), block_hash
106
+ end
107
+
108
+ def chain_get_block_hash(block_id)
109
+ invoke rpc_method(__method__), block_id
110
+ end
111
+
112
+ def chain_get_runtime_version(block_hash = nil)
113
+ invoke rpc_method(__method__), block_hash
114
+ end
115
+
116
+ def state_get_metadata(block_hash = nil)
117
+ invoke rpc_method(__method__), block_hash
118
+ end
119
+
120
+ def state_get_storage(storage_key, block_hash = nil)
121
+ invoke rpc_method(__method__), storage_key, block_hash
122
+ end
123
+
124
+ def system_name
125
+ invoke rpc_method(__method__)
126
+ end
127
+
128
+ def system_version
129
+ invoke rpc_method(__method__)
130
+ end
131
+
132
+ def chain_subscribe_all_heads(&callback)
133
+ request rpc_method(__method__), [], callback
134
+ end
135
+
136
+ def chain_unsubscribe_all_heads(subscription)
137
+ invoke rpc_method(__method__), subscription
138
+ end
139
+
140
+ def chain_subscribe_new_heads(&callback)
141
+ request rpc_method(__method__), [], callback
142
+ end
143
+
144
+ def chain_unsubscribe_new_heads(subscription)
145
+ invoke rpc_method(__method__), subscription
146
+ end
147
+
148
+ def chain_subscribe_finalized_heads(&callback)
149
+ request rpc_method(__method__), [], callback
150
+ end
151
+
152
+ def chain_unsubscribe_finalized_heads(subscription)
153
+ invoke rpc_method(__method__), subscription
154
+ end
155
+
156
+ def state_subscribe_runtime_version(&callback)
157
+ request rpc_method(__method__), [], callback
158
+ end
159
+
160
+ def state_unsubscribe_runtime_version(subscription)
161
+ invoke rpc_method(__method__), subscription
162
+ end
163
+
164
+ def state_subscribe_storage(keys, &callback)
165
+ request rpc_method(__method__), [keys], callback
166
+ end
167
+
168
+ def state_unsubscribe_storage(subscription)
169
+ invoke rpc_method(__method__), subscription
67
170
  end
68
171
 
69
172
  # ################################################
70
- # custom methods wrapped from native rpc methods
173
+ # custom methods based on origin rpc methods
71
174
  # ################################################
72
175
  def method_list
73
- methods = self.rpc_methods["methods"].map(&:underscore)
74
- methods << "method_list"
75
- methods << "get_storage_at"
176
+ self.rpc_methods["methods"].map(&:underscore)
76
177
  end
77
178
 
78
- def init(block_hash = nil)
79
- block_runtime_version = self.state_get_runtime_version(block_hash)
80
- @spec_name = block_runtime_version["specName"]
81
- @spec_version = block_runtime_version["specVersion"]
82
-
83
- Scale::TypeRegistry.instance.load(spec_name, spec_version)
84
- @metadata = self.get_metadata(block_hash)
85
- true
179
+ def get_block_number(block_hash)
180
+ header = self.chain_get_header(block_hash)
181
+ header["number"].to_i(16)
86
182
  end
87
183
 
88
184
  def get_metadata(block_hash)
89
185
  hex = self.state_get_metadata(block_hash)
90
- metadata = Scale::Types::Metadata.decode(Scale::Bytes.new(hex))
91
- metadata.value.value[:metadata]
186
+ Scale::Types::Metadata.decode(Scale::Bytes.new(hex))
187
+ end
188
+
189
+ def get_block(block_hash=nil)
190
+ self.init_runtime(block_hash: block_hash)
191
+ block = self.chain_get_block(block_hash)
192
+
193
+ block["block"]["header"]["number"] = block["block"]["header"]["number"].to_i(16)
194
+
195
+ block["block"]["extrinsics"].each_with_index do |hex, i|
196
+ scale_bytes = Scale::Bytes.new(hex)
197
+ block["block"]["extrinsics"][i] = Scale::Types::Extrinsic.decode(scale_bytes).to_human
198
+ end
199
+
200
+ block['block']['header']["digest"]["logs"].each_with_index do |hex, i|
201
+ scale_bytes = Scale::Bytes.new(hex)
202
+ block['block']['header']["digest"]["logs"][i] = Scale::Types::LogDigest.decode(scale_bytes).to_human
203
+ end
204
+
205
+ block
206
+ end
207
+
208
+ def get_block_events(block_hash)
209
+ self.init_runtime(block_hash: block_hash)
210
+
211
+ storage_key = "0x26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7"
212
+ events_data = state_get_storage storage_key, block_hash
213
+
214
+ scale_bytes = Scale::Bytes.new(events_data)
215
+ Scale::Types.get("Vec<EventRecord>").decode(scale_bytes).to_human
216
+ end
217
+
218
+ def subscribe_block_events(&callback)
219
+ self.chain_subscribe_finalised_heads do |data|
220
+
221
+ block_number = data["params"]["result"]["number"].to_i(16) - 1
222
+ block_hash = data["params"]["result"]["parentHash"]
223
+
224
+ EM.defer(
225
+
226
+ proc {
227
+ events = get_block_events block_hash
228
+ { block_number: block_number, events: events }
229
+ },
230
+
231
+ proc { |result|
232
+ begin
233
+ callback.call result
234
+ rescue => ex
235
+ puts ex.message
236
+ puts ex.backtrace.join("\n")
237
+ end
238
+ },
239
+
240
+ proc { |e|
241
+ puts e
242
+ }
243
+
244
+ )
245
+ end
92
246
  end
93
247
 
94
- # client.init(0x014e4248dd04a8c0342b603a66df0691361ac58e69595e248219afa7af87bdc7)
95
- # Plain: client.get_storage_at("Balances", "TotalIssuance")
96
- # Map: client.get_storage_at("System", "Account", ["0x30599dba50b5f3ba0b36f856a761eb3c0aee61e830d4beb448ef94b6ad92be39"])
97
- # DoubleMap: client.get_storage_at("ImOnline", "AuthoredBlocks", [2818, "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b757"])
98
- def get_storage_at(module_name, storage_function_name, params = nil)
248
+ # Plain: client.get_storage("Sudo", "Key")
249
+ # Plain: client.get_storage("Balances", "TotalIssuance")
250
+ # Map: client.get_storage("System", "Account", ["0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"])
251
+ # DoubleMap: client.get_storage("ImOnline", "AuthoredBlocks", [2818, "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b757"])
252
+ def get_storage(module_name, storage_name, params = nil, block_hash = nil)
253
+ self.init_runtime(block_hash: block_hash)
99
254
 
100
- # TODO: uninit raise a exception
101
255
  # find the storage item from metadata
102
- metadata_modules = metadata[:modules]
256
+ metadata_modules = metadata.value.value[:metadata][:modules]
103
257
  metadata_module = metadata_modules.detect { |mm| mm[:name] == module_name }
104
258
  raise "Module '#{module_name}' not exist" unless metadata_module
105
- storage_item = metadata_module[:storage][:items].detect { |item| item[:name] == storage_function_name }
106
- raise "Storage item '#{storage_function_name}' not exist. \n#{metadata_module.inspect}" unless storage_item
259
+ storage_item = metadata_module[:storage][:items].detect { |item| item[:name] == storage_name }
260
+ raise "Storage item '#{storage_name}' not exist. \n#{metadata_module.inspect}" unless storage_item
107
261
 
108
262
  if storage_item[:type][:Plain]
109
263
  return_type = storage_item[:type][:Plain]
@@ -129,48 +283,66 @@ class SubstrateClient
129
283
 
130
284
  storage_hash = SubstrateClient.generate_storage_hash(
131
285
  module_name,
132
- storage_function_name,
286
+ storage_name,
133
287
  params,
134
288
  hasher,
135
289
  hasher2,
136
- metadata[:version]
290
+ metadata.value.value[:metadata][:version]
137
291
  )
138
292
 
139
- # puts storage_hash
140
-
141
- result = self.state_get_storage_at(storage_hash, block_hash)
293
+ result = self.state_get_storage(storage_hash, block_hash)
142
294
  return unless result
143
- Scale::Types.get(return_type).decode(Scale::Bytes.new(result)).value
144
- rescue => ex
145
- puts ex.message
146
- puts ex.backtrace
295
+ Scale::Types.get(return_type).decode(Scale::Bytes.new(result))
296
+ end
297
+
298
+ # compose_call "Balances", "Transfer", { dest: "0x586cb27c291c813ce74e86a60dad270609abf2fc8bee107e44a80ac00225c409", value: 1_000_000_000_000 }
299
+ def compose_call(module_name, call_name, params, block_hash=nil)
300
+ self.init_runtime(block_hash: block_hash)
301
+
302
+ call = metadata.get_module_call(module_name, call_name)
303
+
304
+ value = {
305
+ call_index: call[:lookup],
306
+ module_name: module_name,
307
+ call_name: call_name,
308
+ params: []
309
+ }
310
+
311
+ params.keys.each_with_index do |call_param_name, i|
312
+ param_value = params[call_param_name]
313
+ value[:params] << {
314
+ name: call_param_name.to_s,
315
+ type: call[:args][i][:type],
316
+ value: param_value
317
+ }
318
+ end
319
+
320
+ Scale::Types::Extrinsic.new(value).encode
147
321
  end
148
322
 
149
323
  class << self
150
- def generate_storage_hash(storage_module_name, storage_function_name, params = nil, hasher = nil, hasher2 = nil, metadata_version = nil)
324
+ def generate_storage_hash(module_name, storage_name, params = nil, hasher = nil, hasher2 = nil, metadata_version = nil)
151
325
  if metadata_version and metadata_version >= 9
152
- storage_hash = Crypto.twox128(storage_module_name) + Crypto.twox128(storage_function_name)
153
-
154
- if params
155
- params.each_with_index do |param, index|
156
- if index == 0
157
- param_hasher = hasher
158
- elsif index == 1
159
- param_hasher = hasher2
160
- else
161
- raise "Unexpected third parameter for storage call"
162
- end
163
-
164
- param_key = param.hex_to_bytes
165
- param_hasher = "Twox128" if param_hasher.nil?
166
- storage_hash += Crypto.send param_hasher.underscore, param_key
326
+ storage_hash = Crypto.twox128(module_name) + Crypto.twox128(storage_name)
327
+
328
+ params&.each_with_index do |param, index|
329
+ if index == 0
330
+ param_hasher = hasher
331
+ elsif index == 1
332
+ param_hasher = hasher2
333
+ else
334
+ raise "Unexpected third parameter for storage call"
167
335
  end
336
+
337
+ param_key = param.hex_to_bytes
338
+ param_hasher = "Twox128" if param_hasher.nil?
339
+ storage_hash += Crypto.send param_hasher.underscore, param_key
168
340
  end
169
341
 
170
342
  "0x#{storage_hash}"
171
343
  else
172
344
  # TODO: add test
173
- storage_hash = storage_module_name + " " + storage_function_name
345
+ storage_hash = module_name + " " + storage_name
174
346
 
175
347
  unless params.nil?
176
348
  params = [params] if params.class != ::Array
@@ -193,6 +365,57 @@ class SubstrateClient
193
365
 
194
366
  end
195
367
 
368
+ private
369
+ def init_ws
370
+ queue = Queue.new
196
371
 
197
- end
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
198
386
 
387
+ sleep(3)
388
+ end
389
+ end
390
+ end
391
+ end
392
+
393
+ def start_connection
394
+ @callbacks = {}
395
+ @subscription_callbacks = {}
396
+
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
407
+ end
408
+ else
409
+ @callbacks[data["id"]].call data
410
+ @callbacks.delete(data["id"])
411
+ end
412
+
413
+ rescue => ex
414
+ puts ex.message
415
+ puts ex.backtrace.join("\n")
416
+ end
417
+ end
418
+ end
419
+ end
420
+
421
+ end
@@ -1,3 +1,3 @@
1
1
  class SubstrateClient
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -36,11 +36,10 @@ Gem::Specification.new do |spec|
36
36
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
37
  spec.require_paths = ["lib"]
38
38
 
39
- spec.add_dependency "substrate_common.rb", "~> 0.1.8"
40
39
  spec.add_dependency "faye-websocket", "~> 0.10.9"
41
40
  spec.add_dependency "eventmachine", "~> 1.2.7"
42
41
  spec.add_dependency "activesupport", "~> 5.2.4"
43
- spec.add_dependency "scale.rb", "~> 0.2.2"
42
+ spec.add_dependency "scale.rb", "~> 0.2.5"
44
43
 
45
44
  spec.add_development_dependency "bundler", "~> 1.17"
46
45
  spec.add_development_dependency "rake", ">= 12.3.3"
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: substrate_client.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
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-04-08 00:00:00.000000000 Z
11
+ date: 2020-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: substrate_common.rb
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 0.1.8
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 0.1.8
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: faye-websocket
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +58,14 @@ dependencies:
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: 0.2.2
61
+ version: 0.2.5
76
62
  type: :runtime
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: 0.2.2
68
+ version: 0.2.5
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: bundler
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -141,7 +127,6 @@ email:
141
127
  - wuminzhe@gmail.com
142
128
  executables:
143
129
  - metadata
144
- - substrate_client
145
130
  extensions: []
146
131
  extra_rdoc_files: []
147
132
  files:
@@ -157,7 +142,6 @@ files:
157
142
  - bin/console
158
143
  - bin/setup
159
144
  - exe/metadata
160
- - exe/substrate_client
161
145
  - lib/substrate_client.rb
162
146
  - lib/substrate_client/version.rb
163
147
  - substrate_client.gemspec
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "substrate_client"
4
- require "json"
5
-
6
- client = SubstrateClient.new("wss://cc3-5.kusama.network/")
7
- # puts client.system_name
8
- # puts client.system_chain
9
- # puts client.system_version
10
- # puts client.system_peers
11
- # puts client.state_getStorage "0x0b76934f4cc08dee01012d059e1b83ee5e0621c4869aa60c02be9adcc98a0d1d"
12
- # puts client.state_getChildKeys "0x","0x",1,"0x"
13
- # puts client.runtime_getState "System", "Events",[],"0xe0303fbe2bc8482e06fb649f934c41349d12a25bd618c92e3331a3347e434f7b"
14
- # puts client.rpc_methods
15
-
16
- client.init
17
- metadata = client.metadata
18
- puts JSON.pretty_generate(metadata)