substrate_client.rb 0.1.3 → 0.1.4

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 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)