scale_rb 0.3.2 → 0.3.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: 6b1c3f0276dedfa00a80fed47d5647ced3d6128667e0b6e3ac38733351cb3dac
4
- data.tar.gz: 5e137b28a94a898949937e3d10d043b80627f46232a9f5d49ba27766fbac6659
3
+ metadata.gz: 946dbb730e56172125e2524d66c41650fb08a3b799576000b5254467080ec771
4
+ data.tar.gz: cae0b7ce708380ceeefa2bdd412abc30adbc5de5153b68bec12625497cf89e03
5
5
  SHA512:
6
- metadata.gz: 0416b944d3a0ccb254390e47c019c5692d04dc3f1c86f6033e6ceaac8e5e8a18c530e20a224ff19975b5acf8413f9e12da16cc6a24253a6f08d09972f981bdea
7
- data.tar.gz: 74e2acc6ee10c7928c7528fa42cdf1dc8c9a778f56c77136a5d9305619b0eb386d752ce3a9902589bed61ffe9eaf74a14446b7579c622fea73d34b960693287e
6
+ metadata.gz: 3d9b11df5acc3538b9fd7af4aabd1db74f9fb0f08ab7bc2620299d2145beee2805eeee12b1948e33a9198b0141b4b6c57187bb99f984743dbfb1c7e62e9b0ca7
7
+ data.tar.gz: df6d923402362b259384fe585a83ee490dc3e5bc5154d41b886a74ee1ab19d3e1fa0e92c0a3f8c2b5ffb976f12138418728b0c046ac23470bb1954b12a65a048
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
13
  /metadata
14
+ Gemfile.lock
data/Gemfile CHANGED
@@ -5,3 +5,4 @@ gemspec
5
5
 
6
6
  gem "rake", "~> 12.0"
7
7
  gem "rspec", "~> 3.0"
8
+ gem 'rubocop', group: 'development', require: false
data/README.md CHANGED
@@ -1,11 +1,13 @@
1
1
  # ScaleRb
2
2
 
3
+ It is still under heavy development. Use the latest version.
4
+
3
5
  ## Installation
4
6
 
5
7
  Add this line to your application's Gemfile:
6
8
 
7
9
  ```ruby
8
- gem 'scale_rb'
10
+ gem 'scale_rb', '~> 0.3.5'
9
11
  ```
10
12
 
11
13
  And then execute:
@@ -3,7 +3,13 @@ require 'scale_rb'
3
3
  ScaleRb.logger.level = Logger::DEBUG
4
4
 
5
5
  client = ScaleRb::HttpClient.new('https://polkadot-rpc.dwellir.com')
6
- block_number = 21585684
6
+ block_number = 21711742
7
7
  block_hash = client.chain_getBlockHash(block_number)
8
- storage = client.get_storage(block_hash, 'System', 'Events')
8
+ metadata = client.get_metadata(block_hash)
9
+
10
+ storage_query = ScaleRb::WsClient::StorageQuery.new(
11
+ pallet_name: 'System',
12
+ storage_name: 'Events',
13
+ )
14
+ storage = client.get_storage(block_hash, storage_query, metadata)
9
15
  puts "block #{block_number}(#{block_hash}) has #{storage.length} events"
@@ -1,10 +1,10 @@
1
1
  require 'scale_rb'
2
2
 
3
- # ScaleRb.logger.level = Logger::DEBUG
3
+ ScaleRb.logger.level = Logger::DEBUG
4
4
 
5
5
  ScaleRb::WsClient.start('wss://polkadot-rpc.dwellir.com') do |client|
6
6
  block_hash = client.chain_getBlockHash(21585684)
7
7
  runtime_version = client.state_getRuntimeVersion(block_hash)
8
- puts runtime_version['specName']
9
- puts runtime_version['specVersion']
8
+ puts runtime_version[:specName]
9
+ puts runtime_version[:specVersion]
10
10
  end
@@ -1,9 +1,14 @@
1
1
  require 'scale_rb'
2
2
 
3
- ScaleRb.logger.level = Logger::DEBUG
4
-
3
+ # You can have multiple subscriptions at the same time
5
4
  ScaleRb::WsClient.start('wss://polkadot-rpc.dwellir.com') do |client|
6
5
  client.chain_subscribeNewHead do |head|
7
- puts "Received new head at height: #{head['number'].to_i(16)}"
6
+ puts "Received new head at height: #{head[:number].to_i(16)}"
7
+ end
8
+
9
+ client.state_subscribeStorage do |storage|
10
+ block_hash = storage[:block]
11
+ changes = storage[:changes]
12
+ puts "Received #{changes.size} storage changes at block: #{block_hash}"
8
13
  end
9
14
  end
@@ -2,19 +2,20 @@ require 'scale_rb'
2
2
 
3
3
  # ScaleRb.logger.level = Logger::DEBUG
4
4
 
5
+ # Unsubscribe after receiving 4 new heads
5
6
  ScaleRb::WsClient.start('wss://polkadot-rpc.dwellir.com') do |client|
6
7
  count = 0
7
8
 
8
9
  subscription_id = client.chain_subscribeNewHead do |head|
9
- count = count + 1
10
+ count += 1
10
11
 
11
12
  if count < 5
12
- block_number = head['number'].to_i(16)
13
+ block_number = head[:number].to_i(16)
13
14
  block_hash = client.chain_getBlockHash(block_number)
14
15
  puts "Received new head at height: #{block_number}, block hash: #{block_hash}"
15
16
  else
16
17
  unsub_result = client.chain_unsubscribeNewHead(subscription_id)
17
- puts "Unsubscribed from new heads: #{unsub_result}"
18
+ puts "Unsubscribe result: #{unsub_result}"
18
19
  end
19
20
  end
20
21
 
@@ -0,0 +1,9 @@
1
+ require 'scale_rb'
2
+
3
+ begin
4
+ ScaleRb::WsClient.start('wss://polkadot-rpc.dwellir.com') do |_client|
5
+ raise 'MyError'
6
+ end
7
+ rescue StandardError => e
8
+ p e.message # "MyError"
9
+ end
@@ -42,7 +42,7 @@ module ScaleRb
42
42
  def query_storage_at(block_hash, storage_keys, type_id, default, registry)
43
43
  result = state_queryStorageAt(storage_keys, block_hash)
44
44
  result.map do |item|
45
- item['changes'].map do |change|
45
+ item[:changes].map do |change|
46
46
  storage_key = change[0]
47
47
  data = change[1] || default
48
48
  storage = data.nil? ? nil : PortableCodec.decode(type_id, data._to_bytes, registry)[0]
@@ -17,7 +17,7 @@ module ScaleRb
17
17
  raise 'url format is not correct' unless url.match?(url_regex)
18
18
 
19
19
  @uri = URI.parse(url)
20
- @supported_methods = request('rpc_methods', [])['methods']
20
+ @supported_methods = request('rpc_methods', [])[:methods]
21
21
  end
22
22
 
23
23
  def request(method, params = [])
@@ -37,11 +37,12 @@ module ScaleRb
37
37
  response = http.request(request)
38
38
  raise response unless response.is_a?(Net::HTTPOK)
39
39
 
40
- body = JSON.parse(response.body)
40
+ # parse response, make key symbol
41
+ body = JSON.parse(response.body, symbolize_names: true)
41
42
  ScaleRb.logger.debug "Response: #{body}"
42
- raise body['error'] if body['error']
43
+ raise body[:error] if body[:error]
43
44
 
44
- body['result']
45
+ body[:result]
45
46
  end
46
47
 
47
48
  def respond_to_missing?(*_args)
@@ -54,4 +55,4 @@ module ScaleRb
54
55
  request(method.to_s, args)
55
56
  end
56
57
  end
57
- end
58
+ end
@@ -1,58 +1,55 @@
1
1
  require 'async'
2
2
  require 'async/websocket/client'
3
3
  require 'async/http/endpoint'
4
- require 'async/queue'
5
- require 'json'
6
4
 
7
5
  require_relative 'client_ext'
8
6
 
9
7
  module ScaleRb
10
8
  class WsClient
11
- def self.start(url)
12
- Async do |task|
13
- endpoint = Async::HTTP::Endpoint.parse(url, alpn_protocols: Async::HTTP::Protocol::HTTP11.names)
14
- client = WsClient.new
15
9
 
16
- task.async do
10
+ class << self
11
+ # @param [string] url
12
+ def start(url)
13
+ Sync do
14
+ endpoint = Async::HTTP::Endpoint.parse(url, alpn_protocols: Async::HTTP::Protocol::HTTP11.names)
15
+
17
16
  Async::WebSocket::Client.connect(endpoint) do |connection|
18
- Async do
19
- while request = client.next_request
20
- ScaleRb.logger.debug "Sending request: #{request.to_json}"
21
- connection.write(request.to_json)
17
+ client = WsClient.new(connection)
18
+
19
+ # `recv_task` does not raise errors (subclass of StandardError), so it will not be stopped by any errors.
20
+ recv_task = Async do
21
+ while (message = client.read_message)
22
+ data = parse_message(message)
23
+ next if data.nil?
24
+
25
+ ScaleRb.logger.debug "Received response: #{data}"
26
+ Async do
27
+ client.handle_response(data)
28
+ end
22
29
  end
23
30
  end
24
31
 
25
- # inside main task
26
- while message = connection.read
27
- data = JSON.parse(message)
28
- ScaleRb.logger.debug "Received message: #{data}"
29
-
30
- Async do
31
- client.handle_response(data)
32
- rescue => e
33
- ScaleRb.logger.error "#{e.class}: #{e.message}"
34
- ScaleRb.logger.error e.backtrace.join("\n")
35
- task.stop
36
- end
37
- end
38
- rescue => e
39
- ScaleRb.logger.error "#{e.class}: #{e.message}"
40
- ScaleRb.logger.error e.backtrace.join("\n")
32
+ client.supported_methods = client.rpc_methods()[:methods]
33
+ yield client
34
+
35
+ recv_task.wait
41
36
  ensure
42
- task.stop
37
+ recv_task&.stop
43
38
  end
44
39
  end
45
40
 
46
- task.async do
47
- client.supported_methods = client.rpc_methods()['methods']
48
- yield client
49
- rescue => e
50
- ScaleRb.logger.error "#{e.class}: #{e.message}"
51
- ScaleRb.logger.error e.backtrace.join("\n")
52
- task.stop
53
- end
41
+ end
42
+
43
+ private
44
+
45
+ def parse_message(message)
46
+ message.parse
47
+ rescue StandardError => e
48
+ ScaleRb.logger.error "Error while parsing message: #{e.inspect}, message: #{message}"
49
+ nil
54
50
  end
55
51
  end
52
+
56
53
  end
57
54
  end
58
55
 
@@ -61,8 +58,8 @@ module ScaleRb
61
58
  include ClientExt
62
59
  attr_accessor :supported_methods
63
60
 
64
- def initialize
65
- @queue = Async::Queue.new
61
+ def initialize(connection)
62
+ @connection = connection
66
63
  @response_handler = ResponseHandler.new
67
64
  @subscription_handler = SubscriptionHandler.new
68
65
  @request_id = 1
@@ -84,10 +81,10 @@ module ScaleRb
84
81
  if method.include?('unsubscribe')
85
82
  unsubscribe(method, args[0])
86
83
  elsif method.include?('subscribe')
87
- raise "A subscribe method needs a block" unless block_given?
84
+ raise 'A subscribe method needs a block' unless block_given?
88
85
 
89
86
  subscribe(method, args) do |notification|
90
- yield notification['params']['result']
87
+ yield notification[:params][:result]
91
88
  end
92
89
  else
93
90
  request(method, args)
@@ -111,17 +108,27 @@ module ScaleRb
111
108
  end
112
109
  end
113
110
 
114
- def next_request
115
- @queue.dequeue
116
- end
117
-
118
111
  def handle_response(response)
119
- if response.key?('id')
112
+ if response.key?(:id)
120
113
  @response_handler.handle(response)
121
- elsif response.key?('method')
114
+ elsif response.key?(:method)
122
115
  @subscription_handler.handle(response)
123
116
  else
124
- puts "Received an unknown message: #{response}"
117
+ ScaleRb.logger.info "Received an unknown response: #{response}"
118
+ end
119
+ rescue StandardError => e
120
+ ScaleRb.logger.error "Error while handling response: #{e.inspect}"
121
+ ScaleRb.logger.debug e.backtrace.join("\n")
122
+ end
123
+
124
+ def read_message
125
+ loop do
126
+ return @connection.read
127
+ rescue StandardError => e
128
+ ScaleRb.logger.error "Error while read message from connection: #{e.inspect}"
129
+ ScaleRb.logger.debug e.backtrace.join("\n")
130
+ sleep 1
131
+ retry
125
132
  end
126
133
  end
127
134
 
@@ -131,88 +138,59 @@ module ScaleRb
131
138
  response_future = Async::Notification.new
132
139
 
133
140
  @response_handler.register(@request_id, proc { |response|
134
- # this is running in the main task
135
- response_future.signal(response['result'])
141
+ response_future.signal(response[:result])
136
142
  })
137
143
 
138
- request = JsonRpcRequest.new(@request_id, method, params)
139
- @queue.enqueue(request)
144
+ request = { jsonrpc: '2.0', id: @request_id, method: method, params: params }
145
+ ScaleRb.logger.debug "Sending request: #{request}"
146
+ @connection.write(request.to_json)
140
147
 
141
148
  @request_id += 1
142
-
143
149
  response_future.wait
144
150
  end
145
151
  end
146
152
 
147
- class JsonRpcRequest
148
- attr_reader :id, :method, :params
149
-
150
- def initialize(id, method, params = {})
151
- @id = id
152
- @method = method
153
- @params = params
154
- end
155
-
156
- def to_json(*_args)
157
- { jsonrpc: '2.0', id: @id, method: @method, params: @params }.to_json
158
- end
159
-
160
- # def to_s
161
- # to_json
162
- # end
163
- end
164
-
165
153
  class ResponseHandler
166
154
  def initialize
167
- @handlers = {}
155
+ @callbacks = {}
168
156
  end
169
157
 
170
- # handler: a proc with response data as param
171
- def register(id, handler)
172
- @handlers[id] = handler
158
+ # callback: a proc with response data as param
159
+ def register(id, callback)
160
+ @callbacks[id] = callback
173
161
  end
174
162
 
175
163
  def handle(response)
176
- id = response['id']
177
- if @handlers.key?(id)
178
- handler = @handlers[id]
179
- handler.call(response)
180
- @handlers.delete(id)
164
+ id = response[:id]
165
+ if @callbacks.key?(id)
166
+ callback = @callbacks[id]
167
+ callback.call(response)
168
+ @callbacks.delete(id)
181
169
  else
182
- ScaleRb.logger.debug "Received a message with unknown id: #{response}"
170
+ ScaleRb.logger.info "Received a message with unknown id: #{response}"
183
171
  end
184
172
  end
185
173
  end
186
174
 
187
175
  class SubscriptionHandler
188
176
  def initialize
189
- @subscriptions = {}
177
+ @callbacks = {}
190
178
  end
191
179
 
192
- def subscribe(subscription_id, handler)
193
- @subscriptions[subscription_id] = handler
180
+ def subscribe(subscription_id, callback)
181
+ @callbacks[subscription_id] = callback
194
182
  end
195
183
 
196
184
  def unsubscribe(subscription_id)
197
- @subscriptions.delete(subscription_id)
185
+ @callbacks.delete(subscription_id)
198
186
  end
199
187
 
200
188
  def handle(notification)
201
- subscription_id = notification.dig('params', 'subscription')
189
+ subscription_id = notification.dig(:params, :subscription)
202
190
  return if subscription_id.nil?
203
191
 
204
- if @subscriptions.key?(subscription_id)
205
- @subscriptions[subscription_id].call(notification)
206
- else
207
- # the subscription_id may be not registered.
208
- # in client.subscribe function,
209
- # ...
210
- # subscription_id = request(method, params)
211
- # @subscription_handler.subscribe(subscription_id, block)
212
- # ...
213
- # the request(method, params) may be slow, so the subscription_id may be not registered when the first notification comes.
214
- sleep 0.01
215
- handle(notification)
192
+ if @callbacks.key?(subscription_id)
193
+ @callbacks[subscription_id].call(notification)
216
194
  end
217
195
  end
218
196
  end
@@ -1,3 +1,3 @@
1
1
  module ScaleRb
2
- VERSION = '0.3.2'
2
+ VERSION = '0.3.5'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scale_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aki Wu
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-07-19 00:00:00.000000000 Z
11
+ date: 2024-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base58
@@ -109,7 +109,6 @@ files:
109
109
  - ".travis.yml"
110
110
  - CODE_OF_CONDUCT.md
111
111
  - Gemfile
112
- - Gemfile.lock
113
112
  - LICENSE.txt
114
113
  - README.md
115
114
  - Rakefile
@@ -121,6 +120,7 @@ files:
121
120
  - examples/ws_client_2.rb
122
121
  - examples/ws_client_3.rb
123
122
  - examples/ws_client_4.rb
123
+ - examples/ws_client_error_handling.rb
124
124
  - exe/metadata
125
125
  - lib/address.rb
126
126
  - lib/client/client_ext.rb
data/Gemfile.lock DELETED
@@ -1,97 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- scale_rb (0.3.2)
5
- async
6
- async-http (~> 0.69.0)
7
- async-websocket (~> 0.26.2)
8
- base58
9
- blake2b_rs (~> 0.1.4)
10
- xxhash
11
-
12
- GEM
13
- remote: https://rubygems.org/
14
- specs:
15
- async (2.14.2)
16
- console (~> 1.25, >= 1.25.2)
17
- fiber-annotation
18
- io-event (~> 1.6, >= 1.6.5)
19
- async-http (0.69.0)
20
- async (>= 2.10.2)
21
- async-pool (~> 0.7)
22
- io-endpoint (~> 0.11)
23
- io-stream (~> 0.4)
24
- protocol-http (~> 0.26)
25
- protocol-http1 (~> 0.19)
26
- protocol-http2 (~> 0.18)
27
- traces (>= 0.10)
28
- async-pool (0.7.0)
29
- async (>= 1.25)
30
- async-websocket (0.26.2)
31
- async-http (~> 0.54)
32
- protocol-rack (~> 0.5)
33
- protocol-websocket (~> 0.14)
34
- base58 (0.2.3)
35
- blake2b_rs (0.1.4)
36
- ffi (~> 1.0)
37
- thermite (~> 0)
38
- console (1.27.0)
39
- fiber-annotation
40
- fiber-local (~> 1.1)
41
- json
42
- diff-lcs (1.5.0)
43
- ffi (1.17.0)
44
- fiber-annotation (0.2.0)
45
- fiber-local (1.1.0)
46
- fiber-storage
47
- fiber-storage (0.1.2)
48
- io-endpoint (0.13.0)
49
- io-event (1.6.5)
50
- io-stream (0.4.0)
51
- json (2.7.2)
52
- minitar (0.9)
53
- protocol-hpack (1.4.3)
54
- protocol-http (0.28.1)
55
- protocol-http1 (0.19.1)
56
- protocol-http (~> 0.22)
57
- protocol-http2 (0.18.0)
58
- protocol-hpack (~> 1.4)
59
- protocol-http (~> 0.18)
60
- protocol-rack (0.6.0)
61
- protocol-http (~> 0.23)
62
- rack (>= 1.0)
63
- protocol-websocket (0.15.0)
64
- protocol-http (~> 0.2)
65
- rack (3.1.7)
66
- rake (12.3.3)
67
- rspec (3.11.0)
68
- rspec-core (~> 3.11.0)
69
- rspec-expectations (~> 3.11.0)
70
- rspec-mocks (~> 3.11.0)
71
- rspec-core (3.11.0)
72
- rspec-support (~> 3.11.0)
73
- rspec-expectations (3.11.0)
74
- diff-lcs (>= 1.2.0, < 2.0)
75
- rspec-support (~> 3.11.0)
76
- rspec-mocks (3.11.1)
77
- diff-lcs (>= 1.2.0, < 2.0)
78
- rspec-support (~> 3.11.0)
79
- rspec-support (3.11.0)
80
- thermite (0.13.0)
81
- minitar (~> 0.5)
82
- rake (>= 10)
83
- tomlrb (~> 1.2)
84
- tomlrb (1.3.0)
85
- traces (0.11.1)
86
- xxhash (0.5.0)
87
-
88
- PLATFORMS
89
- ruby
90
-
91
- DEPENDENCIES
92
- rake (~> 12.0)
93
- rspec (~> 3.0)
94
- scale_rb!
95
-
96
- BUNDLED WITH
97
- 2.1.4