meeseeker 1.0.0 → 2.0.0.pre.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 +4 -4
- data/README.md +116 -98
- data/Rakefile +121 -44
- data/lib/meeseeker.rb +178 -6
- data/lib/meeseeker/block_follower_job.rb +33 -17
- data/lib/meeseeker/hive_engine.rb +20 -0
- data/lib/meeseeker/steem_engine/agent.rb +33 -19
- data/lib/meeseeker/steem_engine/follower_job.rb +31 -14
- data/lib/meeseeker/version.rb +1 -1
- data/lib/meeseeker/witness_schedule_job.rb +6 -2
- data/meeseeker.gemspec +1 -0
- data/test/meeseeker/meeseeker_test.rb +247 -20
- data/test/test_helper.rb +10 -0
- metadata +29 -9
data/lib/meeseeker.rb
CHANGED
@@ -1,28 +1,200 @@
|
|
1
1
|
require 'redis'
|
2
2
|
require 'steem'
|
3
|
+
require 'hive'
|
3
4
|
|
4
5
|
require 'meeseeker/version'
|
5
6
|
require 'meeseeker/block_follower_job'
|
6
7
|
require 'meeseeker/witness_schedule_job'
|
7
8
|
require 'meeseeker/steem_engine/agent'
|
8
9
|
require 'meeseeker/steem_engine/follower_job'
|
10
|
+
require 'meeseeker/hive_engine'
|
9
11
|
|
10
12
|
module Meeseeker
|
11
|
-
|
12
|
-
|
13
|
+
STEEM_CHAIN_ID = '0000000000000000000000000000000000000000000000000000000000000000'
|
14
|
+
HIVE_LEGACY_CHAIN_ID = '0000000000000000000000000000000000000000000000000000000000000000'
|
15
|
+
HIVE_CHAIN_ID = 'beeab0de00000000000000000000000000000000000000000000000000000000'
|
16
|
+
STEEM_CHAIN_KEY_PREFIX = 'steem'
|
17
|
+
HIVE_CHAIN_KEY_PREFIX = 'hive'
|
18
|
+
STEEM_ENGINE_CHAIN_KEY_PREFIX = 'steem_engine'
|
19
|
+
HIVE_ENGINE_CHAIN_KEY_PREFIX = 'hive_engine'
|
20
|
+
LAST_BLOCK_NUM_KEY_SUFFIX = ':meeseeker:last_block_num'
|
21
|
+
LAST_STEEM_ENGINE_BLOCK_NUM_KEY_SUFFIX = ':meeseeker:last_block_num'
|
13
22
|
BLOCKS_PER_DAY = 28800
|
14
23
|
VIRTUAL_TRX_ID = '0000000000000000000000000000000000000000'
|
24
|
+
BLOCK_INTERVAL = 3
|
25
|
+
SHUFFLE_URL = 'shuffle'
|
26
|
+
DEFAULT_STEEM_URL = 'https://api.steemit.com'
|
27
|
+
DEFAULT_STEEM_FAILOVER_URLS = [
|
28
|
+
DEFAULT_STEEM_URL,
|
29
|
+
# 'https://steemd.minnowsupportproject.org',
|
30
|
+
# 'https://anyx.io',
|
31
|
+
# 'http://anyx.io',
|
32
|
+
# 'https://steemd.privex.io',
|
33
|
+
# 'https://api.steem.house'
|
34
|
+
]
|
35
|
+
DEFAULT_HIVE_URL = 'https://api.openhive.network'
|
36
|
+
DEFAULT_HIVE_FAILOVER_URLS = [
|
37
|
+
DEFAULT_HIVE_URL,
|
38
|
+
'https://api.hivekings.com',
|
39
|
+
'https://anyx.io',
|
40
|
+
'http://anyx.io',
|
41
|
+
'https://techcoderx.com',
|
42
|
+
'https://rpc.esteem.app',
|
43
|
+
'https://hived.privex.io',
|
44
|
+
'https://api.pharesim.me',
|
45
|
+
'https://api.hive.blog',
|
46
|
+
'https://rpc.ausbit.dev'
|
47
|
+
]
|
48
|
+
|
49
|
+
def default_chain_key_prefix
|
50
|
+
ENV.fetch('MEESEEKER_CHAIN_KEY_PREFIX', chain_key_prefix)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.chain_key_prefix
|
54
|
+
@chain_key_prefix ||= {}
|
55
|
+
url = default_url(HIVE_CHAIN_KEY_PREFIX)
|
56
|
+
|
57
|
+
return @chain_key_prefix[url] if !!@chain_key_prefix[url]
|
58
|
+
|
59
|
+
# Just use the Hive API for either chain, until we know which one we're
|
60
|
+
# using.
|
61
|
+
api = Hive::DatabaseApi.new(url: url)
|
62
|
+
|
63
|
+
api.get_config do |config|
|
64
|
+
@chain_key_prefix[node_url] = if !!config.HIVE_CHAIN_ID && config.HIVE_CHAIN_ID == HIVE_CHAIN_ID
|
65
|
+
HIVE_CHAIN_KEY_PREFIX
|
66
|
+
elsif !!config.HIVE_CHAIN_ID && config.HIVE_CHAIN_ID == HIVE_LEGACY_CHAIN_ID
|
67
|
+
HIVE_CHAIN_KEY_PREFIX
|
68
|
+
elsif !!config.STEEM_CHAIN_ID && config.STEEM_CHAIN_ID == STEEM_CHAIN_ID
|
69
|
+
STEEM_CHAIN_KEY_PREFIX
|
70
|
+
else
|
71
|
+
config.keys.find{|k| k.end_with? '_CHAIN_ID'}.split('_').first.downcase.tap do |guess|
|
72
|
+
warn "Guessing chain_key_prefix = '#{guess}' for unknown chain on: #{node_url}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.default_url(chain = default_chain_key_prefix)
|
79
|
+
ENV.fetch('MEESEEKER_NODE_URL') do
|
80
|
+
case chain.to_s
|
81
|
+
when STEEM_CHAIN_KEY_PREFIX then DEFAULT_STEEM_URL
|
82
|
+
when HIVE_CHAIN_KEY_PREFIX then DEFAULT_HIVE_URL
|
83
|
+
else
|
84
|
+
raise "Unknown chain: #{chain}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
@problem_node_urls = []
|
90
|
+
|
15
91
|
@redis = Redis.new(url: ENV.fetch('MEESEEKER_REDIS_URL', 'redis://127.0.0.1:6379/0'))
|
16
|
-
@node_url = ENV.fetch('
|
92
|
+
@node_url = default_url(ENV.fetch('MEESEEKER_CHAIN_KEY_PREFIX', HIVE_CHAIN_KEY_PREFIX))
|
17
93
|
@steem_engine_node_url = ENV.fetch('MEESEEKER_STEEM_ENGINE_NODE_URL', 'https://api.steem-engine.com/rpc')
|
94
|
+
@hive_engine_node_url = ENV.fetch('MEESEEKER_HIVE_ENGINE_NODE_URL', 'https://api.hive-engine.com/rpc')
|
18
95
|
@stream_mode = ENV.fetch('MEESEEKER_STREAM_MODE', 'head').downcase.to_sym
|
19
96
|
@include_virtual = ENV.fetch('MEESEEKER_INCLUDE_VIRTUAL', 'true').downcase == 'true'
|
20
97
|
@include_block_header = ENV.fetch('MEESEEKER_INCLUDE_BLOCK_HEADER', 'true').downcase == 'true'
|
21
98
|
@publish_op_custom_id = ENV.fetch('MEESEEKER_PUBLISH_OP_CUSTOM_ID', 'false').downcase == 'true'
|
22
|
-
@expire_keys = ENV.fetch('MEESEEKER_EXPIRE_KEYS', BLOCKS_PER_DAY *
|
99
|
+
@expire_keys = ENV.fetch('MEESEEKER_EXPIRE_KEYS', BLOCKS_PER_DAY * BLOCK_INTERVAL).to_i
|
100
|
+
@max_keys = ENV.fetch('MEESEEKER_MAX_KEYS', '-1').to_i
|
23
101
|
|
24
102
|
extend self
|
25
103
|
|
26
|
-
attr_accessor :redis, :node_url, :steem_engine_node_url,
|
27
|
-
:
|
104
|
+
attr_accessor :redis, :node_url, :steem_engine_node_url,
|
105
|
+
:hive_engine_node_url, :expire_keys, :max_keys, :stream_mode,
|
106
|
+
:include_virtual, :include_block_header, :publish_op_custom_id
|
107
|
+
|
108
|
+
def self.shuffle_node_url(chain = ENV.fetch('MEESEEKER_CHAIN_KEY_PREFIX', HIVE_CHAIN_KEY_PREFIX))
|
109
|
+
chain = chain.to_s
|
110
|
+
node_url = ENV.fetch('MEESEEKER_NODE_URL', default_url(ENV.fetch('MEESEEKER_CHAIN_KEY_PREFIX', chain)))
|
111
|
+
return node_url unless node_url == SHUFFLE_URL
|
112
|
+
|
113
|
+
@problem_node_urls = [] if rand(1..1000) == 13
|
114
|
+
shuffle_node_url!(chain)
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.api_class(chain = default_chain_key_prefix)
|
118
|
+
case chain.to_s
|
119
|
+
when STEEM_CHAIN_KEY_PREFIX then Steem::Api
|
120
|
+
when HIVE_CHAIN_KEY_PREFIX then Hive::Api
|
121
|
+
else
|
122
|
+
raise "Unknown chain: #{chain}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.condenser_api_class(chain = default_chain_key_prefix)
|
127
|
+
case chain.to_s
|
128
|
+
when STEEM_CHAIN_KEY_PREFIX then Steem::CondenserApi
|
129
|
+
when HIVE_CHAIN_KEY_PREFIX then Hive::CondenserApi
|
130
|
+
else
|
131
|
+
raise "Unknown chain: #{chain}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.block_api_class(chain = default_chain_key_prefix)
|
136
|
+
case chain.to_s
|
137
|
+
when STEEM_CHAIN_KEY_PREFIX then Steem::BlockApi
|
138
|
+
when HIVE_CHAIN_KEY_PREFIX then Hive::BlockApi
|
139
|
+
else
|
140
|
+
raise "Unknown chain: #{chain}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.database_api_class(chain = default_chain_key_prefix)
|
145
|
+
case chain.to_s
|
146
|
+
when STEEM_CHAIN_KEY_PREFIX then Steem::DatabaseApi
|
147
|
+
when HIVE_CHAIN_KEY_PREFIX then Hive::DatabaseApi
|
148
|
+
else
|
149
|
+
raise "Unknown chain: #{chain}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.stream_class(chain = default_chain_key_prefix)
|
154
|
+
case chain.to_s
|
155
|
+
when STEEM_CHAIN_KEY_PREFIX then Steem::Stream
|
156
|
+
when HIVE_CHAIN_KEY_PREFIX then Hive::Stream
|
157
|
+
else
|
158
|
+
raise "Unknown chain: #{chain}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.shuffle_node_url!(chain = ENV.fetch('MEESEEKER_CHAIN_KEY_PREFIX', HIVE_CHAIN_KEY_PREFIX))
|
163
|
+
chain = chain.to_s
|
164
|
+
failover_urls = case chain
|
165
|
+
when STEEM_CHAIN_KEY_PREFIX then DEFAULT_STEEM_FAILOVER_URLS - @problem_node_urls
|
166
|
+
when HIVE_CHAIN_KEY_PREFIX then DEFAULT_HIVE_FAILOVER_URLS - @problem_node_urls
|
167
|
+
else; []
|
168
|
+
end
|
169
|
+
url = failover_urls.sample
|
170
|
+
api = api_class(chain).new(url: url)
|
171
|
+
|
172
|
+
api.get_accounts(['fullnodeupdate']) do |accounts|
|
173
|
+
fullnodeupdate = accounts.first
|
174
|
+
metadata = (JSON[fullnodeupdate.json_metadata] rescue nil) || {}
|
175
|
+
|
176
|
+
nodes = metadata.fetch('report', []).map do |report|
|
177
|
+
next if chain == HIVE_CHAIN_KEY_PREFIX && !report[HIVE_CHAIN_KEY_PREFIX]
|
178
|
+
next if chain != HIVE_CHAIN_KEY_PREFIX && !!report[HIVE_CHAIN_KEY_PREFIX]
|
179
|
+
|
180
|
+
report['node']
|
181
|
+
end.compact.uniq
|
182
|
+
|
183
|
+
nodes -= @problem_node_urls
|
184
|
+
|
185
|
+
if nodes.any?
|
186
|
+
nodes.sample
|
187
|
+
else
|
188
|
+
@node_url = failover_urls.sample
|
189
|
+
end
|
190
|
+
end
|
191
|
+
rescue => e
|
192
|
+
puts "#{url}: #{e}"
|
193
|
+
|
194
|
+
@problem_node_urls << url
|
195
|
+
failover_urls -= @problem_node_urls
|
196
|
+
failover_urls.sample
|
197
|
+
end
|
198
|
+
|
199
|
+
shuffle_node_url! if @node_url == SHUFFLE_URL
|
28
200
|
end
|
@@ -3,16 +3,20 @@ module Meeseeker
|
|
3
3
|
MAX_VOP_RETRY = 3
|
4
4
|
|
5
5
|
def perform(options = {})
|
6
|
-
|
6
|
+
chain = (options[:chain] || 'hive').to_sym
|
7
|
+
url = Meeseeker.default_url(chain)
|
8
|
+
block_api = Meeseeker.block_api_class(chain).new(url: url)
|
7
9
|
redis = Meeseeker.redis
|
8
10
|
last_key_prefix = nil
|
9
11
|
trx_index = 0
|
10
12
|
current_block_num = nil
|
11
13
|
block_transactions = []
|
14
|
+
chain_key_prefix = chain.to_s if !!options[:chain]
|
15
|
+
chain_key_prefix ||= Meeseeker.default_chain_key_prefix
|
12
16
|
|
13
17
|
stream_operations(options) do |op, trx_id, block_num|
|
14
18
|
begin
|
15
|
-
current_key_prefix = "
|
19
|
+
current_key_prefix = "#{chain_key_prefix}:#{block_num}:#{trx_id}"
|
16
20
|
|
17
21
|
if current_key_prefix == last_key_prefix
|
18
22
|
trx_index += 1
|
@@ -26,9 +30,9 @@ module Meeseeker
|
|
26
30
|
}
|
27
31
|
|
28
32
|
block_transactions << trx_id unless trx_id == VIRTUAL_TRX_ID
|
29
|
-
redis.publish(
|
33
|
+
redis.publish("#{chain_key_prefix}:transaction", transaction_payload.to_json)
|
30
34
|
end
|
31
|
-
last_key_prefix = "
|
35
|
+
last_key_prefix = "#{chain_key_prefix}:#{block_num}:#{trx_id}"
|
32
36
|
trx_index = 0
|
33
37
|
end
|
34
38
|
|
@@ -42,6 +46,12 @@ module Meeseeker
|
|
42
46
|
puts key
|
43
47
|
end
|
44
48
|
|
49
|
+
unless Meeseeker.max_keys == -1
|
50
|
+
while redis.keys("#{chain_key_prefix}:*").size > Meeseeker.max_keys
|
51
|
+
sleep Meeseeker::BLOCK_INTERVAL
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
45
55
|
redis.set(key, op.to_json)
|
46
56
|
redis.expire(key, Meeseeker.expire_keys) unless Meeseeker.expire_keys == -1
|
47
57
|
|
@@ -56,7 +66,7 @@ module Meeseeker
|
|
56
66
|
block_api.get_block_header(block_num: block_num) do |result|
|
57
67
|
if result.nil? || result.header.nil?
|
58
68
|
puts "Node returned empty result for block_header on block_num: #{block_num} (rate limiting?). Retrying ..."
|
59
|
-
sleep
|
69
|
+
sleep Meeseeker::BLOCK_INTERVAL
|
60
70
|
throw :block_header
|
61
71
|
end
|
62
72
|
|
@@ -65,19 +75,19 @@ module Meeseeker
|
|
65
75
|
end
|
66
76
|
end
|
67
77
|
|
68
|
-
redis.set(
|
69
|
-
redis.publish(
|
78
|
+
redis.set(chain_key_prefix + LAST_BLOCK_NUM_KEY_SUFFIX, block_num)
|
79
|
+
redis.publish("#{chain_key_prefix}:block", block_payload.to_json)
|
70
80
|
current_block_num = block_num
|
71
81
|
end
|
72
82
|
|
73
|
-
redis.publish("
|
83
|
+
redis.publish("#{chain_key_prefix}:op:#{op_type}", {key: key}.to_json)
|
74
84
|
|
75
85
|
if Meeseeker.publish_op_custom_id
|
76
86
|
if %w(custom custom_binary custom_json).include? op_type
|
77
87
|
id = (op["value"]["id"] rescue nil).to_s
|
78
88
|
|
79
89
|
if id.size > 0
|
80
|
-
redis.publish("
|
90
|
+
redis.publish("#{chain_key_prefix}:op:#{op_type}:#{id}", {key: key}.to_json)
|
81
91
|
end
|
82
92
|
end
|
83
93
|
end
|
@@ -85,7 +95,10 @@ module Meeseeker
|
|
85
95
|
end
|
86
96
|
private
|
87
97
|
def stream_operations(options = {}, &block)
|
98
|
+
chain = (options[:chain] || 'hive').to_sym
|
88
99
|
redis = Meeseeker.redis
|
100
|
+
chain_key_prefix = chain.to_s if !!options[:chain]
|
101
|
+
chain_key_prefix ||= Meeseeker.chain_key_prefix
|
89
102
|
last_block_num = nil
|
90
103
|
mode = options.delete(:mode) || Meeseeker.stream_mode
|
91
104
|
options[:include_virtual] ||= Meeseeker.include_virtual
|
@@ -93,8 +106,9 @@ module Meeseeker
|
|
93
106
|
if !!options[:at_block_num]
|
94
107
|
last_block_num = options[:at_block_num].to_i
|
95
108
|
else
|
96
|
-
|
97
|
-
|
109
|
+
url = Meeseeker.default_url(chain)
|
110
|
+
database_api = Meeseeker.database_api_class(chain).new(url: url)
|
111
|
+
last_block_num = redis.get(chain_key_prefix + LAST_BLOCK_NUM_KEY_SUFFIX).to_i + 1
|
98
112
|
|
99
113
|
block_num = catch :dynamic_global_properties do
|
100
114
|
database_api.get_dynamic_global_properties do |dgpo|
|
@@ -125,11 +139,12 @@ module Meeseeker
|
|
125
139
|
end
|
126
140
|
|
127
141
|
begin
|
128
|
-
|
142
|
+
url = Meeseeker.default_url(chain)
|
143
|
+
stream_options = {url: url, mode: mode}
|
129
144
|
options = options.merge(at_block_num: last_block_num)
|
130
145
|
condenser_api = nil
|
131
146
|
|
132
|
-
|
147
|
+
Meeseeker.stream_class.new(stream_options).tap do |stream|
|
133
148
|
puts "Stream begin: #{stream_options.to_json}; #{options.to_json}"
|
134
149
|
|
135
150
|
# Prior to v0.0.4, we only streamed operations with stream.operations.
|
@@ -165,7 +180,8 @@ module Meeseeker
|
|
165
180
|
|
166
181
|
loop do
|
167
182
|
# TODO (HF23) Switch to account_history_api.enum_virtual_ops if supported.
|
168
|
-
|
183
|
+
url = Meeseeker.default_url(chain)
|
184
|
+
condenser_api ||= Meeseeker.condenser_api_class(chain).new(url: url)
|
169
185
|
condenser_api.get_ops_in_block(n, true) do |vops|
|
170
186
|
if vops.nil?
|
171
187
|
puts "Node returned empty result for get_ops_in_block on block_num: #{n} (rate limiting?). Retrying ..."
|
@@ -181,7 +197,7 @@ module Meeseeker
|
|
181
197
|
if retries < MAX_VOP_RETRY
|
182
198
|
retries = retries + 1
|
183
199
|
condenser_api = nil
|
184
|
-
sleep
|
200
|
+
sleep Meeseeker::BLOCK_INTERVAL * retries
|
185
201
|
|
186
202
|
redo
|
187
203
|
end
|
@@ -217,8 +233,8 @@ module Meeseeker
|
|
217
233
|
# We need to tell steem-ruby to avoid json-rpc-batch on this
|
218
234
|
# node.
|
219
235
|
|
220
|
-
|
221
|
-
sleep
|
236
|
+
Meeseeker.block_api_class(chain).const_set 'MAX_RANGE_SIZE', 1
|
237
|
+
sleep Meeseeker::BLOCK_INTERVAL
|
222
238
|
redo
|
223
239
|
end
|
224
240
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Meeseeker::HiveEngine
|
2
|
+
|
3
|
+
class Agent < Meeseeker::SteemEngine::Agent
|
4
|
+
def initialize(options = {})
|
5
|
+
super
|
6
|
+
|
7
|
+
self.user_agent = Meeseeker::AGENT_ID
|
8
|
+
self.max_history = 0
|
9
|
+
self.default_encoding = 'UTF-8'
|
10
|
+
|
11
|
+
@node_url = options[:url] || Meeseeker::hive_engine_node_url
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class FollowerJob < Meeseeker::SteemEngine::FollowerJob
|
16
|
+
def initialize(options = {})
|
17
|
+
@chain_key_prefix = options[:chain_key_prefix] || Meeseeker::HIVE_ENGINE_CHAIN_KEY_PREFIX
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -26,30 +26,44 @@ module Meeseeker::SteemEngine
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def latest_block_info
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
5.times do
|
30
|
+
request_body = {
|
31
|
+
jsonrpc: "2.0",
|
32
|
+
method: :getLatestBlockInfo,
|
33
|
+
id: rpc_id
|
34
|
+
}.to_json
|
35
|
+
|
36
|
+
response = request_with_entity :post, blockchain_uri, request_body, POST_HEADERS
|
37
|
+
latest_block_info = JSON[response.body]["result"]
|
38
|
+
|
39
|
+
return latest_block_info if !!latest_block_info
|
40
|
+
|
41
|
+
sleep 3
|
42
|
+
end
|
34
43
|
|
35
|
-
|
36
|
-
|
37
|
-
JSON[response.body]["result"]
|
44
|
+
return nil
|
38
45
|
end
|
39
46
|
|
40
47
|
def block(block_num)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
5.times do
|
49
|
+
request_body = {
|
50
|
+
jsonrpc: "2.0",
|
51
|
+
method: :getBlockInfo,
|
52
|
+
params: {
|
53
|
+
blockNumber: block_num.to_i
|
54
|
+
},
|
55
|
+
id: rpc_id
|
56
|
+
}.to_json
|
57
|
+
|
58
|
+
response = request_with_entity :post, blockchain_uri, request_body, POST_HEADERS
|
59
|
+
block = JSON[response.body]["result"]
|
60
|
+
|
61
|
+
return block if !!block
|
62
|
+
|
63
|
+
sleep 3
|
64
|
+
end
|
51
65
|
|
52
|
-
|
66
|
+
return nil
|
53
67
|
end
|
54
68
|
private
|
55
69
|
def rpc_id
|
@@ -2,6 +2,14 @@ module Meeseeker::SteemEngine
|
|
2
2
|
MAX_RETRY_INTERVAL = 18.0
|
3
3
|
|
4
4
|
class FollowerJob
|
5
|
+
def initialize(options = {})
|
6
|
+
@chain_key_prefix = options[:chain_key_prefix] || Meeseeker::STEEM_ENGINE_CHAIN_KEY_PREFIX
|
7
|
+
end
|
8
|
+
|
9
|
+
def chain_name
|
10
|
+
@chain_key_prefix.split('_').map(&:capitalize).join(' ')
|
11
|
+
end
|
12
|
+
|
5
13
|
def perform(options = {})
|
6
14
|
redis = Meeseeker.redis
|
7
15
|
last_key_prefix = nil
|
@@ -16,7 +24,7 @@ module Meeseeker::SteemEngine
|
|
16
24
|
begin
|
17
25
|
trx_id = transaction['transactionId'].to_s.split('-').first
|
18
26
|
block_num = block['blockNumber']
|
19
|
-
current_key_prefix = "
|
27
|
+
current_key_prefix = "#{@chain_key_prefix}:#{block_num}:#{trx_id}"
|
20
28
|
contract = transaction['contract']
|
21
29
|
action = transaction['action']
|
22
30
|
|
@@ -34,15 +42,15 @@ module Meeseeker::SteemEngine
|
|
34
42
|
block_transactions << trx_id
|
35
43
|
|
36
44
|
trx_pub_key = if !!virtual
|
37
|
-
|
45
|
+
"#{@chain_key_prefix}:virtual_transaction"
|
38
46
|
else
|
39
|
-
|
47
|
+
"#{@chain_key_prefix}:transaction"
|
40
48
|
end
|
41
49
|
|
42
50
|
redis.publish(trx_pub_key, transaction_payload.to_json)
|
43
51
|
end
|
44
52
|
|
45
|
-
last_key_prefix = "
|
53
|
+
last_key_prefix = "#{@chain_key_prefix}:#{block_num}:#{trx_id}"
|
46
54
|
trx_index = 0
|
47
55
|
end
|
48
56
|
|
@@ -50,6 +58,12 @@ module Meeseeker::SteemEngine
|
|
50
58
|
puts key
|
51
59
|
end
|
52
60
|
|
61
|
+
unless Meeseeker.max_keys == -1
|
62
|
+
while redis.keys("#{@chain_key_prefix}:*").size > Meeseeker.max_keys
|
63
|
+
sleep Meeseeker::BLOCK_INTERVAL
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
53
67
|
redis.set(key, transaction.to_json)
|
54
68
|
redis.expire(key, Meeseeker.expire_keys) unless Meeseeker.expire_keys == -1
|
55
69
|
|
@@ -59,18 +73,21 @@ module Meeseeker::SteemEngine
|
|
59
73
|
block_num: block_num
|
60
74
|
}
|
61
75
|
|
62
|
-
redis.set(Meeseeker::
|
63
|
-
redis.publish(
|
76
|
+
redis.set(@chain_key_prefix + Meeseeker::LAST_STEEM_ENGINE_BLOCK_NUM_KEY_SUFFIX, block_num)
|
77
|
+
redis.publish("#{@chain_key_prefix}:block", block_payload.to_json)
|
64
78
|
current_block_num = block_num
|
65
79
|
end
|
66
80
|
|
67
|
-
redis.publish("
|
68
|
-
redis.publish("
|
81
|
+
redis.publish("#{@chain_key_prefix}:#{contract}", {key: key}.to_json)
|
82
|
+
redis.publish("#{@chain_key_prefix}:#{contract}:#{action}", {key: key}.to_json)
|
69
83
|
end
|
70
84
|
end
|
71
85
|
private
|
72
86
|
def agent
|
73
|
-
@agent ||=
|
87
|
+
@agent ||= case @chain_key_prefix
|
88
|
+
when 'steem_engine' then Agent.new
|
89
|
+
when 'hive_engine' then Meeseeker::HiveEngine::Agent.new
|
90
|
+
end
|
74
91
|
end
|
75
92
|
|
76
93
|
def agent_reset
|
@@ -100,7 +117,7 @@ module Meeseeker::SteemEngine
|
|
100
117
|
last_block_num = options[:at_block_num].to_i
|
101
118
|
else
|
102
119
|
new_sync = false
|
103
|
-
last_block_num = redis.get(Meeseeker::
|
120
|
+
last_block_num = redis.get(@chain_key_prefix + Meeseeker::LAST_STEEM_ENGINE_BLOCK_NUM_KEY_SUFFIX)
|
104
121
|
block_info = agent.latest_block_info
|
105
122
|
block_num = block_info['blockNumber']
|
106
123
|
last_block = agent.block(block_num)
|
@@ -116,13 +133,13 @@ module Meeseeker::SteemEngine
|
|
116
133
|
if Meeseeker.expire_keys == -1
|
117
134
|
last_block_num = [last_block_num, block_num].max
|
118
135
|
|
119
|
-
puts "Sync
|
136
|
+
puts "Sync #{chain_name} from: #{last_block_num}"
|
120
137
|
elsif new_sync || (Time.now.utc - last_block_timestamp > Meeseeker.expire_keys)
|
121
138
|
last_block_num = block_num + 1
|
122
139
|
|
123
|
-
puts
|
140
|
+
puts "Starting new #{chain_name} sync."
|
124
141
|
else
|
125
|
-
puts "Resuming from
|
142
|
+
puts "Resuming from #{chain_name} block #{last_block_num} ..."
|
126
143
|
end
|
127
144
|
end
|
128
145
|
|
@@ -140,7 +157,7 @@ module Meeseeker::SteemEngine
|
|
140
157
|
end
|
141
158
|
|
142
159
|
if block.nil?
|
143
|
-
sleep
|
160
|
+
sleep Meeseeker::BLOCK_INTERVAL
|
144
161
|
redo
|
145
162
|
end
|
146
163
|
|