crea-ruby 0.0.1
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 +55 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +234 -0
- data/Rakefile +332 -0
- data/crea-ruby.gemspec +39 -0
- data/gource.sh +6 -0
- data/lib/crea.rb +85 -0
- data/lib/crea/api.rb +208 -0
- data/lib/crea/base_error.rb +218 -0
- data/lib/crea/block_api.rb +78 -0
- data/lib/crea/broadcast.rb +1334 -0
- data/lib/crea/chain_config.rb +36 -0
- data/lib/crea/formatter.rb +14 -0
- data/lib/crea/jsonrpc.rb +108 -0
- data/lib/crea/marshal.rb +231 -0
- data/lib/crea/mixins/jsonable.rb +37 -0
- data/lib/crea/mixins/retriable.rb +58 -0
- data/lib/crea/mixins/serializable.rb +45 -0
- data/lib/crea/operation.rb +141 -0
- data/lib/crea/operation/account_create.rb +10 -0
- data/lib/crea/operation/account_create_with_delegation.rb +12 -0
- data/lib/crea/operation/account_update.rb +8 -0
- data/lib/crea/operation/account_witness_proxy.rb +4 -0
- data/lib/crea/operation/account_witness_vote.rb +5 -0
- data/lib/crea/operation/cancel_transfer_from_savings.rb +4 -0
- data/lib/crea/operation/challenge_authority.rb +5 -0
- data/lib/crea/operation/change_recovery_account.rb +5 -0
- data/lib/crea/operation/claim_account.rb +5 -0
- data/lib/crea/operation/claim_reward_balance.rb +6 -0
- data/lib/crea/operation/comment.rb +9 -0
- data/lib/crea/operation/comment_options.rb +10 -0
- data/lib/crea/operation/convert.rb +5 -0
- data/lib/crea/operation/create_claimed_account.rb +10 -0
- data/lib/crea/operation/custom.rb +5 -0
- data/lib/crea/operation/custom_binary.rb +8 -0
- data/lib/crea/operation/custom_json.rb +6 -0
- data/lib/crea/operation/decline_voting_rights.rb +4 -0
- data/lib/crea/operation/delegate_vesting_shares.rb +5 -0
- data/lib/crea/operation/delete_comment.rb +4 -0
- data/lib/crea/operation/escrow_approve.rb +8 -0
- data/lib/crea/operation/escrow_dispute.rb +7 -0
- data/lib/crea/operation/escrow_release.rb +10 -0
- data/lib/crea/operation/escrow_transfer.rb +12 -0
- data/lib/crea/operation/feed_publish.rb +4 -0
- data/lib/crea/operation/limit_order_cancel.rb +4 -0
- data/lib/crea/operation/limit_order_create.rb +8 -0
- data/lib/crea/operation/limit_order_create2.rb +8 -0
- data/lib/crea/operation/prove_authority.rb +4 -0
- data/lib/crea/operation/recover_account.rb +6 -0
- data/lib/crea/operation/report_over_production.rb +5 -0
- data/lib/crea/operation/request_account_recovery.rb +6 -0
- data/lib/crea/operation/reset_account.rb +5 -0
- data/lib/crea/operation/set_reset_account.rb +5 -0
- data/lib/crea/operation/set_withdraw_vesting_route.rb +6 -0
- data/lib/crea/operation/transfer.rb +6 -0
- data/lib/crea/operation/transfer_from_savings.rb +7 -0
- data/lib/crea/operation/transfer_to_savings.rb +6 -0
- data/lib/crea/operation/transfer_to_vesting.rb +5 -0
- data/lib/crea/operation/vote.rb +6 -0
- data/lib/crea/operation/withdraw_vesting.rb +4 -0
- data/lib/crea/operation/witness_set_properties.rb +5 -0
- data/lib/crea/operation/witness_update.rb +7 -0
- data/lib/crea/rpc/base_client.rb +179 -0
- data/lib/crea/rpc/http_client.rb +143 -0
- data/lib/crea/rpc/thread_safe_http_client.rb +35 -0
- data/lib/crea/stream.rb +385 -0
- data/lib/crea/transaction.rb +96 -0
- data/lib/crea/transaction_builder.rb +393 -0
- data/lib/crea/type/amount.rb +107 -0
- data/lib/crea/type/base_type.rb +10 -0
- data/lib/crea/utils.rb +17 -0
- data/lib/crea/version.rb +4 -0
- metadata +478 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
module Crea
|
2
|
+
module ChainConfig
|
3
|
+
EXPIRE_IN_SECS = 600
|
4
|
+
EXPIRE_IN_SECS_PROPOSAL = 24 * 60 * 60
|
5
|
+
|
6
|
+
NETWORKS_CREA_CHAIN_ID = '0000000000000000000000000000000000000000000000000000000000000000'
|
7
|
+
NETWORKS_CREA_ADDRESS_PREFIX = 'CREA'
|
8
|
+
NETWORKS_CREA_CORE_ASSET = ["0", 3, "@@000000021"] # CREA
|
9
|
+
NETWORKS_CREA_DEBT_ASSET = ["0", 3, "@@000000013"] # CBD
|
10
|
+
NETWORKS_CREA_VEST_ASSET = ["0", 6, "@@000000037"] # VESTS
|
11
|
+
NETWORKS_CREA_DEFAULT_NODE = 'https://node1.creary.net' # √
|
12
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://api.crearystage.com' # √
|
13
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://api.crearydev.com' # √
|
14
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://appbasetest.timcliff.com'
|
15
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://gtg.crea.house:8090'
|
16
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://api.crea.house' # √?
|
17
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://seed.bitcoiner.me'
|
18
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://cread.minnowsupportproject.org'
|
19
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://cread.privex.io'
|
20
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://rpc.crealiberator.com'
|
21
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://rpc.curiecrea.com'
|
22
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://rpc.buildteam.io'
|
23
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://cread.pevo.science'
|
24
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://rpc.creaviz.com'
|
25
|
+
# NETWORKS_CREA_DEFAULT_NODE = 'https://cread.creagigs.org'
|
26
|
+
|
27
|
+
NETWORKS_TEST_CHAIN_ID = '46d82ab7d8db682eb1959aed0ada039a6d49afa1602491f93dde9cac3e8e6c32'
|
28
|
+
NETWORKS_TEST_ADDRESS_PREFIX = 'TST'
|
29
|
+
NETWORKS_TEST_CORE_ASSET = ["0", 3, "@@000000021"] # TESTS
|
30
|
+
NETWORKS_TEST_DEBT_ASSET = ["0", 3, "@@000000013"] # TBD
|
31
|
+
NETWORKS_TEST_VEST_ASSET = ["0", 6, "@@000000037"] # VESTS
|
32
|
+
NETWORKS_TEST_DEFAULT_NODE = 'https://testnet.crearydev.com'
|
33
|
+
|
34
|
+
NETWORK_CHAIN_IDS = [NETWORKS_CREA_CHAIN_ID, NETWORKS_TEST_CHAIN_ID]
|
35
|
+
end
|
36
|
+
end
|
data/lib/crea/jsonrpc.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
module Crea
|
2
|
+
# {Jsonrpc} allows you to inspect the available methods offered by a node.
|
3
|
+
# If a node runs a plugin you want, then all of the API methods it can exposes
|
4
|
+
# will automatically be available. This API is used internally to determine
|
5
|
+
# which APIs and methods are available on the node you specify.
|
6
|
+
#
|
7
|
+
# In theory, if a new plugin is created and enabled by the node, it will be
|
8
|
+
# available by this library without needing an update to its code.
|
9
|
+
class Jsonrpc < Api
|
10
|
+
API_METHODS = %i(get_signature get_methods)
|
11
|
+
|
12
|
+
def self.api_methods
|
13
|
+
@api_methods ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
# Might help diagnose a cluster that has asymmetric plugin definitions.
|
17
|
+
def self.reset_api_methods
|
18
|
+
@api_methods = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(options = {})
|
22
|
+
@api_name = self.class.api_name = :jsonrpc
|
23
|
+
@methods = API_METHODS
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_api_methods(&block)
|
28
|
+
api_methods = self.class.api_methods[@rpc_client.uri.to_s]
|
29
|
+
|
30
|
+
if api_methods.nil?
|
31
|
+
get_methods do |result, error, rpc_id|
|
32
|
+
raise NotAppBaseError, "#{@rpc_client.uri} does not appear to run AppBase" unless defined? result.map
|
33
|
+
|
34
|
+
methods = result.map do |method|
|
35
|
+
method.split('.').map(&:to_sym)
|
36
|
+
end
|
37
|
+
|
38
|
+
api_methods = Hashie::Mash.new
|
39
|
+
|
40
|
+
methods.each do |api, method|
|
41
|
+
api_methods[api] ||= []
|
42
|
+
api_methods[api] << method
|
43
|
+
end
|
44
|
+
|
45
|
+
self.class.api_methods[@rpc_client.uri.to_s] = api_methods
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if !!block
|
50
|
+
api_methods.each do |api, methods|
|
51
|
+
yield api, methods
|
52
|
+
end
|
53
|
+
else
|
54
|
+
return api_methods
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_all_signatures(&block)
|
59
|
+
request_object = []
|
60
|
+
method_names = []
|
61
|
+
method_map = {}
|
62
|
+
signatures = {}
|
63
|
+
offset = 0
|
64
|
+
|
65
|
+
get_api_methods do |api, methods|
|
66
|
+
request_object += methods.map do |method|
|
67
|
+
method_name = "#{api}.#{method}"
|
68
|
+
method_names << method_name
|
69
|
+
current_rpc_id = @rpc_client.rpc_id
|
70
|
+
offset += 1
|
71
|
+
method_map[current_rpc_id] = [api, method]
|
72
|
+
|
73
|
+
{
|
74
|
+
jsonrpc: '2.0',
|
75
|
+
id: current_rpc_id,
|
76
|
+
method: 'jsonrpc.get_signature',
|
77
|
+
params: {method: method_name}
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
chunks = if request_object.size > Crea::RPC::HttpClient::JSON_RPC_BATCH_SIZE_MAXIMUM
|
83
|
+
request_object.each_slice(Crea::RPC::HttpClient::JSON_RPC_BATCH_SIZE_MAXIMUM)
|
84
|
+
else
|
85
|
+
request_object
|
86
|
+
end
|
87
|
+
|
88
|
+
for request_object in chunks do
|
89
|
+
@rpc_client.rpc_batch_execute(request_object: request_object) do |result, error, id|
|
90
|
+
api, method = method_map[id]
|
91
|
+
api = api.to_sym
|
92
|
+
method = method.to_sym
|
93
|
+
|
94
|
+
signatures[api] ||= {}
|
95
|
+
signatures[api][method] = result
|
96
|
+
end
|
97
|
+
|
98
|
+
if !!block
|
99
|
+
signatures.each do |api, methods|
|
100
|
+
yield api, methods
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
return signatures unless !!block
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/crea/marshal.rb
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
require 'base58'
|
3
|
+
|
4
|
+
module Crea
|
5
|
+
class Marshal
|
6
|
+
include Utils
|
7
|
+
include ChainConfig
|
8
|
+
|
9
|
+
PUBLIC_KEY_DISABLED = '1111111111111111111111111111111114T1Anm'
|
10
|
+
|
11
|
+
attr_reader :bytes, :cursor
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
@bytes = if !!(hex = options[:hex])
|
15
|
+
unhexlify hex
|
16
|
+
else
|
17
|
+
options[:bytes]
|
18
|
+
end
|
19
|
+
|
20
|
+
@chain = options[:chain] || :crea
|
21
|
+
@prefix ||= case @chain
|
22
|
+
when :crea then NETWORKS_CREA_ADDRESS_PREFIX
|
23
|
+
when :test then NETWORKS_TEST_ADDRESS_PREFIX
|
24
|
+
else; raise UnsupportedChainError, "Unsupported chain: #{@chain}"
|
25
|
+
end
|
26
|
+
@cursor = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
def hex
|
30
|
+
hexlify bytes
|
31
|
+
end
|
32
|
+
|
33
|
+
def rewind!
|
34
|
+
@cursor = 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def step(n = 0)
|
38
|
+
@cursor += n
|
39
|
+
end
|
40
|
+
|
41
|
+
def scan(len)
|
42
|
+
bytes.slice(@cursor..(@cursor - 1) + len).tap { |_| @cursor += len }
|
43
|
+
end
|
44
|
+
|
45
|
+
def operation_type
|
46
|
+
Operation::IDS[unsigned_char]
|
47
|
+
end
|
48
|
+
|
49
|
+
def unsigned_char; BinData::Uint8le.read(scan(1)); end # 8-bit unsigned
|
50
|
+
def uint16; BinData::Uint16le.read(scan(2)); end # 16-bit unsigned, VAX (little-endian) byte order
|
51
|
+
def uint32; BinData::Uint32le.read(scan(4)); end # 32-bit unsigned, VAX (little-endian) byte order
|
52
|
+
def uint64; BinData::Uint64le.read(scan(8)); end # 64-bit unsigned, little-endian
|
53
|
+
|
54
|
+
def signed_char; BinData::Int8le.read(scan(1)); end # 8-bit signed
|
55
|
+
def int16; BinData::Int16le.read(scan(2)); end # 16-bit signed, little-endian
|
56
|
+
def int32; BinData::Int32le.read(scan(4)); end # 32-bit signed, little-endian
|
57
|
+
def int64; BinData::Int64le.read(scan(8)); end # 64-bit signed, little-endian
|
58
|
+
|
59
|
+
def boolean; scan(1) == "\x01"; end
|
60
|
+
|
61
|
+
def varint
|
62
|
+
shift = 0
|
63
|
+
result = 0
|
64
|
+
bytes = []
|
65
|
+
|
66
|
+
while (n = unsigned_char) >> 7 == 1
|
67
|
+
bytes << n
|
68
|
+
end
|
69
|
+
|
70
|
+
bytes << n
|
71
|
+
|
72
|
+
bytes.each do |b|
|
73
|
+
result += ((b & 0x7f) << shift)
|
74
|
+
break unless (b & 0x80)
|
75
|
+
shift += 7
|
76
|
+
end
|
77
|
+
|
78
|
+
result
|
79
|
+
end
|
80
|
+
|
81
|
+
def string(len = nil); scan(len || varint); end
|
82
|
+
|
83
|
+
def raw_bytes(len = nil); scan(len || varint).force_encoding('BINARY'); end
|
84
|
+
|
85
|
+
def point_in_time
|
86
|
+
if (time = uint32) == 2**32-1
|
87
|
+
Time.at -1
|
88
|
+
else
|
89
|
+
Time.at time
|
90
|
+
end.utc
|
91
|
+
end
|
92
|
+
|
93
|
+
def public_key(prefix = @prefix)
|
94
|
+
raw_public_key = raw_bytes(33)
|
95
|
+
checksum = OpenSSL::Digest::RIPEMD160.digest(raw_public_key)
|
96
|
+
key = Base58.binary_to_base58(raw_public_key + checksum.slice(0, 4), :bitcoin)
|
97
|
+
|
98
|
+
prefix + key unless key == PUBLIC_KEY_DISABLED
|
99
|
+
end
|
100
|
+
|
101
|
+
def amount
|
102
|
+
amount = uint64.to_f
|
103
|
+
precision = signed_char
|
104
|
+
asset = scan(7).strip
|
105
|
+
|
106
|
+
amount = "%.#{precision}f #{asset}" % (amount / 10 ** precision)
|
107
|
+
|
108
|
+
Crea::Type::Amount.new(amount)
|
109
|
+
end
|
110
|
+
|
111
|
+
def price
|
112
|
+
{base: amount, quote: amount}
|
113
|
+
end
|
114
|
+
|
115
|
+
def authority(options = {optional: false})
|
116
|
+
return if !!options[:optional] && unsigned_char == 0
|
117
|
+
|
118
|
+
{
|
119
|
+
weight_threshold: uint32,
|
120
|
+
account_auths: varint.times.map { [string, uint16] },
|
121
|
+
key_auths: varint.times.map { [public_key, uint16] }
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def optional_authority
|
126
|
+
authority(optional: true)
|
127
|
+
end
|
128
|
+
|
129
|
+
def comment_options_extensions
|
130
|
+
if scan(1) == "\x01"
|
131
|
+
beneficiaries
|
132
|
+
else
|
133
|
+
[]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def beneficiaries
|
138
|
+
if scan(1) == "\x00"
|
139
|
+
varint.times.map {{account: string, weight: uint16}}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def chain_properties
|
144
|
+
{
|
145
|
+
account_creation_fee: amount,
|
146
|
+
maximum_block_size: uint32,
|
147
|
+
cbd_interest_rate: uint16
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
def required_auths
|
152
|
+
varint.times.map { string }
|
153
|
+
end
|
154
|
+
|
155
|
+
def witness_properties
|
156
|
+
properties = {}
|
157
|
+
|
158
|
+
varint.times do
|
159
|
+
key = string.to_sym
|
160
|
+
properties[key] = case key
|
161
|
+
when :account_creation_fee then Crea::Type::Amount.new(string)
|
162
|
+
when :account_subsidy_budget then scan(3)
|
163
|
+
when :account_subsidy_decay, :maximum_block_size then uint32
|
164
|
+
when :url then string
|
165
|
+
when :cbd_exchange_rate
|
166
|
+
JSON[string].tap do |rate|
|
167
|
+
rate["base"] = Crea::Type::Amount.new(rate["base"])
|
168
|
+
rate["quote"] = Crea::Type::Amount.new(rate["quote"])
|
169
|
+
end
|
170
|
+
when :cbd_interest_rate then uint16
|
171
|
+
when :key, :new_signing_key then @prefix + scan(50)
|
172
|
+
else; raise "Unknown witness property: #{key}"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
properties
|
177
|
+
end
|
178
|
+
|
179
|
+
def empty_array
|
180
|
+
unsigned_char == 0 and [] or raise "Found non-empty array."
|
181
|
+
end
|
182
|
+
|
183
|
+
def transaction(options = {})
|
184
|
+
trx = options[:trx] || Transaction.new
|
185
|
+
|
186
|
+
trx.ref_block_num = uint16
|
187
|
+
trx.ref_block_prefix = uint32
|
188
|
+
trx.expiration = point_in_time
|
189
|
+
|
190
|
+
trx.operations = operations
|
191
|
+
|
192
|
+
trx
|
193
|
+
rescue => e
|
194
|
+
raise DeserializationError.new("Transaction failed\nOriginal serialized bytes:\n[#{hex[0..(@cursor * 2) - 1]}]#{hex[((@cursor) * 2)..-1]}", e)
|
195
|
+
end
|
196
|
+
|
197
|
+
def operations
|
198
|
+
operations_len = signed_char
|
199
|
+
operations = []
|
200
|
+
|
201
|
+
while operations.size < operations_len do
|
202
|
+
begin
|
203
|
+
type = operation_type
|
204
|
+
break if type.nil?
|
205
|
+
|
206
|
+
op_class_name = type.to_s.sub!(/_operation$/, '')
|
207
|
+
op_class_name = "Crea::Operation::" + op_class_name.split('_').map(&:capitalize).join
|
208
|
+
op_class = Object::const_get(op_class_name)
|
209
|
+
op = op_class.new
|
210
|
+
|
211
|
+
op_class::serializable_types.each do |k, v|
|
212
|
+
begin
|
213
|
+
# binding.pry if v == :comment_options_extensions
|
214
|
+
op.send("#{k}=", send(v))
|
215
|
+
rescue => e
|
216
|
+
raise DeserializationError.new("#{type}.#{k} (#{v}) failed", e)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
operations << {type: type, value: op}
|
221
|
+
rescue => e
|
222
|
+
raise DeserializationError.new("#{type} failed", e)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
operations
|
227
|
+
rescue => e
|
228
|
+
raise DeserializationError.new("Operations failed", e)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Crea
|
2
|
+
module JSONable
|
3
|
+
module ClassMethods
|
4
|
+
attr_accessor :attributes
|
5
|
+
|
6
|
+
def attr_accessor *attrs
|
7
|
+
self.attributes = Array attrs
|
8
|
+
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.extend(ClassMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_json options = {}
|
18
|
+
serialized = Hash.new
|
19
|
+
|
20
|
+
self.class.attributes.each do |attribute|
|
21
|
+
unless (value = self.public_send attribute).nil?
|
22
|
+
serialized[attribute] = if value.respond_to? :strftime
|
23
|
+
value.strftime('%Y-%m-%dT%H:%M:%S')
|
24
|
+
else
|
25
|
+
value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
serialized
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_json *a
|
34
|
+
as_json.to_json *a
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Crea
|
2
|
+
module Retriable
|
3
|
+
# @private
|
4
|
+
MAX_RETRY_COUNT = 30
|
5
|
+
|
6
|
+
MAX_RETRY_ELAPSE = 60
|
7
|
+
|
8
|
+
# @private
|
9
|
+
MAX_BACKOFF = MAX_RETRY_ELAPSE / 4
|
10
|
+
|
11
|
+
RETRYABLE_EXCEPTIONS = [
|
12
|
+
NonCanonicalSignatureError, IncorrectRequestIdError,
|
13
|
+
IncorrectResponseIdError, RemoteDatabaseLockError
|
14
|
+
]
|
15
|
+
|
16
|
+
def can_retry?(e = nil)
|
17
|
+
@retry_count ||= 0
|
18
|
+
|
19
|
+
return false if @retry_count >= MAX_RETRY_COUNT
|
20
|
+
|
21
|
+
@retry_count = if retry_reset?
|
22
|
+
@first_retry_at = nil
|
23
|
+
else
|
24
|
+
@retry_count + 1
|
25
|
+
end
|
26
|
+
|
27
|
+
can_retry = case e
|
28
|
+
when *RETRYABLE_EXCEPTIONS then true
|
29
|
+
else; false
|
30
|
+
end
|
31
|
+
|
32
|
+
backoff if can_retry
|
33
|
+
|
34
|
+
can_retry
|
35
|
+
end
|
36
|
+
private
|
37
|
+
# @private
|
38
|
+
def first_retry_at
|
39
|
+
@first_retry_at ||= Time.now.utc
|
40
|
+
end
|
41
|
+
|
42
|
+
# @private
|
43
|
+
def retry_reset?
|
44
|
+
Time.now.utc - first_retry_at > MAX_RETRY_ELAPSE
|
45
|
+
end
|
46
|
+
|
47
|
+
# Expontential backoff.
|
48
|
+
#
|
49
|
+
# @private
|
50
|
+
def backoff
|
51
|
+
@backoff ||= 0.1
|
52
|
+
@backoff *= 2
|
53
|
+
@backoff = 0.1 if @backoff > MAX_BACKOFF
|
54
|
+
|
55
|
+
sleep @backoff
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|