raiblocks_rpc 0.1.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +21 -0
- data/README.md +97 -0
- data/Rakefile +6 -0
- data/bin/console +7 -0
- data/bin/setup +8 -0
- data/lib/raiblocks_rpc/client.rb +46 -0
- data/lib/raiblocks_rpc/errors.rb +8 -0
- data/lib/raiblocks_rpc/proxies/account.rb +50 -0
- data/lib/raiblocks_rpc/proxies/accounts.rb +32 -0
- data/lib/raiblocks_rpc/proxies/network.rb +37 -0
- data/lib/raiblocks_rpc/proxies/node.rb +35 -0
- data/lib/raiblocks_rpc/proxies/util.rb +16 -0
- data/lib/raiblocks_rpc/proxies/wallet.rb +48 -0
- data/lib/raiblocks_rpc/proxy.rb +130 -0
- data/lib/raiblocks_rpc/response.rb +21 -0
- data/lib/raiblocks_rpc/version.rb +4 -0
- data/lib/raiblocks_rpc.rb +12 -0
- data/raiblocks_rpc.gemspec +37 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 80b65b8a94a9de27dc3c58f9c04b69b7b3a40e8395db0fbad5f2a9e764951628
|
4
|
+
data.tar.gz: 6bb5855728354d9ae1cfaf2e5fca3ac6c61fd82e8db08f9f3a8e34744320d105
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c4ab4f72e63fe1c86fe82d2ee77b238705e735103768e0a9e1375ca98881e1e5adb9e481b08ade5ba3349a58ba758327b95422b63ede2a61d67f877d7fa93301
|
7
|
+
data.tar.gz: 403d5679bc3b9717bb2d6cc540e649ba54eae73d52c68999e96834f06bbf55f596c186183e8091863fdc0faefd2ec5ec98202fb5103555ea682f9ba4be558c70
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.5.0
|
3
|
+
Exclude:
|
4
|
+
- 'bin/*'
|
5
|
+
DisplayCopNames: true
|
6
|
+
Style/ClassAndModuleChildren:
|
7
|
+
EnforcedStyle: compact
|
8
|
+
Style/EmptyMethod:
|
9
|
+
EnforcedStyle: expanded
|
10
|
+
Layout/EmptyLineAfterMagicComment:
|
11
|
+
Enabled: false
|
12
|
+
Documentation:
|
13
|
+
Enabled: false
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Justin Craig-Kuhn
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# RaiBlocksRpc
|
2
|
+
|
3
|
+
An RPC wrapper for RaiBlocks written in Ruby. It connects to an individual node that you control. There's a client object you can use to make explicit RPC calls as well as proxy objects with logically grouped methods.
|
4
|
+
|
5
|
+
To run a RaiBlocks node locally, see [Docker documentation](https://github.com/clemahieu/raiblocks/wiki/Docker-node).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'raiblocks_rpc'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install raiblocks_rpc
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
There are two ways to use this gem. You can make direct calls to the RPC client or use the provided proxy objects.
|
26
|
+
|
27
|
+
In either case, the client should first be configured to connect to a RaiBlocks node. If you do not specify host or port before using the client, then `localhost:7076` will be used by default.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
RaiblocksRpc::Client.host = 'localhost'
|
31
|
+
RaiblocksRpc::Client.port = 7076
|
32
|
+
````
|
33
|
+
|
34
|
+
### Raw RPC Calls
|
35
|
+
|
36
|
+
You can use the RPC client to make raw RPC calls to a RaiBlocks node according to the [documentation](https://github.com/clemahieu/raiblocks/wiki/RPC-protocol).
|
37
|
+
|
38
|
+
Every call 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.
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
RaiblocksRpc::Client.instance.call(:account_balance, account: 'xrb_someaddress1234')
|
42
|
+
# => {"balance"=>100, "pending"=>0}
|
43
|
+
````
|
44
|
+
|
45
|
+
Response data are provided as `Hashie` objects with integer coercion, indifferent access, and method access included so you have several options for accessing values.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
data = RaiblocksRpc::Client.instance.call(:account_balance, account: 'xrb_someaddress1234')
|
49
|
+
# => {"balance"=>100, "pending"=>0}
|
50
|
+
data.balance
|
51
|
+
# => 100
|
52
|
+
data[:balance]
|
53
|
+
# => 100
|
54
|
+
data['balance']
|
55
|
+
# => 100
|
56
|
+
````
|
57
|
+
|
58
|
+
### Proxy Objects
|
59
|
+
|
60
|
+
A few proxy objects are provided as a means to logically group RPC calls. Here we do not strictly follow the grouping as expressed in the [RaiBlocks RPC documentation](https://github.com/clemahieu/raiblocks/wiki/RPC-protocol). Instead, the following objects are provided:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
RaiblocksRpc::Account # { account: 'xrb_address12345' }
|
64
|
+
RaiblocksRpc::Accounts # { accounts: ['xrb_address12345', 'xrb_address67890] }
|
65
|
+
RaiblocksRpc::Wallet # { wallet: 'F3093AB' }
|
66
|
+
RaiblocksRpc::Network
|
67
|
+
RaiblocksRpc::Node
|
68
|
+
RaiblocksRpc::Util
|
69
|
+
```
|
70
|
+
|
71
|
+
`Account`, `Accounts`, and `Wallet` each require parameters to be passed during initialization. You can then make calls on these objects without needing to pass in the params for subsequent calls.
|
72
|
+
|
73
|
+
Methods whose prefix matches the class name, such as `account_balance`, also have an abbreviated version, in this case `balance`.
|
74
|
+
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
account = RaiblocksRpc::Account.new('xrb_someaddress1234')
|
78
|
+
|
79
|
+
account.balance
|
80
|
+
# => {"balance"=>100, "pending"=>0}
|
81
|
+
account.account_balance
|
82
|
+
# => {"balance"=>100, "pending"=>0}
|
83
|
+
```
|
84
|
+
|
85
|
+
Some methods appear on multiple objects for convenience.
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
RaiblocksRpc::Node.new.block_count
|
89
|
+
# => {"count"=>314848, "unchecked"=>4793586}
|
90
|
+
|
91
|
+
RaiblocksRpc::Network.new.block_count
|
92
|
+
# => {"count"=>314848, "unchecked"=>4793642}
|
93
|
+
```
|
94
|
+
|
95
|
+
## License
|
96
|
+
|
97
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'singleton'
|
3
|
+
require 'rest-client'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class RaiblocksRpc::Client
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :host, :port
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(action, params = {})
|
14
|
+
post({ action: action }.merge(params))
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def post(params)
|
20
|
+
response = RestClient.post(url, params.to_json)
|
21
|
+
ensure_status_success!(response)
|
22
|
+
|
23
|
+
data = RaiblocksRpc::Response.new(JSON[response.body])
|
24
|
+
ensure_valid_response!(data)
|
25
|
+
|
26
|
+
data
|
27
|
+
end
|
28
|
+
|
29
|
+
def url
|
30
|
+
self.class.host ||= 'localhost'
|
31
|
+
self.class.port ||= 7076
|
32
|
+
"http://#{self.class.host}:#{self.class.port}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def ensure_status_success!(response)
|
36
|
+
return if response.code == 200
|
37
|
+
raise RaiblocksRpc::BadRequest,
|
38
|
+
"Error response from node: #{JSON[response.body]}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def ensure_valid_response!(data)
|
42
|
+
return unless data['error']
|
43
|
+
raise RaiblocksRpc::InvalidRequest,
|
44
|
+
"Invalid request: #{data['error']}"
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module RaiblocksRpc
|
3
|
+
class BadRequest < StandardError; end
|
4
|
+
class InvalidRequest < StandardError; end
|
5
|
+
class InvalidParameterType < StandardError; end
|
6
|
+
class ForbiddenParameter < StandardError; end
|
7
|
+
class MissingParameters < StandardError; end
|
8
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class RaiblocksRpc::Account < RaiblocksRpc::Proxy
|
3
|
+
attr_accessor :address
|
4
|
+
|
5
|
+
def initialize(address)
|
6
|
+
unless address
|
7
|
+
raise RaiblocksRpc::MissingArguments,
|
8
|
+
'Missing argument: address (str)'
|
9
|
+
end
|
10
|
+
|
11
|
+
self.address = address
|
12
|
+
end
|
13
|
+
|
14
|
+
def proxy_params
|
15
|
+
{ account: :address }
|
16
|
+
end
|
17
|
+
|
18
|
+
def proxy_methods
|
19
|
+
{
|
20
|
+
account_balance: nil,
|
21
|
+
account_block_count: nil,
|
22
|
+
account_info: nil,
|
23
|
+
account_create: { required: %i[wallet] },
|
24
|
+
account_history: { required: %i[count] },
|
25
|
+
account_list: nil,
|
26
|
+
account_move: { required: %i[wallet source accounts] },
|
27
|
+
account_key: nil,
|
28
|
+
account_remove: { required: %i[wallet] },
|
29
|
+
account_representative: nil,
|
30
|
+
account_representative_set: { required: %i[wallet representative] },
|
31
|
+
account_weight: nil,
|
32
|
+
delegators: nil,
|
33
|
+
delegators_count: nil,
|
34
|
+
frontiers: { required: %i[count] },
|
35
|
+
frontier_count: nil,
|
36
|
+
ledger: { required: %i[count] },
|
37
|
+
validate_account_number: nil,
|
38
|
+
pending: { required: %i[count], optional: %i[threshold exists] },
|
39
|
+
payment_wait: { required: %i[amount timeout] },
|
40
|
+
accounts_balances: { required: %i[accounts] },
|
41
|
+
accounts_create: {
|
42
|
+
required: %i[accounts wallet count], optional: %i[work]
|
43
|
+
},
|
44
|
+
accounts_frontiers: { required: %i[accounts] },
|
45
|
+
accounts_pending: {
|
46
|
+
required: %i[accounts count], optional: %i[threshold source]
|
47
|
+
}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class RaiblocksRpc::Accounts < RaiblocksRpc::Proxy
|
3
|
+
attr_accessor :addresses
|
4
|
+
|
5
|
+
def initialize(addresses)
|
6
|
+
unless addresses.is_a?(Array)
|
7
|
+
raise RaiblocksRpc::MissingArguments,
|
8
|
+
'Missing argument: addresses (str[])'
|
9
|
+
end
|
10
|
+
|
11
|
+
self.addresses = addresses
|
12
|
+
end
|
13
|
+
|
14
|
+
def proxy_params
|
15
|
+
{ accounts: :addresses }
|
16
|
+
end
|
17
|
+
|
18
|
+
def proxy_methods
|
19
|
+
{
|
20
|
+
accounts_balances: nil,
|
21
|
+
accounts_create: { required: %i[wallet count], optional: %i[work] },
|
22
|
+
accounts_frontiers: nil,
|
23
|
+
accounts_pending: { required: %i[count], optional: %i[threshold source] }
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
# TODO implement ability to instantiate Account instances like
|
28
|
+
# accounts = Accounts.new(['abc', 'def'])
|
29
|
+
# accounts.first
|
30
|
+
# => RaiblocksRpc::Account address='abc'
|
31
|
+
# [], each (more iterators?)
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class RaiblocksRpc::Network < RaiblocksRpc::Proxy
|
3
|
+
def proxy_methods
|
4
|
+
{
|
5
|
+
available_supply: nil,
|
6
|
+
block: { required: %i[hash] },
|
7
|
+
blocks: { required: %i[hashes] },
|
8
|
+
blocks_info: { required: %i[hashes], optional: %i[pending source] },
|
9
|
+
block_account: { required: %i[hash] },
|
10
|
+
block_count: nil,
|
11
|
+
block_count_type: nil,
|
12
|
+
chain: { required: %i[block count] },
|
13
|
+
history: { required: %i[hash count] },
|
14
|
+
block_create: {
|
15
|
+
required: %i[type key representative source], optional: %i[work]
|
16
|
+
},
|
17
|
+
process: { required: %i[block] },
|
18
|
+
republish: {
|
19
|
+
required: %i[hash], optional: %i[count sources destinations]
|
20
|
+
},
|
21
|
+
successors: { required: %i[block count] },
|
22
|
+
pending_exists: { required: %i[hash] },
|
23
|
+
unchecked: { required: %i[count] },
|
24
|
+
unchecked_clear: nil,
|
25
|
+
unchecked_get: { required: %i[hash] },
|
26
|
+
unchecked_keys: { required: %i[key count] },
|
27
|
+
work_cancel: { required: %i[hash] },
|
28
|
+
work_generate: { required: %i[hash] },
|
29
|
+
payment_wait: { required: %i[account amount timeout] },
|
30
|
+
work_validate: { required: %i[work hash] },
|
31
|
+
bootstrap: { required: %i[address port] },
|
32
|
+
keepalive: { required: %i[address port] },
|
33
|
+
work_peer_add: { required: %i[address port] },
|
34
|
+
bootstrap_any: nil
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class RaiblocksRpc::Node < RaiblocksRpc::Proxy
|
3
|
+
def proxy_methods
|
4
|
+
{
|
5
|
+
bootstrap: { required: %i[address port] },
|
6
|
+
bootstrap_any: nil,
|
7
|
+
keepalive: { required: %i[address port] },
|
8
|
+
work_peer_add: { required: %i[address port] },
|
9
|
+
deterministic_key: { required: %i[seed index] },
|
10
|
+
receive_minimum: nil,
|
11
|
+
receive_minimum_set: { required: %i[amount] },
|
12
|
+
representatives: nil,
|
13
|
+
stop: nil,
|
14
|
+
version: nil,
|
15
|
+
peers: nil,
|
16
|
+
work_peers: nil,
|
17
|
+
work_peers_clear: nil,
|
18
|
+
work_validate: { required: %i[work hash] },
|
19
|
+
search_pending: { required: %i[wallet] },
|
20
|
+
search_pending_all: nil,
|
21
|
+
available_supply: nil,
|
22
|
+
block: { required: %i[hash] },
|
23
|
+
blocks: { required: %i[hashes] },
|
24
|
+
blocks_info: { required: %i[hashes], optional: %i[pending source] },
|
25
|
+
block_account: { required: %i[hash] },
|
26
|
+
block_count: nil,
|
27
|
+
block_count_type: nil,
|
28
|
+
unchecked: { required: %i[count] },
|
29
|
+
unchecked_clear: nil,
|
30
|
+
unchecked_get: { required: %i[hash] },
|
31
|
+
unchecked_keys: { required: %i[key count] },
|
32
|
+
payment_wait: { required: %i[account amount timeout] }
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class RaiblocksRpc::Util < RaiblocksRpc::Proxy
|
3
|
+
def proxy_methods
|
4
|
+
{
|
5
|
+
mrai_from_raw: { required: %i[amount] },
|
6
|
+
mrai_to_raw: { required: %i[amount] },
|
7
|
+
krai_from_raw: { required: %i[amount] },
|
8
|
+
krai_to_raw: { required: %i[amount] },
|
9
|
+
rai_from_raw: { required: %i[amount] },
|
10
|
+
rai_to_raw: { required: %i[amount] },
|
11
|
+
key_create: nil,
|
12
|
+
key_expand: { required: %i[key] },
|
13
|
+
work_validate: { required: %i[work hash] }
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class RaiblocksRpc::Wallet < RaiblocksRpc::Proxy
|
3
|
+
attr_accessor :seed
|
4
|
+
|
5
|
+
def initialize(wallet_seed)
|
6
|
+
unless wallet_address.is_a?(String) || public_key.is_a?(Symbol)
|
7
|
+
raise RaiblocksRpc::MissingArguments,
|
8
|
+
'Missing argument: wallet_seed (str)'
|
9
|
+
end
|
10
|
+
|
11
|
+
self.seed = wallet_seed
|
12
|
+
end
|
13
|
+
|
14
|
+
def proxy_params
|
15
|
+
{ wallet: :seed }
|
16
|
+
end
|
17
|
+
|
18
|
+
def proxy_methods
|
19
|
+
{
|
20
|
+
wallet_balances: nil,
|
21
|
+
wallet_add: { required: %i[key], optional: %i[work] },
|
22
|
+
password_change: { required: %i[password] },
|
23
|
+
wallet_change_seed: { required: %i[seed] },
|
24
|
+
wallet_contains: { required: %i[account] },
|
25
|
+
wallet_create: nil,
|
26
|
+
wallet_destroy: nil,
|
27
|
+
wallet_export: nil,
|
28
|
+
wallet_frontiers: nil,
|
29
|
+
wallet_locked: nil,
|
30
|
+
password_enter: { required: %i[password] },
|
31
|
+
wallet_pending: { required: %i[count], optional: %i[threshold source] },
|
32
|
+
wallet_republish: { required: %i[count] },
|
33
|
+
wallet_balance_total: nil,
|
34
|
+
password_valid: nil,
|
35
|
+
wallet_work_get: nil,
|
36
|
+
send: { required: %[wallet source destination amount] },
|
37
|
+
work_get: nil,
|
38
|
+
work_set: nil,
|
39
|
+
search_pending: nil,
|
40
|
+
wallet_representative: nil,
|
41
|
+
wallet_representative_set: %i[representative],
|
42
|
+
payment_begin: nil,
|
43
|
+
payment_init: nil,
|
44
|
+
payment_end: { required: %i[account] },
|
45
|
+
receive: { required: %i[account block] }
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class RaiblocksRpc::Proxy
|
3
|
+
attr_accessor :params, :param_signature, :m
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def proxy_methods
|
8
|
+
raise 'Child class must override `proxy_methods` method'
|
9
|
+
end
|
10
|
+
|
11
|
+
def proxy_params
|
12
|
+
{}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Define proxy methods based on #proxy_methods
|
16
|
+
def method_missing(m, *args, &_block)
|
17
|
+
set_accessors(m)
|
18
|
+
if valid_proxy_method?
|
19
|
+
define_proxy_method(m)
|
20
|
+
return send(m, args.first)
|
21
|
+
end
|
22
|
+
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def respond_to_missing?(m, include_private = false)
|
27
|
+
set_accessors(m)
|
28
|
+
valid_proxy_method? || super
|
29
|
+
end
|
30
|
+
|
31
|
+
# Valid proxy methods are:
|
32
|
+
# (1) The raw name of an `action` as passed to the RPC server
|
33
|
+
# (e.g. `account_balance`)
|
34
|
+
# (2) An abbreviation of an `action` such as `balance` from `account_balance`
|
35
|
+
# where `account` is the lowercase name of the encapsulating class.
|
36
|
+
def valid_proxy_method?
|
37
|
+
rpc_action? || rpc_action_abbrev?
|
38
|
+
end
|
39
|
+
|
40
|
+
def rpc_action
|
41
|
+
return method_expansion if rpc_action_abbrev?
|
42
|
+
m
|
43
|
+
end
|
44
|
+
|
45
|
+
def rpc_action?
|
46
|
+
proxy_method_names.include?(m)
|
47
|
+
end
|
48
|
+
|
49
|
+
def rpc_action_abbrev?
|
50
|
+
proxy_method_names.each do |proxy_m|
|
51
|
+
proxy_m = proxy_m.to_s
|
52
|
+
next unless proxy_m.start_with?(action_prefix)
|
53
|
+
return true if m.to_s == action_abbrev(proxy_m)
|
54
|
+
end
|
55
|
+
|
56
|
+
false
|
57
|
+
end
|
58
|
+
|
59
|
+
def action_abbrev(proxy_m)
|
60
|
+
proxy_m.to_s[action_prefix.size..-1]
|
61
|
+
end
|
62
|
+
|
63
|
+
def method_expansion
|
64
|
+
"#{action_prefix}#{m}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def proxy_method_names
|
68
|
+
@proxy_method_names ||= proxy_methods.keys
|
69
|
+
end
|
70
|
+
|
71
|
+
def action_prefix
|
72
|
+
@action_prefix ||= self.class.name.split('::').last.downcase + '_'
|
73
|
+
end
|
74
|
+
|
75
|
+
def define_proxy_method(m)
|
76
|
+
self.class.send(:define_method, m) do |opts = {}|
|
77
|
+
set_accessors(m, opts)
|
78
|
+
populate_and_validate_params!
|
79
|
+
RaiblocksRpc::Client.instance.call(rpc_action, params)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_accessors(m, opts = nil)
|
84
|
+
self.m = m
|
85
|
+
self.param_signature = proxy_methods[m.to_sym]
|
86
|
+
self.params = validate_opts!(opts)
|
87
|
+
end
|
88
|
+
|
89
|
+
def populate_and_validate_params!
|
90
|
+
proxy_params.each { |k, v| self.params[k] ||= send(v) }
|
91
|
+
validate_params!
|
92
|
+
end
|
93
|
+
|
94
|
+
def validate_params!
|
95
|
+
return if param_signature.nil?
|
96
|
+
ensure_required_params!
|
97
|
+
ensure_no_forbidden_params!
|
98
|
+
end
|
99
|
+
|
100
|
+
def allowed_params
|
101
|
+
proxy_params.keys +
|
102
|
+
(param_signature[:required] || []) +
|
103
|
+
(param_signature[:optional] || [])
|
104
|
+
end
|
105
|
+
|
106
|
+
def validate_opts!(opts)
|
107
|
+
return opts if opts.is_a?(Hash)
|
108
|
+
return {} if opts.nil?
|
109
|
+
raise RaiblocksRpc::InvalidParameterType,
|
110
|
+
'You must pass a hash to an action method'
|
111
|
+
end
|
112
|
+
|
113
|
+
def params_keys
|
114
|
+
params.keys.map(&:to_sym)
|
115
|
+
end
|
116
|
+
|
117
|
+
def ensure_required_params!
|
118
|
+
missing_params = param_signature[:required] - params_keys
|
119
|
+
return unless missing_params.any?
|
120
|
+
raise RaiblocksRpc::MissingParameters,
|
121
|
+
"Missing required parameter(s): #{missing_params.join(', ')}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def ensure_no_forbidden_params!
|
125
|
+
forbidden_params = params_keys - allowed_params
|
126
|
+
return unless forbidden_params.any?
|
127
|
+
raise RaiblocksRpc::ForbiddenParameter,
|
128
|
+
"Forbidden parameter(s) passed: #{forbidden_params.join(', ')}"
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'hashie'
|
3
|
+
|
4
|
+
class RaiblocksRpc::Response < Hash
|
5
|
+
include ::Hashie::Extensions::MergeInitializer
|
6
|
+
include ::Hashie::Extensions::IndifferentAccess
|
7
|
+
include ::Hashie::Extensions::MethodAccess
|
8
|
+
|
9
|
+
def initialize(hash = {})
|
10
|
+
super
|
11
|
+
coerce_integers
|
12
|
+
end
|
13
|
+
|
14
|
+
def coerce_integers
|
15
|
+
merge!(self) do |_k, v|
|
16
|
+
Integer(v)
|
17
|
+
rescue ArgumentError
|
18
|
+
v
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'raiblocks_rpc/client'
|
3
|
+
require 'raiblocks_rpc/errors'
|
4
|
+
require 'raiblocks_rpc/proxy'
|
5
|
+
require 'raiblocks_rpc/response'
|
6
|
+
require 'raiblocks_rpc/version'
|
7
|
+
require 'raiblocks_rpc/proxies/account'
|
8
|
+
require 'raiblocks_rpc/proxies/accounts'
|
9
|
+
require 'raiblocks_rpc/proxies/network'
|
10
|
+
require 'raiblocks_rpc/proxies/node'
|
11
|
+
require 'raiblocks_rpc/proxies/util'
|
12
|
+
require 'raiblocks_rpc/proxies/wallet'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'raiblocks_rpc/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'raiblocks_rpc'
|
8
|
+
spec.version = RaiblocksRpc::VERSION
|
9
|
+
spec.authors = ['Justin Craig-Kuhn (JCK)']
|
10
|
+
spec.email = ['jcraigk@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = 'RPC wrapper for RaiBlocks nodes written in Ruby'
|
13
|
+
spec.description = 'An RPC wrapper for RaiBlocks nodes written in Ruby.' \
|
14
|
+
'It connects to an individual node that you control. ' \
|
15
|
+
"There's a client object you can use to make explicit " \
|
16
|
+
'RPC calls as well as proxy objects with logically ' \
|
17
|
+
'grouped methods.'
|
18
|
+
spec.homepage = 'https://github.com/jcraigk/ruby_raiblocks_rpc'
|
19
|
+
spec.license = 'MIT'
|
20
|
+
|
21
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
22
|
+
f.match(%r{^(test|spec|features)/})
|
23
|
+
end
|
24
|
+
spec.bindir = 'exe'
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = %w[lib]
|
27
|
+
|
28
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
29
|
+
spec.add_development_dependency 'pry', '~> 0.11.3'
|
30
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
31
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
32
|
+
spec.add_development_dependency 'simplecov', '~> 0.15.1'
|
33
|
+
spec.add_development_dependency 'rubocop', '~> 0.52.1'
|
34
|
+
|
35
|
+
spec.add_runtime_dependency 'hashie', '~> 3.5', '>= 3.5.7'
|
36
|
+
spec.add_runtime_dependency 'rest-client', '~> 2.0', '>= 2.0.2'
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: raiblocks_rpc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Justin Craig-Kuhn (JCK)
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-01-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.11.3
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.11.3
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.15.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.15.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.52.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.52.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: hashie
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.5'
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 3.5.7
|
107
|
+
type: :runtime
|
108
|
+
prerelease: false
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - "~>"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '3.5'
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 3.5.7
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: rest-client
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '2.0'
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 2.0.2
|
127
|
+
type: :runtime
|
128
|
+
prerelease: false
|
129
|
+
version_requirements: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '2.0'
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 2.0.2
|
137
|
+
description: An RPC wrapper for RaiBlocks nodes written in Ruby.It connects to an
|
138
|
+
individual node that you control. There's a client object you can use to make explicit
|
139
|
+
RPC calls as well as proxy objects with logically grouped methods.
|
140
|
+
email:
|
141
|
+
- jcraigk@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".rspec"
|
148
|
+
- ".rubocop.yml"
|
149
|
+
- Gemfile
|
150
|
+
- LICENSE.txt
|
151
|
+
- README.md
|
152
|
+
- Rakefile
|
153
|
+
- bin/console
|
154
|
+
- bin/setup
|
155
|
+
- lib/raiblocks_rpc.rb
|
156
|
+
- lib/raiblocks_rpc/client.rb
|
157
|
+
- lib/raiblocks_rpc/errors.rb
|
158
|
+
- lib/raiblocks_rpc/proxies/account.rb
|
159
|
+
- lib/raiblocks_rpc/proxies/accounts.rb
|
160
|
+
- lib/raiblocks_rpc/proxies/network.rb
|
161
|
+
- lib/raiblocks_rpc/proxies/node.rb
|
162
|
+
- lib/raiblocks_rpc/proxies/util.rb
|
163
|
+
- lib/raiblocks_rpc/proxies/wallet.rb
|
164
|
+
- lib/raiblocks_rpc/proxy.rb
|
165
|
+
- lib/raiblocks_rpc/response.rb
|
166
|
+
- lib/raiblocks_rpc/version.rb
|
167
|
+
- raiblocks_rpc.gemspec
|
168
|
+
homepage: https://github.com/jcraigk/ruby_raiblocks_rpc
|
169
|
+
licenses:
|
170
|
+
- MIT
|
171
|
+
metadata: {}
|
172
|
+
post_install_message:
|
173
|
+
rdoc_options: []
|
174
|
+
require_paths:
|
175
|
+
- lib
|
176
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
requirements: []
|
187
|
+
rubyforge_project:
|
188
|
+
rubygems_version: 2.7.3
|
189
|
+
signing_key:
|
190
|
+
specification_version: 4
|
191
|
+
summary: RPC wrapper for RaiBlocks nodes written in Ruby
|
192
|
+
test_files: []
|