nano_rpc 0.14.0 → 0.15.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/README.md +53 -49
- data/lib/nano_rpc/node.rb +173 -138
- data/lib/nano_rpc/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 384dfb2767f15ba663867d79e98d771de4743b29650acf636f8dbb05ca13712b
|
4
|
+
data.tar.gz: b98fb36169c35288da75d2da4902f79d275ae9a88197ba746281baa9bfa7c6ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d39b16abbafe3347448eca3341dcc98918149e6df0724078c2e45fdb444f4a352620b50ec2de0d8f4f40a6fa70448a5e520c6299599024fc9908ff90aede288b
|
7
|
+
data.tar.gz: 166a68643c927e662cf33372882e3978135e3ab17a9e5a276eb52e3340754f7e9414cda652b507988c6a66a6d4853737e7a5ffceb332ccdd3fb9015e254d9ba7
|
data/README.md
CHANGED
@@ -30,55 +30,7 @@ Or install it yourself as:
|
|
30
30
|
|
31
31
|
## Usage
|
32
32
|
|
33
|
-
There are two ways to use this gem. You can
|
34
|
-
|
35
|
-
### Raw RPC Calls
|
36
|
-
|
37
|
-
The NanoRpc::Node object exposes raw Remote Procedure Call methods according to the [Nano RPC Docs](https://github.com/clemahieu/raiblocks/wiki/RPC-protocol).
|
38
|
-
|
39
|
-
Every method requires an `action`, which is passed as the first argument to `call`. Depending on the action, there may be additional required or optional parameters that are passed as an options hash.
|
40
|
-
|
41
|
-
First setup the node connection:
|
42
|
-
|
43
|
-
```ruby
|
44
|
-
# Connect to the default node (localhost:7076)
|
45
|
-
node = NanoRpc.node
|
46
|
-
|
47
|
-
# or connect to a custom node
|
48
|
-
node = NanoRpc::Node.new(host: 'mynanonode', port: 1234)
|
49
|
-
```
|
50
|
-
|
51
|
-
If you're using [Nanode](https://www.nanode.co/) or similar service that requires `Authorization` key in HTTP header, you can specify it using `auth`.
|
52
|
-
|
53
|
-
```ruby
|
54
|
-
node = NanoRpc::Node.new(auth: 'someauthkey')
|
55
|
-
```
|
56
|
-
|
57
|
-
You can also specify custom headers as a hash. These will be sent with every RPC request.
|
58
|
-
|
59
|
-
```ruby
|
60
|
-
node = NanoRpc::Node.new(headers: { 'Authorization' => 'someauthkey' })
|
61
|
-
```
|
62
|
-
|
63
|
-
Once the node is setup, make a `call`, passing the action and data:
|
64
|
-
|
65
|
-
```ruby
|
66
|
-
node.call(:account_balance, account: 'xrb_1234')
|
67
|
-
# => {"balance"=>100, "pending"=>0}
|
68
|
-
```
|
69
|
-
|
70
|
-
Response data are provided as [Hashie](https://github.com/intridea/hashie) objects with integer coercion, indifferent access, and method access.
|
71
|
-
|
72
|
-
```ruby
|
73
|
-
data = node.call(:account_balance, account: 'xrb_1234')
|
74
|
-
# => {"balance"=>100, "pending"=>0}
|
75
|
-
data.balance
|
76
|
-
# => 100
|
77
|
-
data[:balance]
|
78
|
-
# => 100
|
79
|
-
data['balance']
|
80
|
-
# => 100
|
81
|
-
```
|
33
|
+
There are two ways to use this gem. You can use proxy objects that expose helper methods or you make direct RPC calls using Ruby hashes.
|
82
34
|
|
83
35
|
### Proxy Objects / Helper Methods
|
84
36
|
|
@@ -127,6 +79,58 @@ To convert from Nano to raw and back, use `#to_raw` and `#to_nano`, available on
|
|
127
79
|
|
128
80
|
For a comprehensive guide, see the [Wiki](https://github.com/jcraigk/ruby_nano_rpc/wiki).
|
129
81
|
|
82
|
+
### Direct RPC Calls
|
83
|
+
|
84
|
+
The NanoRpc::Node object exposes raw Remote Procedure Call methods according to the [Nano RPC Docs](https://github.com/clemahieu/raiblocks/wiki/RPC-protocol).
|
85
|
+
|
86
|
+
Every method requires an `action`, which is passed as the first argument to `call`. Depending on the action, there may be additional required or optional parameters that are passed as an options hash.
|
87
|
+
|
88
|
+
First setup the node connection:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
# Connect to the default node (localhost:7076)
|
92
|
+
node = NanoRpc.node
|
93
|
+
|
94
|
+
# or connect to a custom node
|
95
|
+
node = NanoRpc::Node.new(host: 'mynanonode', port: 1234)
|
96
|
+
```
|
97
|
+
|
98
|
+
If you're using [Nanode](https://www.nanode.co/) or similar service that requires `Authorization` key in HTTP header, you can specify it using `auth`:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
node = NanoRpc::Node.new(auth: 'someauthkey')
|
102
|
+
```
|
103
|
+
|
104
|
+
You can also specify custom headers as a hash and they will be sent with every RPC request:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
node = NanoRpc::Node.new(headers: { 'Authorization' => 'someauthkey' })
|
108
|
+
```
|
109
|
+
|
110
|
+
The default timeout for each request is 20 seconds but you can specify a custom value:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
node = NanoRpc::Node.new(timeout: 10)
|
114
|
+
```
|
115
|
+
|
116
|
+
Once the node is setup, use the `call` method, passing in action and params:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
node.call(:account_balance, account: 'xrb_1234')
|
120
|
+
# => {"balance"=>100, "pending"=>0}
|
121
|
+
```
|
122
|
+
|
123
|
+
Response data are provided as [Hashie](https://github.com/intridea/hashie) objects with integer coercion, indifferent access, and method access.
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
data.balance
|
127
|
+
# => 100
|
128
|
+
data[:balance]
|
129
|
+
# => 100
|
130
|
+
data['balance']
|
131
|
+
# => 100
|
132
|
+
```
|
133
|
+
|
130
134
|
## Credits
|
131
135
|
|
132
136
|
Logo created by Andrei Luca ([Twitter](https://twitter.com/lucandrei_))
|
data/lib/nano_rpc/node.rb
CHANGED
@@ -6,159 +6,194 @@ module NanoRpc
|
|
6
6
|
def self.node
|
7
7
|
@node ||= Node.new
|
8
8
|
end
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
class NanoRpc::Node
|
12
|
+
include NanoRpc::Proxy
|
13
|
+
include NanoRpc::NodeHelper
|
14
|
+
|
15
|
+
attr_reader :host, :port, :auth, :headers, :node, :timeout
|
16
|
+
|
17
|
+
DEFAULT_TIMEOUT = 60
|
18
|
+
|
19
|
+
def initialize(
|
20
|
+
host: 'localhost',
|
21
|
+
port: 7076,
|
22
|
+
auth: nil,
|
23
|
+
headers: nil,
|
24
|
+
timeout: DEFAULT_TIMEOUT
|
25
|
+
)
|
26
|
+
@host = host
|
27
|
+
@port = port
|
28
|
+
@auth = auth
|
29
|
+
@headers = headers
|
30
|
+
@timeout = timeout
|
31
|
+
@node = self
|
32
|
+
|
33
|
+
super
|
34
|
+
end
|
22
35
|
|
23
|
-
|
24
|
-
|
36
|
+
def call(action, params = {})
|
37
|
+
args = { action: action }
|
38
|
+
args.merge!(params) if params.is_a?(Hash)
|
39
|
+
args = extract_proxy_args(args)
|
40
|
+
rpc_post(args)
|
41
|
+
end
|
25
42
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
43
|
+
# Condense host/port on object inspection
|
44
|
+
def inspect
|
45
|
+
"#{inspect_prefix}, @url=\"#{@host}:#{port}\">"
|
46
|
+
end
|
30
47
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
48
|
+
proxy_method :available_supply
|
49
|
+
proxy_method :block, required: %i[hash]
|
50
|
+
proxy_method :block_account, required: %i[hash]
|
51
|
+
proxy_method :block_confirm, required: %i[hash]
|
52
|
+
proxy_method :block_count
|
53
|
+
proxy_method :block_count_type
|
54
|
+
proxy_method :block_create,
|
55
|
+
required: %i[type key representative source],
|
56
|
+
optional: %i[work]
|
57
|
+
proxy_method :blocks, required: %i[hashes]
|
58
|
+
proxy_method :blocks_info,
|
59
|
+
required: %i[hashes],
|
60
|
+
optional: %i[pending source balance]
|
61
|
+
proxy_method :bootstrap, required: %i[address port]
|
62
|
+
proxy_method :bootstrap_any
|
63
|
+
proxy_method :chain, required: %i[block count]
|
64
|
+
proxy_method :confirmation_history
|
65
|
+
proxy_method :deterministic_key, required: %i[seed index]
|
66
|
+
proxy_method :frontier_count
|
67
|
+
proxy_method :history, required: %i[hash count]
|
68
|
+
proxy_method :keepalive, required: %i[address port]
|
69
|
+
proxy_method :key_create
|
70
|
+
proxy_method :key_expand, required: %i[key]
|
71
|
+
proxy_method :krai_from_raw, required: %i[amount]
|
72
|
+
proxy_method :krai_to_raw, required: %i[amount]
|
73
|
+
proxy_method :mrai_from_raw, required: %i[amount]
|
74
|
+
proxy_method :mrai_to_raw, required: %i[amount]
|
75
|
+
proxy_method :payment_wait, required: %i[account amount timeout]
|
76
|
+
proxy_method :peers
|
77
|
+
proxy_method :pending_exists, required: %i[hash]
|
78
|
+
proxy_method :process, required: %i[block]
|
79
|
+
proxy_method :rai_from_raw, required: %i[amount]
|
80
|
+
proxy_method :rai_to_raw, required: %i[amount]
|
81
|
+
proxy_method :receive_minimum
|
82
|
+
proxy_method :receive_minimum_set, required: %i[amount]
|
83
|
+
proxy_method :representatives
|
84
|
+
proxy_method :representatives_online
|
85
|
+
proxy_method :republish,
|
86
|
+
required: %i[hash],
|
87
|
+
optional: %i[count sources destinations]
|
88
|
+
proxy_method :search_pending, required: %i[wallet]
|
89
|
+
proxy_method :search_pending_all
|
90
|
+
proxy_method :stats, required: %i[type]
|
91
|
+
proxy_method :stop
|
92
|
+
proxy_method :successors, required: %i[block count]
|
93
|
+
proxy_method :unchecked, required: %i[count]
|
94
|
+
proxy_method :unchecked_clear
|
95
|
+
proxy_method :unchecked_get, required: %i[hash]
|
96
|
+
proxy_method :unchecked_keys, required: %i[key count]
|
97
|
+
proxy_method :receive_minimum
|
98
|
+
proxy_method :receive_minimum_set, required: %i[amount]
|
99
|
+
proxy_method :representatives
|
100
|
+
proxy_method :representatives_online
|
101
|
+
proxy_method :republish,
|
102
|
+
required: %i[hash],
|
103
|
+
optional: %i[count sources destinations]
|
104
|
+
proxy_method :search_pending, required: %i[wallet]
|
105
|
+
proxy_method :search_pending_all
|
106
|
+
proxy_method :stats, required: %i[type]
|
107
|
+
proxy_method :stop
|
108
|
+
proxy_method :successors, required: %i[block count]
|
109
|
+
proxy_method :unchecked, required: %i[count]
|
110
|
+
proxy_method :unchecked_clear
|
111
|
+
proxy_method :unchecked_get, required: %i[hash]
|
112
|
+
proxy_method :unchecked_keys, required: %i[key count]
|
113
|
+
proxy_method :version
|
114
|
+
proxy_method :wallet_create
|
115
|
+
proxy_method :work_cancel, required: %i[hash]
|
116
|
+
proxy_method :work_generate,
|
117
|
+
required: %i[hash],
|
118
|
+
optional: %i[use_peers]
|
119
|
+
proxy_method :work_peer_add, required: %i[address port]
|
120
|
+
proxy_method :work_peers
|
121
|
+
proxy_method :work_peers_clear
|
122
|
+
proxy_method :work_validate, required: %i[work hash]
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def extract_proxy_args(args)
|
127
|
+
args.each do |k, v|
|
128
|
+
m = proxy_method(v)
|
129
|
+
args[k] = v.send(m) if m
|
36
130
|
end
|
131
|
+
args
|
132
|
+
end
|
37
133
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
required: %i[type key representative source],
|
46
|
-
optional: %i[work]
|
47
|
-
proxy_method :blocks, required: %i[hashes]
|
48
|
-
proxy_method :blocks_info,
|
49
|
-
required: %i[hashes],
|
50
|
-
optional: %i[pending source balance]
|
51
|
-
proxy_method :bootstrap, required: %i[address port]
|
52
|
-
proxy_method :bootstrap_any
|
53
|
-
proxy_method :chain, required: %i[block count]
|
54
|
-
proxy_method :confirmation_history
|
55
|
-
proxy_method :deterministic_key, required: %i[seed index]
|
56
|
-
proxy_method :frontier_count
|
57
|
-
proxy_method :history, required: %i[hash count]
|
58
|
-
proxy_method :keepalive, required: %i[address port]
|
59
|
-
proxy_method :key_create
|
60
|
-
proxy_method :key_expand, required: %i[key]
|
61
|
-
proxy_method :krai_from_raw, required: %i[amount]
|
62
|
-
proxy_method :krai_to_raw, required: %i[amount]
|
63
|
-
proxy_method :mrai_from_raw, required: %i[amount]
|
64
|
-
proxy_method :mrai_to_raw, required: %i[amount]
|
65
|
-
proxy_method :payment_wait, required: %i[account amount timeout]
|
66
|
-
proxy_method :peers
|
67
|
-
proxy_method :pending_exists, required: %i[hash]
|
68
|
-
proxy_method :process, required: %i[block]
|
69
|
-
proxy_method :rai_from_raw, required: %i[amount]
|
70
|
-
proxy_method :rai_to_raw, required: %i[amount]
|
71
|
-
proxy_method :receive_minimum
|
72
|
-
proxy_method :receive_minimum_set, required: %i[amount]
|
73
|
-
proxy_method :representatives
|
74
|
-
proxy_method :representatives_online
|
75
|
-
proxy_method :republish,
|
76
|
-
required: %i[hash],
|
77
|
-
optional: %i[count sources destinations]
|
78
|
-
proxy_method :search_pending, required: %i[wallet]
|
79
|
-
proxy_method :search_pending_all
|
80
|
-
proxy_method :stats, required: %i[type]
|
81
|
-
proxy_method :stop
|
82
|
-
proxy_method :successors, required: %i[block count]
|
83
|
-
proxy_method :unchecked, required: %i[count]
|
84
|
-
proxy_method :unchecked_clear
|
85
|
-
proxy_method :unchecked_get, required: %i[hash]
|
86
|
-
proxy_method :unchecked_keys, required: %i[key count]
|
87
|
-
proxy_method :version
|
88
|
-
proxy_method :wallet_create
|
89
|
-
proxy_method :work_cancel, required: %i[hash]
|
90
|
-
proxy_method :work_generate,
|
91
|
-
required: %i[hash],
|
92
|
-
optional: %i[use_peers]
|
93
|
-
proxy_method :work_peer_add, required: %i[address port]
|
94
|
-
proxy_method :work_peers
|
95
|
-
proxy_method :work_peers_clear
|
96
|
-
proxy_method :work_validate, required: %i[work hash]
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
def extract_proxy_args(args)
|
101
|
-
args.each do |k, v|
|
102
|
-
m = proxy_method(v)
|
103
|
-
args[k] = v.send(m) if m
|
104
|
-
end
|
105
|
-
args
|
134
|
+
def proxy_method(obj)
|
135
|
+
if obj.is_a?(NanoRpc::Wallet)
|
136
|
+
:seed
|
137
|
+
elsif obj.is_a?(NanoRpc::Accounts)
|
138
|
+
:addresses
|
139
|
+
elsif obj.is_a?(NanoRpc::Account)
|
140
|
+
:address
|
106
141
|
end
|
142
|
+
end
|
107
143
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
elsif obj.is_a?(NanoRpc::Account)
|
114
|
-
:address
|
115
|
-
end
|
116
|
-
end
|
144
|
+
def rpc_post(params)
|
145
|
+
response = rest_client_post(params)
|
146
|
+
ensure_status_success(response)
|
147
|
+
data = NanoRpc::Response.new(JSON[response&.body])
|
148
|
+
ensure_valid_response(data)
|
117
149
|
|
118
|
-
|
119
|
-
|
120
|
-
ensure_status_success(response)
|
121
|
-
data = NanoRpc::Response.new(JSON[response&.body])
|
122
|
-
ensure_valid_response(data)
|
150
|
+
data
|
151
|
+
end
|
123
152
|
|
124
|
-
|
125
|
-
|
153
|
+
def request_headers
|
154
|
+
h = headers || {}
|
155
|
+
h['Content-Type'] = 'json'
|
156
|
+
h['Authorization'] = auth unless auth.nil?
|
157
|
+
h
|
158
|
+
end
|
126
159
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
160
|
+
def rest_client_post(params)
|
161
|
+
execute_post(params)
|
162
|
+
rescue Errno::ECONNREFUSED
|
163
|
+
raise NanoRpc::NodeConnectionFailure,
|
164
|
+
"Node connection failure at #{url}"
|
165
|
+
rescue RestClient::Exceptions::OpenTimeout
|
166
|
+
raise NanoRpc::NodeOpenTimeout,
|
167
|
+
'Node failed to respond in time'
|
168
|
+
end
|
133
169
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
170
|
+
def execute_post(params)
|
171
|
+
RestClient::Request.execute(
|
172
|
+
method: :post,
|
173
|
+
url: url,
|
174
|
+
headers: request_headers,
|
175
|
+
payload: params.to_json,
|
176
|
+
timeout: timeout
|
177
|
+
)
|
178
|
+
end
|
143
179
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
end
|
180
|
+
def url
|
181
|
+
if host.start_with?('http://', 'https://')
|
182
|
+
"#{host}:#{port}"
|
183
|
+
else
|
184
|
+
"http://#{host}:#{port}"
|
150
185
|
end
|
186
|
+
end
|
151
187
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
188
|
+
def ensure_status_success(response)
|
189
|
+
return if response&.code == 200
|
190
|
+
raise NanoRpc::BadRequest,
|
191
|
+
"Error response from node: #{JSON[response&.body]}"
|
192
|
+
end
|
157
193
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
end
|
194
|
+
def ensure_valid_response(data)
|
195
|
+
return unless data['error']
|
196
|
+
raise NanoRpc::InvalidRequest,
|
197
|
+
"Invalid request: #{data['error']}"
|
163
198
|
end
|
164
199
|
end
|
data/lib/nano_rpc/version.rb
CHANGED