scale_rb 0.2.2 → 0.3.0
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 +4 -4
- data/.gitignore +1 -0
- data/.rspec +0 -0
- data/.rubocop.yml +0 -0
- data/.travis.yml +0 -0
- data/CODE_OF_CONDUCT.md +0 -0
- data/Gemfile +0 -0
- data/Gemfile.lock +50 -2
- data/LICENSE.txt +0 -0
- data/README.md +7 -4
- data/Rakefile +0 -0
- data/examples/http_client_1.rb +9 -0
- data/examples/http_client_2.rb +9 -0
- data/examples/ws_client_1.rb +14 -0
- data/examples/ws_client_2.rb +9 -0
- data/examples/ws_client_3.rb +21 -0
- data/examples/ws_client_4.rb +13 -0
- data/lib/address.rb +0 -0
- data/lib/client/client_ext.rb +214 -0
- data/lib/client/http_client.rb +37 -77
- data/lib/client/ws_client.rb +202 -0
- data/lib/codec.rb +0 -0
- data/lib/hasher.rb +0 -0
- data/lib/metadata/metadata.rb +0 -0
- data/lib/metadata/metadata_v10.rb +0 -0
- data/lib/metadata/metadata_v11.rb +0 -0
- data/lib/metadata/metadata_v12.rb +0 -0
- data/lib/metadata/metadata_v13.rb +0 -0
- data/lib/metadata/metadata_v14.rb +0 -0
- data/lib/metadata/metadata_v9.rb +0 -0
- data/lib/monkey_patching.rb +0 -0
- data/lib/portable_codec.rb +0 -0
- data/lib/registry.rb +0 -0
- data/lib/scale_rb/version.rb +1 -1
- data/lib/scale_rb.rb +4 -4
- data/lib/storage_helper.rb +0 -0
- data/scale_rb.gemspec +7 -3
- data/tea.yaml +6 -0
- metadata +61 -13
- data/lib/client/abstract_ws_client.rb +0 -104
- data/lib/client/http_client_metadata.rb +0 -78
- data/lib/client/http_client_storage.rb +0 -180
- data/lib/client/rpc_request_builder.rb +0 -55
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'async'
|
2
|
+
require 'async/websocket/client'
|
3
|
+
require 'async/http/endpoint'
|
4
|
+
require 'async/queue'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
require_relative 'client_ext'
|
8
|
+
|
9
|
+
module ScaleRb
|
10
|
+
class WsClient
|
11
|
+
include ClientExt
|
12
|
+
attr_accessor :supported_methods
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@queue = Async::Queue.new
|
16
|
+
@response_handler = ResponseHandler.new
|
17
|
+
@subscription_handler = SubscriptionHandler.new
|
18
|
+
@request_id = 1
|
19
|
+
end
|
20
|
+
|
21
|
+
def request(method, params = [])
|
22
|
+
# don't check for rpc_methods, because there is no @supported_methods when initializing
|
23
|
+
if method != 'rpc_methods' && !@supported_methods.include?(method)
|
24
|
+
raise "Method `#{method}` is not supported. It should be in [#{@supported_methods.join(', ')}]."
|
25
|
+
end
|
26
|
+
|
27
|
+
response_future = Async::Notification.new
|
28
|
+
|
29
|
+
@response_handler.register(@request_id, proc { |response|
|
30
|
+
# this is running in the main task
|
31
|
+
response_future.signal(response['result'])
|
32
|
+
})
|
33
|
+
|
34
|
+
request = JsonRpcRequest.new(@request_id, method, params)
|
35
|
+
@queue.enqueue(request)
|
36
|
+
|
37
|
+
@request_id += 1
|
38
|
+
|
39
|
+
response_future.wait
|
40
|
+
end
|
41
|
+
|
42
|
+
def subscribe(method, params = [], &block)
|
43
|
+
return unless method.include?('subscribe')
|
44
|
+
|
45
|
+
subscription_id = request(method, params)
|
46
|
+
@subscription_handler.subscribe(subscription_id, block)
|
47
|
+
subscription_id
|
48
|
+
end
|
49
|
+
|
50
|
+
def unsubscribe(method, subscription_id)
|
51
|
+
result = request(method, [subscription_id])
|
52
|
+
@subscription_handler.unsubscribe(subscription_id)
|
53
|
+
result
|
54
|
+
end
|
55
|
+
|
56
|
+
def next_request
|
57
|
+
@queue.dequeue
|
58
|
+
end
|
59
|
+
|
60
|
+
def handle_response(response)
|
61
|
+
if response.key?('id')
|
62
|
+
@response_handler.handle(response)
|
63
|
+
elsif response.key?('method')
|
64
|
+
@subscription_handler.handle(response)
|
65
|
+
else
|
66
|
+
puts "Received an unknown message: #{response}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def respond_to_missing?(*_args)
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_missing(method, *args)
|
75
|
+
ScaleRb.logger.debug "#{method}(#{args.join(', ')})"
|
76
|
+
|
77
|
+
method = method.to_s
|
78
|
+
if method.include?('unsubscribe')
|
79
|
+
unsubscribe(method, args[0])
|
80
|
+
elsif method.include?('subscribe')
|
81
|
+
raise "A subscribe method needs a block" unless block_given?
|
82
|
+
|
83
|
+
subscribe(method, args) do |notification|
|
84
|
+
yield notification['params']['result']
|
85
|
+
end
|
86
|
+
else
|
87
|
+
request(method, args)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.start(url)
|
92
|
+
Async do |task|
|
93
|
+
endpoint = Async::HTTP::Endpoint.parse(url, alpn_protocols: Async::HTTP::Protocol::HTTP11.names)
|
94
|
+
client = WsClient.new
|
95
|
+
|
96
|
+
task.async do
|
97
|
+
Async::WebSocket::Client.connect(endpoint) do |connection|
|
98
|
+
Async do
|
99
|
+
while request = client.next_request
|
100
|
+
ScaleRb.logger.debug "Sending request: #{request.to_json}"
|
101
|
+
connection.write(request.to_json)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# inside main task
|
106
|
+
while message = connection.read
|
107
|
+
data = JSON.parse(message)
|
108
|
+
ScaleRb.logger.debug "Received message: #{data}"
|
109
|
+
|
110
|
+
# 可以简单的理解为,这里的handle_response就是通知wait中的request,可以继续了.
|
111
|
+
Async do
|
112
|
+
client.handle_response(data)
|
113
|
+
rescue => e
|
114
|
+
ScaleRb.logger.error "#{e.class}: #{e.message}"
|
115
|
+
ScaleRb.logger.error e.backtrace.join("\n")
|
116
|
+
task.stop
|
117
|
+
end
|
118
|
+
end
|
119
|
+
rescue => e
|
120
|
+
ScaleRb.logger.error "#{e.class}: #{e.message}"
|
121
|
+
ScaleRb.logger.error e.backtrace.join("\n")
|
122
|
+
ensure
|
123
|
+
task.stop
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
task.async do
|
128
|
+
client.supported_methods = client.request('rpc_methods')['methods']
|
129
|
+
yield client
|
130
|
+
rescue => e
|
131
|
+
ScaleRb.logger.error "#{e.class}: #{e.message}"
|
132
|
+
ScaleRb.logger.error e.backtrace.join("\n")
|
133
|
+
task.stop
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class JsonRpcRequest
|
140
|
+
attr_reader :id, :method, :params
|
141
|
+
|
142
|
+
def initialize(id, method, params = {})
|
143
|
+
@id = id
|
144
|
+
@method = method
|
145
|
+
@params = params
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_json(*_args)
|
149
|
+
{ jsonrpc: '2.0', id: @id, method: @method, params: @params }.to_json
|
150
|
+
end
|
151
|
+
|
152
|
+
# def to_s
|
153
|
+
# to_json
|
154
|
+
# end
|
155
|
+
end
|
156
|
+
|
157
|
+
class ResponseHandler
|
158
|
+
def initialize
|
159
|
+
@handlers = {}
|
160
|
+
end
|
161
|
+
|
162
|
+
# handler: a proc with response data as param
|
163
|
+
def register(id, handler)
|
164
|
+
@handlers[id] = handler
|
165
|
+
end
|
166
|
+
|
167
|
+
def handle(response)
|
168
|
+
id = response['id']
|
169
|
+
if @handlers.key?(id)
|
170
|
+
handler = @handlers[id]
|
171
|
+
handler.call(response)
|
172
|
+
@handlers.delete(id)
|
173
|
+
else
|
174
|
+
ScaleRb.logger.debug "Received a message with unknown id: #{response}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class SubscriptionHandler
|
180
|
+
def initialize
|
181
|
+
@subscriptions = {}
|
182
|
+
end
|
183
|
+
|
184
|
+
def subscribe(subscription_id, handler)
|
185
|
+
@subscriptions[subscription_id] = handler
|
186
|
+
end
|
187
|
+
|
188
|
+
def unsubscribe(subscription_id)
|
189
|
+
@subscriptions.delete(subscription_id)
|
190
|
+
end
|
191
|
+
|
192
|
+
def handle(notification)
|
193
|
+
subscription_id = notification.dig('params', 'subscription')
|
194
|
+
if subscription_id && @subscriptions.key?(subscription_id)
|
195
|
+
@subscriptions[subscription_id].call(notification)
|
196
|
+
else
|
197
|
+
ScaleRb.logger.debug "Received a notification with unknown subscription id: #{notification}"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
data/lib/codec.rb
CHANGED
File without changes
|
data/lib/hasher.rb
CHANGED
File without changes
|
data/lib/metadata/metadata.rb
CHANGED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/lib/metadata/metadata_v9.rb
CHANGED
File without changes
|
data/lib/monkey_patching.rb
CHANGED
File without changes
|
data/lib/portable_codec.rb
CHANGED
File without changes
|
data/lib/registry.rb
CHANGED
File without changes
|
data/lib/scale_rb/version.rb
CHANGED
data/lib/scale_rb.rb
CHANGED
@@ -20,15 +20,15 @@ require 'metadata/metadata'
|
|
20
20
|
require 'hasher'
|
21
21
|
require 'storage_helper'
|
22
22
|
|
23
|
-
# client
|
24
|
-
require 'client/http_client'
|
25
|
-
require 'client/abstract_ws_client'
|
26
|
-
|
27
23
|
# get registry from config
|
28
24
|
require 'registry'
|
29
25
|
|
30
26
|
require 'address'
|
31
27
|
|
28
|
+
# clients
|
29
|
+
require 'client/http_client'
|
30
|
+
require 'client/ws_client'
|
31
|
+
|
32
32
|
module ScaleRb
|
33
33
|
class << self
|
34
34
|
attr_accessor :logger
|
data/lib/storage_helper.rb
CHANGED
File without changes
|
data/scale_rb.gemspec
CHANGED
@@ -6,11 +6,11 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.authors = ['Aki Wu']
|
7
7
|
spec.email = ['wuminzhe@gmail.com']
|
8
8
|
|
9
|
-
spec.summary = '
|
10
|
-
spec.description = '
|
9
|
+
spec.summary = 'A Ruby SCALE Codec Library, and, Substrate RPC Client'
|
10
|
+
spec.description = 'This gem includes a ruby implementation of SCALE Codec, a general Substrate Http JSONRPC Client, and, a general Substrate Websocket JSON-RPC Client.'
|
11
11
|
spec.homepage = 'https://github.com/wuminzhe/scale_rb'
|
12
12
|
spec.license = 'MIT'
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new('>=
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 3.1.1') # async gem's requirement
|
14
14
|
|
15
15
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
16
16
|
|
@@ -34,4 +34,8 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_dependency 'base58'
|
35
35
|
spec.add_dependency 'blake2b_rs', '~> 0.1.4'
|
36
36
|
spec.add_dependency 'xxhash'
|
37
|
+
# for websocket client
|
38
|
+
spec.add_dependency 'async'
|
39
|
+
spec.add_dependency 'async-http', '~> 0.69.0'
|
40
|
+
spec.add_dependency 'async-websocket', '~> 0.26.2'
|
37
41
|
end
|
data/tea.yaml
ADDED
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.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aki Wu
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base58
|
@@ -52,7 +52,50 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: async
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: async-http
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.69.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.69.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: async-websocket
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.26.2
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.26.2
|
97
|
+
description: This gem includes a ruby implementation of SCALE Codec, a general Substrate
|
98
|
+
Http JSONRPC Client, and, a general Substrate Websocket JSON-RPC Client.
|
56
99
|
email:
|
57
100
|
- wuminzhe@gmail.com
|
58
101
|
executables:
|
@@ -72,13 +115,17 @@ files:
|
|
72
115
|
- Rakefile
|
73
116
|
- bin/console
|
74
117
|
- bin/setup
|
118
|
+
- examples/http_client_1.rb
|
119
|
+
- examples/http_client_2.rb
|
120
|
+
- examples/ws_client_1.rb
|
121
|
+
- examples/ws_client_2.rb
|
122
|
+
- examples/ws_client_3.rb
|
123
|
+
- examples/ws_client_4.rb
|
75
124
|
- exe/metadata
|
76
125
|
- lib/address.rb
|
77
|
-
- lib/client/
|
126
|
+
- lib/client/client_ext.rb
|
78
127
|
- lib/client/http_client.rb
|
79
|
-
- lib/client/
|
80
|
-
- lib/client/http_client_storage.rb
|
81
|
-
- lib/client/rpc_request_builder.rb
|
128
|
+
- lib/client/ws_client.rb
|
82
129
|
- lib/codec.rb
|
83
130
|
- lib/hasher.rb
|
84
131
|
- lib/metadata/metadata.rb
|
@@ -95,13 +142,14 @@ files:
|
|
95
142
|
- lib/scale_rb/version.rb
|
96
143
|
- lib/storage_helper.rb
|
97
144
|
- scale_rb.gemspec
|
145
|
+
- tea.yaml
|
98
146
|
homepage: https://github.com/wuminzhe/scale_rb
|
99
147
|
licenses:
|
100
148
|
- MIT
|
101
149
|
metadata:
|
102
150
|
bug_tracker_uri: https://github.com/wuminzhe/scale_rb/issues/
|
103
151
|
source_code_uri: https://github.com/wuminzhe/scale_rb.git
|
104
|
-
post_install_message:
|
152
|
+
post_install_message:
|
105
153
|
rdoc_options: []
|
106
154
|
require_paths:
|
107
155
|
- lib
|
@@ -109,15 +157,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
157
|
requirements:
|
110
158
|
- - ">="
|
111
159
|
- !ruby/object:Gem::Version
|
112
|
-
version:
|
160
|
+
version: 3.1.1
|
113
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
162
|
requirements:
|
115
163
|
- - ">="
|
116
164
|
- !ruby/object:Gem::Version
|
117
165
|
version: '0'
|
118
166
|
requirements: []
|
119
|
-
rubygems_version: 3.
|
120
|
-
signing_key:
|
167
|
+
rubygems_version: 3.4.19
|
168
|
+
signing_key:
|
121
169
|
specification_version: 4
|
122
|
-
summary:
|
170
|
+
summary: A Ruby SCALE Codec Library, and, Substrate RPC Client
|
123
171
|
test_files: []
|
@@ -1,104 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative './rpc_request_builder'
|
4
|
-
|
5
|
-
module ScaleRb
|
6
|
-
class AbstractWsClient
|
7
|
-
extend RpcRequestBuilder
|
8
|
-
attr_accessor :metadata, :registry
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@id = 0
|
12
|
-
@metadata = nil
|
13
|
-
@registry = nil
|
14
|
-
@callbacks = {}
|
15
|
-
@subscription_callbacks = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
def send_json_rpc(_body)
|
19
|
-
raise 'WsClient is a abstract base class for websocket client, please use its sub-class'
|
20
|
-
end
|
21
|
-
|
22
|
-
# changes: [
|
23
|
-
# [
|
24
|
-
# "0x26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7", # storage key
|
25
|
-
# "0x0400000000000000d887690900000000020000" # change
|
26
|
-
# ]
|
27
|
-
# ]
|
28
|
-
def process(resp)
|
29
|
-
# handle id
|
30
|
-
@callbacks[resp['id']]&.call(resp['id'], resp) if resp['id']
|
31
|
-
|
32
|
-
# handle storage subscription
|
33
|
-
return unless resp['params'] && resp['params']['subscription']
|
34
|
-
return unless @metadata && @registry
|
35
|
-
|
36
|
-
subscription = resp['params']['subscription']
|
37
|
-
changes = resp['params']['result']['changes']
|
38
|
-
block = resp['params']['result']['block']
|
39
|
-
p "block: #{block}"
|
40
|
-
|
41
|
-
return unless @subscription_callbacks[subscription]
|
42
|
-
|
43
|
-
pallet_name, item_name, subscription_callback = @subscription_callbacks[subscription]
|
44
|
-
storage_item = Metadata.get_storage_item(pallet_name, item_name, @metadata)
|
45
|
-
storages = decode_storages(changes.map(&:last), storage_item, registry)
|
46
|
-
subscription_callback.call(storages)
|
47
|
-
end
|
48
|
-
|
49
|
-
def get_metadata(callback = nil)
|
50
|
-
if callback.nil?
|
51
|
-
callback = lambda do |id, resp|
|
52
|
-
return unless resp['id'] && resp['result']
|
53
|
-
return if resp['id'] != id
|
54
|
-
|
55
|
-
metadata_hex = resp['result']
|
56
|
-
metadata = Metadata.decode_metadata(metadata_hex.strip._to_bytes)
|
57
|
-
return unless metadata
|
58
|
-
|
59
|
-
@metadata = metadata
|
60
|
-
@registry = Metadata.build_registry(@metadata)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
id = bind_id_to(callback)
|
65
|
-
body = state_getMetadata(id)
|
66
|
-
send_json_rpc(body)
|
67
|
-
end
|
68
|
-
|
69
|
-
def subscribe_storage(pallet_name, item_name, subscription_callback, key = nil, registry = nil)
|
70
|
-
callback = create_callback_for_subscribe_storage(pallet_name, item_name, subscription_callback)
|
71
|
-
id = bind_id_to(callback)
|
72
|
-
body = derived_state_subscribe_storage(id, pallet_name, item_name, key, registry)
|
73
|
-
send_json_rpc(body)
|
74
|
-
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
def bind_id_to(callback)
|
79
|
-
@callbacks[@id] = callback
|
80
|
-
old = @id
|
81
|
-
@id += 1
|
82
|
-
old
|
83
|
-
end
|
84
|
-
|
85
|
-
def decode_storages(datas, storage_item, registry)
|
86
|
-
datas.map do |data|
|
87
|
-
StorageHelper.decode_storage2(data, storage_item, registry)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def create_callback_for_subscribe_storage(pallet_name, item_name, subscription_callback)
|
92
|
-
lambda do |id, resp|
|
93
|
-
return unless resp['id'] && resp['result']
|
94
|
-
return if resp['id'] != id
|
95
|
-
|
96
|
-
@subscription_callbacks[resp['result']] = [
|
97
|
-
pallet_name,
|
98
|
-
item_name,
|
99
|
-
subscription_callback
|
100
|
-
]
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'fileutils'
|
3
|
-
|
4
|
-
module ScaleRb
|
5
|
-
module HttpClient
|
6
|
-
class << self
|
7
|
-
def get_metadata(url, at = nil)
|
8
|
-
hex = state_getMetadata(url, at)
|
9
|
-
Metadata.decode_metadata(hex.strip._to_bytes)
|
10
|
-
end
|
11
|
-
|
12
|
-
# cached version of get_metadata
|
13
|
-
# get metadata from cache first
|
14
|
-
def get_metadata_cached(url, at: nil, dir: nil)
|
15
|
-
dir = ENV['SCALE_RB_METADATA_DIR'] || File.join(Dir.pwd, 'metadata') if dir.nil?
|
16
|
-
|
17
|
-
at = ScaleRb::HttpClient.chain_getFinalizedHead(url) if at.nil?
|
18
|
-
spec_name, spec_version = get_spec(url, at)
|
19
|
-
|
20
|
-
# get metadata from cache first
|
21
|
-
metadata = metadata_cached(
|
22
|
-
spec_name: spec_name,
|
23
|
-
spec_version: spec_version,
|
24
|
-
dir: dir
|
25
|
-
)
|
26
|
-
return metadata if metadata
|
27
|
-
|
28
|
-
# get metadata from rpc
|
29
|
-
metadata = ScaleRb::HttpClient.get_metadata(url, at)
|
30
|
-
|
31
|
-
# cache it
|
32
|
-
ScaleRb.logger.debug "caching metadata `#{spec_name}_#{spec_version}.json`"
|
33
|
-
save_metadata_to_file(
|
34
|
-
spec_name: spec_name,
|
35
|
-
spec_version: spec_version,
|
36
|
-
metadata: metadata,
|
37
|
-
dir: dir
|
38
|
-
)
|
39
|
-
|
40
|
-
metadata
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def get_spec(url, at)
|
46
|
-
runtime_version = ScaleRb::HttpClient.state_getRuntimeVersion(url, at)
|
47
|
-
spec_name = runtime_version['specName']
|
48
|
-
spec_version = runtime_version['specVersion']
|
49
|
-
[spec_name, spec_version]
|
50
|
-
end
|
51
|
-
|
52
|
-
def metadata_cached(spec_name:, spec_version:, dir:)
|
53
|
-
raise 'spec_version is required' unless spec_version
|
54
|
-
raise 'spec_name is required' unless spec_name
|
55
|
-
|
56
|
-
file_path = File.join(dir, "#{spec_name}_#{spec_version}.json")
|
57
|
-
return unless File.exist?(file_path)
|
58
|
-
|
59
|
-
ScaleRb.logger.debug "found metadata `#{spec_name}_#{spec_version}.json` in cache"
|
60
|
-
JSON.parse(File.read(file_path))
|
61
|
-
end
|
62
|
-
|
63
|
-
def save_metadata_to_file(spec_name:, spec_version:, metadata:, dir:)
|
64
|
-
FileUtils.mkdir_p(dir)
|
65
|
-
|
66
|
-
File.open(File.join(dir, "#{spec_name}_#{spec_version}.json"), 'w') do |f|
|
67
|
-
f.write(JSON.pretty_generate(metadata))
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def require_block_hash_correct(url, block_hash)
|
72
|
-
return unless ScaleRb::HttpClient.chain_getHeader(url, block_hash).nil?
|
73
|
-
|
74
|
-
raise 'Unable to retrieve header and parent from supplied hash'
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|