raiblocks_rpc 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+ module Raiblocks::Proxy
3
+ attr_accessor :client
4
+
5
+ def initialize(opts = {})
6
+ @client = opts[:client] || Raiblocks.client
7
+ end
8
+
9
+ def self.included(base)
10
+ base.extend(ClassMethods)
11
+ end
12
+ module ClassMethods
13
+ attr_reader :proxy_method_def, :proxy_param_def
14
+
15
+ def proxy_params(param_def = nil)
16
+ @proxy_param_def = param_def
17
+ end
18
+
19
+ def proxy_method(name, signature = nil)
20
+ @proxy_method_def ||= {}
21
+ @proxy_method_def[name] = signature
22
+ end
23
+
24
+ def proxy_methods
25
+ proxy_method_def.keys.sort
26
+ end
27
+
28
+ def methods
29
+ (super + proxy_methods).sort
30
+ end
31
+
32
+ def define_proxy_method(m, singleton = false)
33
+ send(
34
+ singleton ? :define_singleton_method : :define_method,
35
+ method_alias(m)
36
+ ) do |opts = {}|
37
+ params = Raiblocks::ProxyContext.new(
38
+ singleton ? self : self.class, m, opts
39
+ ).populate_params(singleton ? nil : base_params)
40
+ data = Raiblocks.client.call(m, params)
41
+ data.is_a?(Hash) && data.keys.map(&:to_s) == [m.to_s] ? data[m] : data
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ # Raiblocks `send` action is also the method caller in Ruby ;)
48
+ def method_alias(m)
49
+ m == :send ? :tx_send : m
50
+ end
51
+
52
+ def method_missing(m, *args, &_block)
53
+ return super unless valid_method?(m)
54
+ define_proxy_method(m, true)
55
+ send(m, args.first)
56
+ end
57
+
58
+ def respond_to_missing?(m, include_private = false)
59
+ valid_method?(m) || super
60
+ end
61
+
62
+ def valid_method?(m)
63
+ proxy_param_def.nil? && methods.include?(m)
64
+ end
65
+
66
+ def proxy_context(m)
67
+ @proxy_context ||= {}
68
+ @proxy_context[m] ||= Raiblocks::ProxyContext.new(self, m)
69
+ end
70
+ end
71
+
72
+ def proxy_methods
73
+ self.class.proxy_methods
74
+ end
75
+
76
+ def methods
77
+ (super + proxy_methods).sort
78
+ end
79
+
80
+ private
81
+
82
+ def base_params
83
+ return if self.class.proxy_param_def.nil?
84
+ self.class
85
+ .proxy_param_def
86
+ .each_with_object({}) do |(k, v), params|
87
+ params[k] ||= send(v)
88
+ end
89
+ end
90
+
91
+ def method_missing(m, *args, &_block)
92
+ return super unless methods.include?(m)
93
+ self.class.define_proxy_method(m)
94
+ send(m, args.first)
95
+ end
96
+
97
+ def respond_to_missing?(m, include_private = false)
98
+ methods.include?(m) || super
99
+ end
100
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+ class Raiblocks::ProxyContext
3
+ def initialize(klass, m, opts = {})
4
+ @klass = klass
5
+ @method_def = klass.proxy_method_def
6
+ @param_def = klass.proxy_param_def
7
+ @m = m
8
+ @opts = opts
9
+ end
10
+
11
+ def valid_proxy_method?
12
+ rpc_action?
13
+ end
14
+
15
+ def populate_params(params)
16
+ opts = validate_opts!
17
+ opts.merge!(params) if params
18
+ validate_params!
19
+ opts.delete_if { |_k, v| v.nil? }
20
+ opts
21
+ end
22
+
23
+ def validate_opts!
24
+ return @opts if @opts.is_a?(Hash)
25
+ return {} if @opts.nil?
26
+ raise Raiblocks::InvalidParameterType,
27
+ 'You must pass a hash to an action method'
28
+ end
29
+
30
+ def validate_params!
31
+ ensure_required_params!
32
+ ensure_no_forbidden_params!
33
+ end
34
+
35
+ def ensure_required_params!
36
+ missing_params = required_params - opts_keys
37
+ return unless missing_params.any?
38
+ raise Raiblocks::MissingParameters,
39
+ "Missing required parameter(s): #{missing_params.join(', ')}"
40
+ end
41
+
42
+ def ensure_no_forbidden_params!
43
+ forbidden_params = base_param_keys + opts_keys - allowed_params
44
+ return unless forbidden_params.any?
45
+ raise Raiblocks::ForbiddenParameter,
46
+ "Forbidden parameter(s) passed: #{forbidden_params.join(', ')}"
47
+ end
48
+
49
+ private
50
+
51
+ def opts_keys
52
+ @opts.nil? ? [] : @opts.keys
53
+ end
54
+
55
+ def allowed_params
56
+ base_param_keys + required_params + optional_params
57
+ end
58
+
59
+ def required_params
60
+ return [] unless @method_def && @method_def[@m]
61
+ @method_def[@m][:required]
62
+ end
63
+
64
+ def optional_params
65
+ return [] unless @method_def && @method_def[@m]
66
+ @method_def[@m][:optional]
67
+ end
68
+
69
+ def base_param_keys
70
+ @param_def.is_a?(Hash) ? @param_def.keys : []
71
+ end
72
+
73
+ def method_expansion
74
+ "#{action_prefix}#{@m}"
75
+ end
76
+
77
+ def action_prefix
78
+ @klass.name.split('::').last.downcase + '_'
79
+ end
80
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ require 'hashie'
3
+
4
+ class Raiblocks::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_values
12
+ end
13
+
14
+ private
15
+
16
+ def coerce_values
17
+ merge!(self) { |_k, v| to_f_or_i_or_s(v) }
18
+ end
19
+
20
+ def to_f_or_i_or_s(v)
21
+ (float = Float(v)) && (float % 1.0).zero? ? float.to_i : float
22
+ rescue ArgumentError, TypeErrror
23
+ v
24
+ end
25
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ module Raiblocks
3
+ VERSION = '0.4.0'
4
+ end
data/lib/raiblocks_rpc.rb CHANGED
@@ -1,18 +1,15 @@
1
1
  # frozen_string_literal: true
2
- require 'raiblocks_rpc/version'
3
- require 'raiblocks_rpc/client'
4
- require 'raiblocks_rpc/errors'
5
- require 'raiblocks_rpc/proxy'
6
- require 'raiblocks_rpc/response'
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'
13
-
14
- module RaiblocksRpc
15
- def self.client
16
- @client ||= Client.new
17
- end
18
- end
2
+ require 'raiblocks/version'
3
+ require 'raiblocks/client'
4
+ require 'raiblocks/errors'
5
+ require 'raiblocks/proxy'
6
+ require 'raiblocks/proxy_context'
7
+ require 'raiblocks/response'
8
+ require 'raiblocks/helpers/account_proxy_helper'
9
+ require 'raiblocks/helpers/accounts_proxy_helper'
10
+ require 'raiblocks/helpers/node_proxy_helper'
11
+ require 'raiblocks/helpers/wallet_proxy_helper'
12
+ require 'raiblocks/proxies/account'
13
+ require 'raiblocks/proxies/accounts'
14
+ require 'raiblocks/proxies/node'
15
+ require 'raiblocks/proxies/wallet'
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'raiblocks_rpc/version'
4
+ require 'raiblocks/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'raiblocks_rpc'
8
- spec.version = RaiblocksRpc::VERSION
8
+ spec.version = Raiblocks::VERSION
9
9
  spec.authors = ['Justin Craig-Kuhn (JCK)']
10
10
  spec.email = ['jcraigk@gmail.com']
11
11
 
@@ -29,8 +29,8 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency 'pry', '~> 0.11.3'
30
30
  spec.add_development_dependency 'rake', '~> 10.0'
31
31
  spec.add_development_dependency 'rspec', '~> 3.0'
32
- spec.add_development_dependency 'simplecov', '~> 0.15.1'
33
32
  spec.add_development_dependency 'rubocop', '~> 0.52.1'
33
+ spec.add_development_dependency 'simplecov', '~> 0.15.1'
34
34
 
35
35
  spec.add_runtime_dependency 'hashie', '~> 3.5', '>= 3.5.7'
36
36
  spec.add_runtime_dependency 'rest-client', '~> 2.0', '>= 2.0.2'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: raiblocks_rpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Craig-Kuhn (JCK)
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-22 00:00:00.000000000 Z
11
+ date: 2018-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -67,33 +67,33 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: simplecov
70
+ name: rubocop
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.15.1
75
+ version: 0.52.1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.15.1
82
+ version: 0.52.1
83
83
  - !ruby/object:Gem::Dependency
84
- name: rubocop
84
+ name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.52.1
89
+ version: 0.15.1
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.52.1
96
+ version: 0.15.1
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: hashie
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -152,18 +152,21 @@ files:
152
152
  - Rakefile
153
153
  - bin/console
154
154
  - bin/setup
155
+ - lib/raiblocks/client.rb
156
+ - lib/raiblocks/errors.rb
157
+ - lib/raiblocks/helpers/account_proxy_helper.rb
158
+ - lib/raiblocks/helpers/accounts_proxy_helper.rb
159
+ - lib/raiblocks/helpers/node_proxy_helper.rb
160
+ - lib/raiblocks/helpers/wallet_proxy_helper.rb
161
+ - lib/raiblocks/proxies/account.rb
162
+ - lib/raiblocks/proxies/accounts.rb
163
+ - lib/raiblocks/proxies/node.rb
164
+ - lib/raiblocks/proxies/wallet.rb
165
+ - lib/raiblocks/proxy.rb
166
+ - lib/raiblocks/proxy_context.rb
167
+ - lib/raiblocks/response.rb
168
+ - lib/raiblocks/version.rb
155
169
  - 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
170
  - raiblocks_rpc.gemspec
168
171
  homepage: https://github.com/jcraigk/ruby_raiblocks_rpc
169
172
  licenses:
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'singleton'
3
- require 'rest-client'
4
- require 'json'
5
-
6
- class RaiblocksRpc::Client
7
- attr_accessor :host, :port
8
-
9
- def initialize(host: 'localhost', port: 7076)
10
- @host = host
11
- @port = port
12
- end
13
-
14
- def call(action, params = {})
15
- post({ action: action }.merge(params))
16
- end
17
-
18
- private
19
-
20
- def post(params)
21
- response = RestClient.post(url, params.to_json)
22
- ensure_status_success!(response)
23
-
24
- data = RaiblocksRpc::Response.new(JSON[response.body])
25
- ensure_valid_response!(data)
26
-
27
- data
28
- end
29
-
30
- def url
31
- "http://#{host}:#{port}"
32
- end
33
-
34
- def ensure_status_success!(response)
35
- return if response.code == 200
36
- raise RaiblocksRpc::BadRequest,
37
- "Error response from node: #{JSON[response.body]}"
38
- end
39
-
40
- def ensure_valid_response!(data)
41
- return unless data['error']
42
- raise RaiblocksRpc::InvalidRequest,
43
- "Invalid request: #{data['error']}"
44
- end
45
- end
@@ -1,50 +0,0 @@
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
@@ -1,32 +0,0 @@
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
@@ -1,37 +0,0 @@
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
@@ -1,35 +0,0 @@
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
@@ -1,16 +0,0 @@
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
@@ -1,48 +0,0 @@
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