steem-ruby 0.9.0 → 0.9.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.
Files changed (68) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/README.md +88 -15
  4. data/Rakefile +128 -31
  5. data/lib/steem.rb +49 -0
  6. data/lib/steem/api.rb +39 -37
  7. data/lib/steem/base_error.rb +80 -41
  8. data/lib/steem/block_api.rb +23 -3
  9. data/lib/steem/broadcast.rb +465 -29
  10. data/lib/steem/chain_config.rb +3 -3
  11. data/lib/steem/marshal.rb +231 -0
  12. data/lib/steem/mixins/jsonable.rb +37 -0
  13. data/lib/steem/mixins/retriable.rb +30 -24
  14. data/lib/steem/mixins/serializable.rb +45 -0
  15. data/lib/steem/operation.rb +141 -0
  16. data/lib/steem/operation/account_create.rb +10 -0
  17. data/lib/steem/operation/account_create_with_delegation.rb +12 -0
  18. data/lib/steem/operation/account_update.rb +8 -0
  19. data/lib/steem/operation/account_witness_proxy.rb +4 -0
  20. data/lib/steem/operation/account_witness_vote.rb +5 -0
  21. data/lib/steem/operation/cancel_transfer_from_savings.rb +4 -0
  22. data/lib/steem/operation/challenge_authority.rb +5 -0
  23. data/lib/steem/operation/change_recovery_account.rb +5 -0
  24. data/lib/steem/operation/claim_account.rb +5 -0
  25. data/lib/steem/operation/claim_reward_balance.rb +6 -0
  26. data/lib/steem/operation/comment.rb +9 -0
  27. data/lib/steem/operation/comment_options.rb +10 -0
  28. data/lib/steem/operation/convert.rb +5 -0
  29. data/lib/steem/operation/create_claimed_account.rb +10 -0
  30. data/lib/steem/operation/custom.rb +5 -0
  31. data/lib/steem/operation/custom_binary.rb +8 -0
  32. data/lib/steem/operation/custom_json.rb +6 -0
  33. data/lib/steem/operation/decline_voting_rights.rb +4 -0
  34. data/lib/steem/operation/delegate_vesting_shares.rb +5 -0
  35. data/lib/steem/operation/delete_comment.rb +4 -0
  36. data/lib/steem/operation/escrow_approve.rb +8 -0
  37. data/lib/steem/operation/escrow_dispute.rb +7 -0
  38. data/lib/steem/operation/escrow_release.rb +10 -0
  39. data/lib/steem/operation/escrow_transfer.rb +12 -0
  40. data/lib/steem/operation/feed_publish.rb +4 -0
  41. data/lib/steem/operation/limit_order_cancel.rb +4 -0
  42. data/lib/steem/operation/limit_order_create.rb +8 -0
  43. data/lib/steem/operation/limit_order_create2.rb +8 -0
  44. data/lib/steem/operation/prove_authority.rb +4 -0
  45. data/lib/steem/operation/recover_account.rb +6 -0
  46. data/lib/steem/operation/report_over_production.rb +5 -0
  47. data/lib/steem/operation/request_account_recovery.rb +6 -0
  48. data/lib/steem/operation/reset_account.rb +5 -0
  49. data/lib/steem/operation/set_reset_account.rb +5 -0
  50. data/lib/steem/operation/set_withdraw_vesting_route.rb +6 -0
  51. data/lib/steem/operation/transfer.rb +6 -0
  52. data/lib/steem/operation/transfer_from_savings.rb +7 -0
  53. data/lib/steem/operation/transfer_to_savings.rb +6 -0
  54. data/lib/steem/operation/transfer_to_vesting.rb +5 -0
  55. data/lib/steem/operation/vote.rb +6 -0
  56. data/lib/steem/operation/withdraw_vesting.rb +4 -0
  57. data/lib/steem/operation/witness_set_properties.rb +5 -0
  58. data/lib/steem/operation/witness_update.rb +7 -0
  59. data/lib/steem/rpc/base_client.rb +16 -4
  60. data/lib/steem/rpc/http_client.rb +18 -2
  61. data/lib/steem/stream.rb +385 -0
  62. data/lib/steem/transaction.rb +96 -0
  63. data/lib/steem/transaction_builder.rb +176 -103
  64. data/lib/steem/type/amount.rb +61 -9
  65. data/lib/steem/version.rb +1 -1
  66. data/steem-ruby.gemspec +9 -4
  67. metadata +203 -56
  68. data/Gemfile.lock +0 -73
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4c0d2e4cfae2885bc24acaa7d2a5f046e73a1505
4
- data.tar.gz: ddfdd7c5505ada6ea5e67584e51f6b5241e74bb6
2
+ SHA256:
3
+ metadata.gz: 6ee068c00342f904efe37abe6e2cafa9332b1221cac3598071aefab473cfe996
4
+ data.tar.gz: b84eb953f450d52ebabfb1417b2e46a0154aeb8a1066981dcee937480b761632
5
5
  SHA512:
6
- metadata.gz: ec9da3a5222a1ef5bf503ab496eeb12b88609ff1b76d0fd888ca10a355fa3bf0c1bea497a75327a5922a7b002d7b8f19d38eb9b047b431d5fa532eea740c3fa3
7
- data.tar.gz: 3a3aac4b912eeb02c92c97b9e74be3c747595b0acfffd75318258d4b89b99b1569776ff9aa4d7393aa0176b45b2170f5723195aafc87729ae7e22f9cb733d944
6
+ metadata.gz: 824809d5a78d22ac1d15c812537e4c6fa11e85e56920cee365c18c18efc932ba7b265f049462407dd3acae1f460e912f0f582d6f2b05f07ebae8075a8c25b02a
7
+ data.tar.gz: b5fd1bb775ec114939ac338e9f4a83dee337af072b17d435475c420b84b272880bc5847ab3cb8b88f6f689e661fb2897ac729cc6d540ea8ac1fff1073bba69bc
data/.gitignore CHANGED
@@ -43,7 +43,7 @@ build-iPhoneSimulator/
43
43
 
44
44
  # for a library or gem, you might want to ignore these files since the code is
45
45
  # intended to run in multiple environments; otherwise, check them in:
46
- # Gemfile.lock
46
+ Gemfile.lock
47
47
  # .ruby-version
48
48
  # .ruby-gemset
49
49
 
data/README.md CHANGED
@@ -13,17 +13,17 @@ Full documentation: http://www.rubydoc.info/gems/steem-ruby
13
13
 
14
14
  The `steem-ruby` gem was written from the ground up by `@inertia`, who is also the author of [`radiator`](https://github.com/inertia186/radiator).
15
15
 
16
- > "I intend to continue work on `radiator` indefinitely. But in `radiator-0.5`, I intend to refactor `radiator` so that is uses `steem-ruby` as its core. This means that some features of `radiator` like Serialization will become redundant. I think it's still useful for radiator to do its own serialzation because it reduces the number of API requests." - @inertia
17
-
18
- | `radiator` | `steem-ruby` |
19
- |-|-|
20
- | Has internal failover logic | Can have failover delegated externally |
21
- | Passes `error` responses to the caller | Handles `error` responses and raises exceptions |
22
- | Supports tx signing, does its own serialization | Also supports tx signing, but delegates serialization to `database_api.get_transaction_hex` |
23
- | All apis and methods are hardcoded | Asks `jsonrpc` what apis and methods are available from the node |
24
- | (`radiator-0.4.x`) Only supports AppBase but relies on `condenser_api` | Only supports AppBase but does not rely on `condenser_api` **(WIP)**
25
- | Small list of helper methods for select ops (in addition to build your own transaction) | Complete implementation of helper methods for every op (in addition to build your own transaction) |
26
- | Does not (yet) support `json-rpc-batch` requests | Supports `json-rpc-batch` requests |
16
+ > "I intend to continue work on `radiator` indefinitely. But in `radiator-0.5`, I intend to refactor `radiator` so that is uses `steem-ruby` as its core. This means that some features of `radiator` like Serialization will become redundant. I think it's still useful for radiator to do its own serialization because it reduces the number of API requests." - @inertia
17
+
18
+ `radiator` | `steem-ruby`
19
+ ---------- | ------------
20
+ Has internal failover logic | Can have failover delegated externally
21
+ Passes `error` responses to the caller | Handles `error` responses and raises exceptions
22
+ Supports tx signing, does its own serialization | Also supports tx signing, but delegates serialization to `database_api.get_transaction_hex`, then deserializes to verify
23
+ All apis and methods are hardcoded | Asks `jsonrpc` what apis and methods are available from the node
24
+ (`radiator-0.4.x`) Only supports AppBase but relies on `condenser_api` | Only supports AppBase but does not rely on `condenser_api` **(WIP)**
25
+ Small list of helper methods for select ops (in addition to build your own transaction) | Complete implementation of helper methods for every op (in addition to build your own transaction)
26
+ Does not (yet) support `json-rpc-batch` requests | Supports `json-rpc-batch` requests
27
27
 
28
28
  ## Getting Started
29
29
 
@@ -70,6 +70,79 @@ end
70
70
 
71
71
  *See: [Broadcast](https://www.rubydoc.info/gems/steem-ruby/Steem/Broadcast)*
72
72
 
73
+ ### Streaming
74
+
75
+ The value passed to the block is an object, with the keys: `:type` and `:value`.
76
+
77
+ ```ruby
78
+ stream = Steem::Stream.new
79
+
80
+ stream.operations do |op|
81
+ puts "#{op.type}: #{op.value}"
82
+ end
83
+ ```
84
+
85
+ To start a stream from a specific block number, pass it as an argument:
86
+
87
+ ```ruby
88
+ stream = Steem::Stream.new
89
+
90
+ stream.operations(at_block_num: 9001) do |op|
91
+ puts "#{op.type}: #{op.value}"
92
+ end
93
+ ```
94
+
95
+ You can also grab the related transaction id and block number for each operation:
96
+
97
+ ```ruby
98
+ stream = Steem::Stream.new
99
+
100
+ stream.operations do |op, trx_id, block_num|
101
+ puts "#{block_num} :: #{trx_id}"
102
+ puts "#{op.type}: #{op.value}"
103
+ end
104
+ ```
105
+
106
+ To stream only certain operations:
107
+
108
+ ```ruby
109
+ stream = Steem::Stream.new
110
+
111
+ stream.operations(types: :vote_operation) do |op|
112
+ puts "#{op.type}: #{op.value}"
113
+ end
114
+ ```
115
+
116
+ Or pass an array of certain operations:
117
+
118
+ ```ruby
119
+ stream = Steem::Stream.new
120
+
121
+ stream.operations(types: [:comment_operation, :vote_operation]) do |op|
122
+ puts "#{op.type}: #{op.value}"
123
+ end
124
+ ```
125
+
126
+ Or (optionally) just pass the operation(s) you want as the only arguments. This is semantic sugar for when you want specific types and take all of the defaults.
127
+
128
+ ```ruby
129
+ stream = Steem::Stream.new
130
+
131
+ stream.operations(:vote_operation) do |op|
132
+ puts "#{op.type}: #{op.value}"
133
+ end
134
+ ```
135
+
136
+ To also include virtual operations:
137
+
138
+ ```ruby
139
+ stream = Steem::Stream.new
140
+
141
+ stream.operations(include_virtual: true) do |op|
142
+ puts "#{op.type}: #{op.value}"
143
+ end
144
+ ```
145
+
73
146
  ### Multisig
74
147
 
75
148
  You can use multisignature to broadcast an operation.
@@ -90,7 +163,7 @@ end
90
163
  In addition to signing with multiple `wif` private keys, it is possible to also export a partially signed transaction to have signing completed by someone else.
91
164
 
92
165
  ```ruby
93
- builder = TransactionBuilder.new(wif: wif1)
166
+ builder = Steem::TransactionBuilder.new(wif: wif1)
94
167
 
95
168
  builder.put(vote: {
96
169
  voter: voter,
@@ -110,10 +183,10 @@ Then send the contents of `trx.json` to the other signing party so they can priv
110
183
 
111
184
  ```ruby
112
185
  trx = open('trx.json').read
113
- builder = TransactionBuilder.new(wif: wif2, trx: trx)
114
- api = Steem::NetworkBroadcastApi.new
186
+ builder = Steem::TransactionBuilder.new(wif: wif2, trx: trx)
187
+ api = Steem::CondenserApi.new
115
188
  trx = builder.transaction
116
- api.broadcast_transaction_synchronous(trx: trx)
189
+ api.broadcast_transaction_synchronous(trx)
117
190
  ```
118
191
 
119
192
  ### Get Accounts
data/Rakefile CHANGED
@@ -138,44 +138,141 @@ end
138
138
 
139
139
  namespace :stream do
140
140
  desc 'Test the ability to stream a block range.'
141
- task :block_range do
142
- block_api = Steem::BlockApi.new(url: ENV['TEST_NODE'])
141
+ task :block_range, [:mode, :at_block_num] do |t, args|
142
+ mode = (args[:mode] || 'irreversible').to_sym
143
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
144
+ stream = Steem::Stream.new(url: ENV['TEST_NODE'], mode: mode)
143
145
  api = Steem::Api.new(url: ENV['TEST_NODE'])
144
146
  last_block_num = nil
145
- first_block_num = nil
146
147
  last_timestamp = nil
148
+ range_complete = false
147
149
 
148
- loop do
149
- api.get_dynamic_global_properties do |properties|
150
- current_block_num = properties.last_irreversible_block_num
151
- # First pass replays latest a random number of blocks to test chunking.
152
- first_block_num ||= current_block_num - (rand * 200).to_i
150
+ api.get_dynamic_global_properties do |properties|
151
+ current_block_num = if mode == :head
152
+ properties.head_block_number
153
+ else
154
+ properties.last_irreversible_block_num
155
+ end
156
+
157
+ # First pass replays latest a random number of blocks to test chunking.
158
+ first_block_num ||= current_block_num - (rand * 200).to_i
159
+
160
+ range = first_block_num..current_block_num
161
+ puts "Initial block range: #{range.size}"
162
+
163
+ stream.blocks(at_block_num: range.first) do |block, block_num|
164
+ current_timestamp = Time.parse(block.timestamp + 'Z')
153
165
 
154
- if current_block_num >= first_block_num
155
- range = first_block_num..current_block_num
156
- puts "Got block range: #{range.size}"
157
- block_api.get_blocks(block_range: range) do |block, block_num|
158
- current_timestamp = Time.parse(block.timestamp + 'Z')
159
-
160
- if !!last_timestamp && block_num != last_block_num + 1
161
- puts "Bug: Last block number was #{last_block_num} then jumped to: #{block_num}"
162
- exit
163
- end
164
-
165
- if !!last_timestamp && current_timestamp < last_timestamp
166
- puts "Bug: Went back in time. Last timestamp was #{last_timestamp}, then jumped back to #{current_timestamp}"
167
- exit
168
- end
169
-
170
- puts "\t#{block_num} Timestamp: #{current_timestamp}, witness: #{block.witness}"
171
- last_block_num = block_num
172
- last_timestamp = current_timestamp
173
- end
174
-
175
- first_block_num = range.max + 1
166
+ if !range_complete && block_num > range.last
167
+ puts 'Done with initial range.'
168
+ range_complete = true
176
169
  end
177
170
 
178
- sleep 3
171
+ if !!last_timestamp && block_num != last_block_num + 1
172
+ puts "Bug: Last block number was #{last_block_num} then jumped to: #{block_num}"
173
+ exit
174
+ end
175
+
176
+ if !!last_timestamp && current_timestamp < last_timestamp
177
+ puts "Bug: Went back in time. Last timestamp was #{last_timestamp}, then jumped back to #{current_timestamp}"
178
+ exit
179
+ end
180
+
181
+ puts "\t#{block_num} Timestamp: #{current_timestamp}, witness: #{block.witness}"
182
+ last_block_num = block_num
183
+ last_timestamp = current_timestamp
184
+ end
185
+ end
186
+ end
187
+
188
+ desc 'Test the ability to stream a block range of transactions.'
189
+ task :trx_range, [:mode, :at_block_num] do |t, args|
190
+ mode = (args[:mode] || 'irreversible').to_sym
191
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
192
+ stream = Steem::Stream.new(url: ENV['TEST_NODE'], mode: mode)
193
+ api = Steem::Api.new(url: ENV['TEST_NODE'])
194
+
195
+ api.get_dynamic_global_properties do |properties|
196
+ current_block_num = if mode == :head
197
+ properties.head_block_number
198
+ else
199
+ properties.last_irreversible_block_num
200
+ end
201
+
202
+ # First pass replays latest a random number of blocks to test chunking.
203
+ first_block_num ||= current_block_num - (rand * 200).to_i
204
+
205
+ stream.transactions(at_block_num: first_block_num) do |trx, trx_id, block_num|
206
+ puts "#{block_num} :: #{trx_id}; ops: #{trx.operations.map(&:type).join(', ')}"
207
+ end
208
+ end
209
+ end
210
+
211
+ desc 'Test the ability to stream a block range of operations.'
212
+ task :op_range, [:mode, :at_block_num] do |t, args|
213
+ mode = (args[:mode] || 'irreversible').to_sym
214
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
215
+ stream = Steem::Stream.new(url: ENV['TEST_NODE'], mode: mode)
216
+ api = Steem::Api.new(url: ENV['TEST_NODE'])
217
+
218
+ api.get_dynamic_global_properties do |properties|
219
+ current_block_num = if mode == :head
220
+ properties.head_block_number
221
+ else
222
+ properties.last_irreversible_block_num
223
+ end
224
+
225
+ # First pass replays latest a random number of blocks to test chunking.
226
+ first_block_num ||= current_block_num - (rand * 200).to_i
227
+
228
+ stream.operations(at_block_num: first_block_num) do |op, trx_id, block_num|
229
+ puts "#{block_num} :: #{trx_id}; op: #{op.type}"
230
+ end
231
+ end
232
+ end
233
+
234
+ desc 'Test the ability to stream a block range of virtual operations.'
235
+ task :vop_range, [:mode, :at_block_num] do |t, args|
236
+ mode = (args[:mode] || 'irreversible').to_sym
237
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
238
+ stream = Steem::Stream.new(url: ENV['TEST_NODE'], mode: mode)
239
+ api = Steem::Api.new(url: ENV['TEST_NODE'])
240
+
241
+ api.get_dynamic_global_properties do |properties|
242
+ current_block_num = if mode == :head
243
+ properties.head_block_number
244
+ else
245
+ properties.last_irreversible_block_num
246
+ end
247
+
248
+ # First pass replays latest a random number of blocks to test chunking.
249
+ first_block_num ||= current_block_num - (rand * 200).to_i
250
+
251
+ stream.operations(at_block_num: first_block_num, only_virtual: true) do |op, trx_id, block_num|
252
+ puts "#{block_num} :: #{trx_id}; op: #{op.type}"
253
+ end
254
+ end
255
+ end
256
+
257
+ desc 'Test the ability to stream a block range of all operations (including virtual).'
258
+ task :all_op_range, [:mode, :at_block_num] do |t, args|
259
+ mode = (args[:mode] || 'irreversible').to_sym
260
+ first_block_num = args[:at_block_num].to_i if !!args[:at_block_num]
261
+ stream = Steem::Stream.new(url: ENV['TEST_NODE'], mode: mode)
262
+ api = Steem::Api.new(url: ENV['TEST_NODE'])
263
+
264
+ api.get_dynamic_global_properties do |properties|
265
+ current_block_num = if mode == :head
266
+ properties.head_block_number
267
+ else
268
+ properties.last_irreversible_block_num
269
+ end
270
+
271
+ # First pass replays latest a random number of blocks to test chunking.
272
+ first_block_num ||= current_block_num - (rand * 200).to_i
273
+
274
+ stream.operations(at_block_num: first_block_num, include_virtual: true) do |op, trx_id, block_num|
275
+ puts "#{block_num} :: #{trx_id}; op: #{op.type}"
179
276
  end
180
277
  end
181
278
  end
@@ -6,10 +6,58 @@ require 'hashie'
6
6
  require 'steem/version'
7
7
  require 'steem/utils'
8
8
  require 'steem/base_error'
9
+ require 'steem/mixins/serializable'
10
+ require 'steem/mixins/jsonable'
9
11
  require 'steem/mixins/retriable'
10
12
  require 'steem/chain_config'
11
13
  require 'steem/type/base_type'
12
14
  require 'steem/type/amount'
15
+ require 'steem/operation'
16
+ require 'steem/operation/account_create.rb'
17
+ require 'steem/operation/account_create_with_delegation.rb'
18
+ require 'steem/operation/account_update.rb'
19
+ require 'steem/operation/account_witness_proxy.rb'
20
+ require 'steem/operation/account_witness_vote.rb'
21
+ require 'steem/operation/cancel_transfer_from_savings.rb'
22
+ require 'steem/operation/challenge_authority.rb'
23
+ require 'steem/operation/change_recovery_account.rb'
24
+ require 'steem/operation/claim_account.rb'
25
+ require 'steem/operation/claim_reward_balance.rb'
26
+ require 'steem/operation/comment.rb'
27
+ require 'steem/operation/comment_options.rb'
28
+ require 'steem/operation/convert.rb'
29
+ require 'steem/operation/create_claimed_account.rb'
30
+ require 'steem/operation/custom.rb'
31
+ require 'steem/operation/custom_binary.rb'
32
+ require 'steem/operation/custom_json.rb'
33
+ require 'steem/operation/decline_voting_rights.rb'
34
+ require 'steem/operation/delegate_vesting_shares.rb'
35
+ require 'steem/operation/delete_comment.rb'
36
+ require 'steem/operation/escrow_approve.rb'
37
+ require 'steem/operation/escrow_dispute.rb'
38
+ require 'steem/operation/escrow_release.rb'
39
+ require 'steem/operation/escrow_transfer.rb'
40
+ require 'steem/operation/feed_publish.rb'
41
+ require 'steem/operation/limit_order_cancel.rb'
42
+ require 'steem/operation/limit_order_create.rb'
43
+ require 'steem/operation/limit_order_create2.rb'
44
+ require 'steem/operation/prove_authority.rb'
45
+ require 'steem/operation/recover_account.rb'
46
+ require 'steem/operation/report_over_production.rb'
47
+ require 'steem/operation/request_account_recovery.rb'
48
+ require 'steem/operation/reset_account.rb'
49
+ require 'steem/operation/set_reset_account.rb'
50
+ require 'steem/operation/set_withdraw_vesting_route.rb'
51
+ require 'steem/operation/transfer.rb'
52
+ require 'steem/operation/transfer_from_savings.rb'
53
+ require 'steem/operation/transfer_to_savings.rb'
54
+ require 'steem/operation/transfer_to_vesting.rb'
55
+ require 'steem/operation/vote.rb'
56
+ require 'steem/operation/withdraw_vesting.rb'
57
+ require 'steem/operation/witness_update.rb'
58
+ require 'steem/operation/witness_set_properties.rb'
59
+ require 'steem/marshal'
60
+ require 'steem/transaction'
13
61
  require 'steem/transaction_builder'
14
62
  require 'steem/rpc/base_client'
15
63
  require 'steem/rpc/http_client'
@@ -19,6 +67,7 @@ require 'steem/jsonrpc'
19
67
  require 'steem/block_api'
20
68
  require 'steem/formatter'
21
69
  require 'steem/broadcast'
70
+ require 'steem/stream'
22
71
 
23
72
  module Steem
24
73
  def self.api_classes
@@ -1,6 +1,6 @@
1
1
  module Steem
2
2
  # This ruby API works with
3
- # {https://github.com/steemit/steem/releases steemd-0.19.4} and other AppBase
3
+ # {https://github.com/steemit/steem/releases steemd-0.19.10} and other AppBase
4
4
  # compatible upstreams. To access different API namespaces, use the
5
5
  # following:
6
6
  #
@@ -36,10 +36,10 @@ module Steem
36
36
  #
37
37
  # Also see: {https://developers.steem.io/apidefinitions/ Complete API Definitions}
38
38
  class Api
39
- attr_accessor :chain, :methods
39
+ attr_accessor :chain, :methods, :rpc_client
40
40
 
41
41
  # Use this for debugging naive thread handler.
42
- # DEFAULT_RPC_CLIENT_CLASS = RPC::BaseClient
42
+ # DEFAULT_RPC_CLIENT_CLASS = RPC::HttpClient
43
43
  DEFAULT_RPC_CLIENT_CLASS = RPC::ThreadSafeHttpClient
44
44
 
45
45
  def self.api_name=(api_name)
@@ -57,17 +57,37 @@ module Steem
57
57
  @api_name.to_s.split('_').map(&:capitalize).join
58
58
  end
59
59
 
60
- def self.jsonrpc=(jsonrpc)
61
- @jsonrpc = jsonrpc
60
+ def self.jsonrpc=(jsonrpc, url = nil)
61
+ @jsonrpc ||= {}
62
+ @jsonrpc[url || jsonrpc.rpc_client.uri.to_s] = jsonrpc
62
63
  end
63
64
 
64
- def self.jsonrpc
65
- @jsonrpc
65
+ def self.jsonrpc(url = nil)
66
+ if @jsonrpc.size < 2 && url.nil?
67
+ @jsonrpc.values.first
68
+ else
69
+ @jsonrpc[url]
70
+ end
66
71
  end
67
72
 
68
- # Override this if you want to use your own client.
73
+ # Override this if you want to just use your own client. Otherwise, inject
74
+ # the default using:
75
+ #
76
+ # Steem::Api.register default_rpc_client_class: MyClient
69
77
  def self.default_rpc_client_class
70
- DEFAULT_RPC_CLIENT_CLASS
78
+ if !!@injected_dependencies && !!@injected_dependencies[:default_rpc_client_class]
79
+ @injected_dependencies[:default_rpc_client_class]
80
+ else
81
+ DEFAULT_RPC_CLIENT_CLASS
82
+ end
83
+ end
84
+
85
+ # Used for dependency injection. Currently, the only key supported is:
86
+ #
87
+ # `default_rpc_client_class`
88
+ def self.register(register)
89
+ @injected_dependencies ||= {}
90
+ @injected_dependencies = @injected_dependencies.merge register
71
91
  end
72
92
 
73
93
  def initialize(options = {})
@@ -89,7 +109,7 @@ module Steem
89
109
  # have access to instance options until now.
90
110
 
91
111
  Api::jsonrpc = Jsonrpc.new(options)
92
- @methods = Api::jsonrpc.get_api_methods
112
+ @methods = Api::jsonrpc(rpc_client.uri.to_s).get_api_methods
93
113
 
94
114
  unless !!@methods[@api_name]
95
115
  raise UnknownApiError, "#{@api_name} (known APIs: #{@methods.keys.join(' ')})"
@@ -115,28 +135,18 @@ module Steem
115
135
  end
116
136
  private
117
137
  # @private
118
- def self.args_keys_to_s(rpc_method_name)
138
+ def args_keys_to_s(rpc_method_name)
119
139
  args = signature(rpc_method_name).args
120
140
  args_keys = JSON[args.to_json]
121
141
  end
122
142
 
123
143
  # @private
124
- def self.signature(rpc_method_name)
125
- @@signatures ||= {}
126
- @@signatures[rpc_method_name] ||= jsonrpc.get_signature(method: rpc_method_name).result
127
- end
128
-
129
- # @private
130
- def self.raise_error_response(rpc_method_name, rpc_args, response)
131
- raise UnknownError, "#{rpc_method_name}: #{response}" if response.error.nil?
132
-
133
- error = response.error
134
-
135
- if error.message == 'Invalid Request'
136
- raise Steem::ArgumentError, "Unexpected arguments: #{rpc_args.inspect}. Expected: #{rpc_method_name} (#{args_keys_to_s(rpc_method_name)})"
137
- end
144
+ def signature(rpc_method_name)
145
+ url = rpc_client.uri.to_s
138
146
 
139
- BaseError.build_error(error, rpc_method_name)
147
+ @@signatures ||= {}
148
+ @@signatures[url] ||= {}
149
+ @@signatures[url][rpc_method_name] ||= Api::jsonrpc(url).get_signature(method: rpc_method_name).result
140
150
  end
141
151
 
142
152
  # @private
@@ -153,9 +163,9 @@ module Steem
153
163
  when :condenser_api then args
154
164
  when :jsonrpc then args.first
155
165
  else
156
- expected_args = Api::signature(rpc_method_name).args || []
166
+ expected_args = signature(rpc_method_name).args || []
157
167
  expected_args_key_string = if expected_args.size > 0
158
- " (#{Api::args_keys_to_s(rpc_method_name)})"
168
+ " (#{args_keys_to_s(rpc_method_name)})"
159
169
  end
160
170
  expected_args_size = expected_args.size
161
171
 
@@ -178,15 +188,7 @@ module Steem
178
188
  args
179
189
  end
180
190
 
181
- response = @rpc_client.rpc_execute(@api_name, m, rpc_args)
182
-
183
- if defined?(response.error) && !!response.error
184
- if !!response.error.message
185
- Api::raise_error_response rpc_method_name, rpc_args, response
186
- else
187
- raise Steem::ArgumentError, response.error.inspect
188
- end
189
- end
191
+ response = rpc_client.rpc_execute(@api_name, m, rpc_args)
190
192
 
191
193
  if !!block
192
194
  case response