scale_rb 0.3.2 → 0.3.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 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