zold 0.14.8 → 0.14.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +0 -0
- data/Gemfile +2 -0
- data/Rakefile +2 -0
- data/appveyor.yml +8 -3
- data/features/step_definitions/steps.rb +2 -0
- data/features/support/env.rb +2 -0
- data/fixtures/merge/asserts.rb +2 -0
- data/fixtures/merge/into-no-wallet/assert.rb +2 -0
- data/fixtures/merge/random-expenses/assert.rb +2 -0
- data/fixtures/merge/simple-case/assert.rb +2 -0
- data/fixtures/scripts/_head.sh +13 -0
- data/fixtures/scripts/distribute-wallet.sh +86 -0
- data/fixtures/scripts/spread-wallets.sh +56 -0
- data/lib/zold.rb +2 -0
- data/lib/zold/amount.rb +3 -1
- data/lib/zold/atomic_file.rb +2 -0
- data/lib/zold/backtrace.rb +2 -0
- data/lib/zold/commands/alias.rb +2 -0
- data/lib/zold/commands/args.rb +2 -0
- data/lib/zold/commands/calculate.rb +5 -3
- data/lib/zold/commands/clean.rb +2 -0
- data/lib/zold/commands/create.rb +2 -0
- data/lib/zold/commands/diff.rb +2 -0
- data/lib/zold/commands/fetch.rb +7 -2
- data/lib/zold/commands/invoice.rb +2 -0
- data/lib/zold/commands/list.rb +2 -0
- data/lib/zold/commands/merge.rb +2 -0
- data/lib/zold/commands/node.rb +2 -0
- data/lib/zold/commands/pay.rb +2 -0
- data/lib/zold/commands/propagate.rb +2 -0
- data/lib/zold/commands/pull.rb +2 -0
- data/lib/zold/commands/push.rb +2 -0
- data/lib/zold/commands/remote.rb +11 -6
- data/lib/zold/commands/routines/bonuses.rb +78 -0
- data/lib/zold/commands/routines/reconnect.rb +2 -0
- data/lib/zold/commands/routines/spread.rb +2 -0
- data/lib/zold/commands/show.rb +2 -0
- data/lib/zold/commands/taxes.rb +2 -0
- data/lib/zold/copies.rb +4 -2
- data/lib/zold/hexnum.rb +2 -0
- data/lib/zold/http.rb +28 -20
- data/lib/zold/hungry_wallets.rb +2 -0
- data/lib/zold/id.rb +2 -0
- data/lib/zold/json_page.rb +2 -0
- data/lib/zold/key.rb +2 -0
- data/lib/zold/log.rb +2 -0
- data/lib/zold/metronome.rb +2 -0
- data/lib/zold/node/async_entrance.rb +3 -3
- data/lib/zold/node/emission.rb +2 -0
- data/lib/zold/node/entrance.rb +5 -2
- data/lib/zold/node/farm.rb +3 -1
- data/lib/zold/node/front.rb +4 -1
- data/lib/zold/node/safe_entrance.rb +2 -0
- data/lib/zold/node/spread_entrance.rb +2 -0
- data/lib/zold/patch.rb +2 -0
- data/lib/zold/prefixes.rb +2 -0
- data/lib/zold/remotes.rb +15 -13
- data/lib/zold/score.rb +62 -59
- data/lib/zold/signature.rb +2 -0
- data/lib/zold/tax.rb +3 -1
- data/lib/zold/txn.rb +4 -2
- data/lib/zold/type.rb +36 -0
- data/lib/zold/upgrades.rb +2 -4
- data/lib/zold/verbose_thread.rb +2 -0
- data/lib/zold/version.rb +4 -2
- data/lib/zold/version_file.rb +2 -0
- data/lib/zold/wallet.rb +4 -2
- data/lib/zold/wallets.rb +2 -0
- data/test/commands/routines/test_bonuses.rb +76 -0
- data/test/commands/routines/test_reconnect.rb +2 -0
- data/test/commands/routines/test_spread.rb +2 -0
- data/test/commands/test_alias.rb +2 -0
- data/test/commands/test_calculate.rb +2 -0
- data/test/commands/test_clean.rb +2 -0
- data/test/commands/test_create.rb +2 -0
- data/test/commands/test_diff.rb +2 -0
- data/test/commands/test_fetch.rb +2 -0
- data/test/commands/test_invoice.rb +2 -0
- data/test/commands/test_list.rb +2 -0
- data/test/commands/test_merge.rb +2 -0
- data/test/commands/test_node.rb +6 -0
- data/test/commands/test_pay.rb +2 -0
- data/test/commands/test_propagate.rb +2 -0
- data/test/commands/test_push.rb +2 -0
- data/test/commands/test_remote.rb +40 -0
- data/test/commands/test_show.rb +2 -0
- data/test/commands/test_taxes.rb +2 -0
- data/test/fake_home.rb +2 -0
- data/test/node/fake_entrance.rb +2 -0
- data/test/node/fake_node.rb +3 -1
- data/test/node/test_async_entrance.rb +2 -0
- data/test/node/test_emission.rb +2 -0
- data/test/node/test_entrance.rb +2 -0
- data/test/node/test_farm.rb +9 -7
- data/test/node/test_front.rb +15 -10
- data/test/node/test_safe_entrance.rb +2 -0
- data/test/node/test_spread_entrance.rb +2 -0
- data/test/test__helper.rb +2 -0
- data/test/test_amount.rb +2 -0
- data/test/test_atomic_file.rb +2 -0
- data/test/test_backtrace.rb +2 -0
- data/test/test_copies.rb +4 -1
- data/test/test_hexnum.rb +2 -0
- data/test/test_http.rb +5 -3
- data/test/test_id.rb +2 -0
- data/test/test_key.rb +2 -0
- data/test/test_metronome.rb +2 -0
- data/test/test_patch.rb +2 -0
- data/test/test_prefixes.rb +2 -0
- data/test/test_remotes.rb +11 -0
- data/test/test_score.rb +26 -24
- data/test/test_signature.rb +2 -0
- data/test/test_tax.rb +4 -2
- data/test/test_txn.rb +2 -0
- data/test/test_upgrades.rb +2 -0
- data/test/test_verbose_thread.rb +2 -0
- data/test/test_version.rb +2 -0
- data/test/test_wallet.rb +2 -0
- data/test/test_wallets.rb +2 -0
- data/test/test_zold.rb +2 -0
- data/test/upgrades/test_protocol_up.rb +2 -0
- data/upgrades/2.rb +2 -0
- data/upgrades/protocol_up.rb +2 -0
- data/upgrades/rename_foreign_wallets.rb +2 -0
- data/zold.gemspec +5 -1
- metadata +38 -4
data/lib/zold/commands/remote.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright (c) 2018 Yegor Bugayenko
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -138,7 +140,7 @@ Available options:"
|
|
138
140
|
|
139
141
|
def show
|
140
142
|
@remotes.all.each do |r|
|
141
|
-
score = Rainbow("/#{r[:score]}").color(r[:score]
|
143
|
+
score = Rainbow("/#{r[:score]}").color(r[:score].positive? ? :green : :red)
|
142
144
|
@log.info(r[:host] + Rainbow(":#{r[:port]}").gray + score)
|
143
145
|
end
|
144
146
|
end
|
@@ -155,7 +157,7 @@ Available options:"
|
|
155
157
|
|
156
158
|
def add(host, port, opts)
|
157
159
|
unless opts['skip-ping']
|
158
|
-
res = Http.new("http://#{host}:#{port}/version", network: opts['network']).get
|
160
|
+
res = Http.new(uri: "http://#{host}:#{port}/version", score: nil, network: opts['network']).get
|
159
161
|
raise "The node #{host}:#{port} is not responding (code is #{res.code})" unless res.code == '200'
|
160
162
|
end
|
161
163
|
if @remotes.exists?(host, port)
|
@@ -251,10 +253,13 @@ in #{(Time.now - start).round(2)}s")
|
|
251
253
|
end
|
252
254
|
end
|
253
255
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
256
|
+
def select(opts)
|
257
|
+
max_nodes = opts['max-nodes']
|
258
|
+
@log.info("Selecting #{max_nodes} strongest nodes.")
|
259
|
+
selected_remotes = @remotes.all.sort_by { |remote| remote[:score] }.first(max_nodes)
|
260
|
+
(@remotes.all - selected_remotes).each do |weak_remote|
|
261
|
+
@remotes.remove(weak_remote[:host], weak_remote[:port])
|
262
|
+
end
|
258
263
|
end
|
259
264
|
|
260
265
|
def terminate
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
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 all
|
13
|
+
# 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 NONINFINGEMENT. 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 THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
require_relative '../remote'
|
24
|
+
require_relative '../pull'
|
25
|
+
require_relative '../pay'
|
26
|
+
require_relative '../push'
|
27
|
+
|
28
|
+
# Pay bonuses routine.
|
29
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
31
|
+
# License:: MIT
|
32
|
+
module Zold
|
33
|
+
# Routines module
|
34
|
+
module Routines
|
35
|
+
# Pay bonuses to random nodes
|
36
|
+
class Bonuses
|
37
|
+
def initialize(opts, wallets, remotes, copies, farm, log: Log::Quiet.new)
|
38
|
+
@opts = opts
|
39
|
+
@wallets = wallets
|
40
|
+
@remotes = remotes
|
41
|
+
@copies = copies
|
42
|
+
@farm = farm
|
43
|
+
@log = log
|
44
|
+
end
|
45
|
+
|
46
|
+
def exec(_ = 0)
|
47
|
+
sleep(@opts['bonus-time'] * 60) unless @opts['routine-immediately']
|
48
|
+
raise '--private-key is required to pay bonuses' unless @opts['private-key']
|
49
|
+
raise '--bonus-wallet is required to pay bonuses' unless @opts['bonus-wallet']
|
50
|
+
raise '--bonus-amount is required to pay bonuses' unless @opts['bonus-amount']
|
51
|
+
winners = Remote.new(remotes: @remotes, log: @log, farm: @farm).run(
|
52
|
+
['remote', 'elect', @opts['bonus-wallet'], '--private-key', @opts['private-key']] +
|
53
|
+
(@opts['ignore-score-weakness'] ? ['--ignore-score-weakness'] : [])
|
54
|
+
)
|
55
|
+
return if winners.empty?
|
56
|
+
unless @wallets.find(Id.new(@opts['bonus-wallet'])).exists?
|
57
|
+
Pull.new(wallets: @wallets, remotes: @remotes, copies: @copies, log: @log).run(
|
58
|
+
['pull', @opts['bonus-wallet']] +
|
59
|
+
(@opts['ignore-score-weakness'] ? ['--ignore-score-weakness'] : [])
|
60
|
+
)
|
61
|
+
end
|
62
|
+
winners.each do |score|
|
63
|
+
Pay.new(wallets: @wallets, remotes: @remotes, log: @log).run(
|
64
|
+
[
|
65
|
+
'pay', @opts['bonus-wallet'], score.invoice, @opts['bonus-amount'].to_s,
|
66
|
+
"Hosting bonus for #{score.host} #{score.port} #{score.value}",
|
67
|
+
'--private-key', @opts['private-key']
|
68
|
+
]
|
69
|
+
)
|
70
|
+
end
|
71
|
+
Push.new(wallets: @wallets, remotes: @remotes, log: @log).run(
|
72
|
+
['push', @opts['bonus-wallet']] +
|
73
|
+
(@opts['ignore-score-weakness'] ? ['--ignore-score-weakness'] : [])
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/zold/commands/show.rb
CHANGED
data/lib/zold/commands/taxes.rb
CHANGED
data/lib/zold/copies.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright (c) 2018 Yegor Bugayenko
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -88,11 +90,11 @@ module Zold
|
|
88
90
|
def add(content, host, port, score, time = Time.now)
|
89
91
|
raise "Content can't be empty" if content.empty?
|
90
92
|
raise 'TCP port must be of type Integer' unless port.is_a?(Integer)
|
91
|
-
raise "TCP port can't be negative: #{port}" if port
|
93
|
+
raise "TCP port can't be negative: #{port}" if port.negative?
|
92
94
|
raise 'Time must be of type Time' unless time.is_a?(Time)
|
93
95
|
raise "Time must be in the past: #{time}" if time > Time.now
|
94
96
|
raise 'Score must be Integer' unless score.is_a?(Integer)
|
95
|
-
raise "Score can't be negative: #{score}" if score
|
97
|
+
raise "Score can't be negative: #{score}" if score.negative?
|
96
98
|
@mutex.synchronize do
|
97
99
|
FileUtils.mkdir_p(@dir)
|
98
100
|
list = load
|
data/lib/zold/hexnum.rb
CHANGED
data/lib/zold/http.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright (c) 2018 Yegor Bugayenko
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -24,6 +26,7 @@ require 'net/http'
|
|
24
26
|
require_relative 'backtrace'
|
25
27
|
require_relative 'version'
|
26
28
|
require_relative 'score'
|
29
|
+
require_relative 'type'
|
27
30
|
|
28
31
|
# HTTP page.
|
29
32
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -31,48 +34,53 @@ require_relative 'score'
|
|
31
34
|
# License:: MIT
|
32
35
|
module Zold
|
33
36
|
# Http page
|
34
|
-
class Http
|
37
|
+
class Http < Dry::Struct
|
35
38
|
# HTTP header we add to each HTTP request, in order to inform
|
36
39
|
# the other node about the score. If the score is big enough,
|
37
40
|
# the remote node will add us to its list of remote nodes.
|
38
|
-
SCORE_HEADER = 'X-Zold-Score'
|
41
|
+
SCORE_HEADER = 'X-Zold-Score'
|
39
42
|
|
40
43
|
# HTTP header we add, in order to inform the node about our
|
41
44
|
# version. This is done mostly in order to let the other node
|
42
45
|
# reboot itself, if the version is higher.
|
43
|
-
VERSION_HEADER = 'X-Zold-Version'
|
46
|
+
VERSION_HEADER = 'X-Zold-Version'
|
44
47
|
|
45
48
|
# HTTP header we add, in order to inform the node about our
|
46
49
|
# network. This is done in order to isolate test networks from
|
47
50
|
# production one.
|
48
|
-
NETWORK_HEADER = 'X-Zold-Network'
|
51
|
+
NETWORK_HEADER = 'X-Zold-Network'
|
49
52
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
# @todo #98:30m/DEV The following two statements are seen as issues by rubocop
|
54
|
+
# raising a Lint/AmbiguousBlockAssociation offense. It is somthing
|
55
|
+
# that could be solved by changing the TargetRubyVersion in .rubocop.yml
|
56
|
+
# that is already taken care of in another issue. I am leaving a todo
|
57
|
+
# to check that rubocop doesn't complain anymore, otherwise find another
|
58
|
+
# solution
|
59
|
+
attribute :uri, (Types::Class.constructor do |value|
|
60
|
+
value.is_a?(URI) ? value : URI(value)
|
61
|
+
end)
|
62
|
+
attribute :score, (Types::Class.constructor do |value|
|
63
|
+
value.nil? ? Score::ZERO : value
|
64
|
+
end)
|
65
|
+
attribute :network, Types::Strict::String.optional.default('test')
|
58
66
|
|
59
67
|
def get
|
60
|
-
http = Net::HTTP.new(
|
68
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
61
69
|
http.read_timeout = 8
|
62
70
|
http.open_timeout = 4
|
63
|
-
path =
|
64
|
-
path += '?' +
|
71
|
+
path = uri.path
|
72
|
+
path += '?' + uri.query if uri.query
|
65
73
|
http.request_get(path, headers)
|
66
74
|
rescue StandardError => e
|
67
75
|
Error.new(e)
|
68
76
|
end
|
69
77
|
|
70
78
|
def put(body)
|
71
|
-
http = Net::HTTP.new(
|
79
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
72
80
|
http.read_timeout = 16
|
73
81
|
http.open_timeout = 4
|
74
|
-
path =
|
75
|
-
path += '?' +
|
82
|
+
path = uri.path
|
83
|
+
path += '?' + uri.query if uri.query
|
76
84
|
http.request_put(
|
77
85
|
path, body,
|
78
86
|
headers.merge(
|
@@ -112,8 +120,8 @@ module Zold
|
|
112
120
|
'Accept-Encoding': 'gzip'
|
113
121
|
}
|
114
122
|
headers[Http::VERSION_HEADER] = VERSION
|
115
|
-
headers[Http::NETWORK_HEADER] =
|
116
|
-
headers[Http::SCORE_HEADER] =
|
123
|
+
headers[Http::NETWORK_HEADER] = network
|
124
|
+
headers[Http::SCORE_HEADER] = score.reduced(4).to_text if score.valid? && !score.expired? && score.value > 3
|
117
125
|
headers
|
118
126
|
end
|
119
127
|
end
|
data/lib/zold/hungry_wallets.rb
CHANGED
data/lib/zold/id.rb
CHANGED
data/lib/zold/json_page.rb
CHANGED
data/lib/zold/key.rb
CHANGED
data/lib/zold/log.rb
CHANGED
data/lib/zold/metronome.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright (c) 2018 Yegor Bugayenko
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -77,10 +79,8 @@ module Zold
|
|
77
79
|
|
78
80
|
def to_json
|
79
81
|
@entrance.to_json.merge(
|
80
|
-
'
|
81
|
-
'pool.largest_length': @pool.largest_length,
|
82
|
+
'queue': queue.count,
|
82
83
|
'pool.length': @pool.length,
|
83
|
-
'pool.queue_length': @pool.queue_length,
|
84
84
|
'pool.running': @pool.running?
|
85
85
|
)
|
86
86
|
end
|
data/lib/zold/node/emission.rb
CHANGED
data/lib/zold/node/entrance.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright (c) 2018 Yegor Bugayenko
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -60,7 +62,8 @@ module Zold
|
|
60
62
|
|
61
63
|
def to_json
|
62
64
|
{
|
63
|
-
history: @history.join(', ')
|
65
|
+
'history': @history.join(', '),
|
66
|
+
'history_size': @history.count
|
64
67
|
}
|
65
68
|
end
|
66
69
|
|
@@ -76,7 +79,7 @@ module Zold
|
|
76
79
|
unless @remotes.all.empty?
|
77
80
|
Fetch.new(
|
78
81
|
wallets: @wallets, remotes: @remotes, copies: copies.root, log: @log
|
79
|
-
).run(['fetch', id.to_s, "--ignore-node=#{@address}", "--network=#{@network}"])
|
82
|
+
).run(['fetch', id.to_s, "--ignore-node=#{@address}", "--network=#{@network}", '--quiet-if-absent'])
|
80
83
|
end
|
81
84
|
modified = Merge.new(
|
82
85
|
wallets: @wallets, copies: copies.root, log: @log
|
data/lib/zold/node/farm.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright (c) 2018 Yegor Bugayenko
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -121,7 +123,7 @@ module Zold
|
|
121
123
|
def cleanup(host, port, strength, threads)
|
122
124
|
scores = load
|
123
125
|
before = scores.map(&:value).max.to_i
|
124
|
-
save(threads, [Score.new(Time.now, host, port, @invoice, strength: strength)])
|
126
|
+
save(threads, [Score.new(time: Time.now, host: host, port: port, invoice: @invoice, strength: strength)])
|
125
127
|
scores = load
|
126
128
|
push(scores)
|
127
129
|
after = scores.map(&:value).max.to_i
|
data/lib/zold/node/front.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright (c) 2018 Yegor Bugayenko
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -131,6 +133,7 @@ module Zold
|
|
131
133
|
JSON.pretty_generate(
|
132
134
|
version: settings.version,
|
133
135
|
network: settings.network,
|
136
|
+
protocol: settings.protocol,
|
134
137
|
score: score.to_h,
|
135
138
|
pid: Process.pid,
|
136
139
|
cpus: Concurrent.processor_count,
|
@@ -203,7 +206,7 @@ module Zold
|
|
203
206
|
wallet.network,
|
204
207
|
wallet.protocol,
|
205
208
|
wallet.id.to_s,
|
206
|
-
wallet.key.
|
209
|
+
wallet.key.to_pub,
|
207
210
|
'',
|
208
211
|
wallet.txns.map(&:to_text).join("\n"),
|
209
212
|
'',
|
data/lib/zold/patch.rb
CHANGED
data/lib/zold/prefixes.rb
CHANGED
data/lib/zold/remotes.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright (c) 2018 Yegor Bugayenko
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -77,7 +79,7 @@ module Zold
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def http(path = '/')
|
80
|
-
Http.new("http://#{@host}:#{@port}#{path}", @score, network: @network)
|
82
|
+
Http.new(uri: "http://#{@host}:#{@port}#{path}", score: @score, network: @network)
|
81
83
|
end
|
82
84
|
|
83
85
|
def to_s
|
@@ -155,12 +157,11 @@ module Zold
|
|
155
157
|
raise 'Port can\'t be nil' if port.nil?
|
156
158
|
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
|
157
159
|
raise 'Port can\'t be zero' if port.zero?
|
158
|
-
raise 'Port can\'t be negative' if port
|
160
|
+
raise 'Port can\'t be negative' if port.negative?
|
159
161
|
raise 'Port can\'t be over 65536' if port > 0xffff
|
160
162
|
raise "#{host}:#{port} already exists" if exists?(host, port)
|
161
163
|
list = load
|
162
164
|
list << { host: host.downcase, port: port, score: 0 }
|
163
|
-
list.uniq! { |r| "#{r[:host]}:#{r[:port]}" }
|
164
165
|
save(list)
|
165
166
|
end
|
166
167
|
|
@@ -168,7 +169,6 @@ module Zold
|
|
168
169
|
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
|
169
170
|
raise 'Host can\'t be nil' if host.nil?
|
170
171
|
raise 'Port can\'t be nil' if port.nil?
|
171
|
-
raise "#{host}:#{port} is absent" unless exists?(host, port)
|
172
172
|
list = load
|
173
173
|
list.reject! { |r| r[:host] == host.downcase && r[:port] == port }
|
174
174
|
save(list)
|
@@ -211,10 +211,7 @@ in #{(Time.now - start).round}s; errors=#{errors}")
|
|
211
211
|
raise 'Host can\'t be nil' if host.nil?
|
212
212
|
raise 'Port can\'t be nil' if port.nil?
|
213
213
|
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
|
214
|
-
|
215
|
-
raise "#{host}:#{port} is absent among #{list.count} remotes" unless exists?(host, port)
|
216
|
-
list.find { |r| r[:host] == host.downcase && r[:port] == port }[:errors] += 1
|
217
|
-
save(list)
|
214
|
+
if_present(host, port) { |r| r[:errors] += 1 }
|
218
215
|
end
|
219
216
|
|
220
217
|
def rescore(host, port, score)
|
@@ -222,14 +219,19 @@ in #{(Time.now - start).round}s; errors=#{errors}")
|
|
222
219
|
raise 'Port can\'t be nil' if port.nil?
|
223
220
|
raise 'Score can\'t be nil' if score.nil?
|
224
221
|
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
|
225
|
-
|
226
|
-
list = load
|
227
|
-
list.find { |r| r[:host] == host.downcase && r[:port] == port }[:score] = score
|
228
|
-
save(list)
|
222
|
+
if_present(host, port) { |r| r[:score] = score }
|
229
223
|
end
|
230
224
|
|
231
225
|
private
|
232
226
|
|
227
|
+
def if_present(host, port)
|
228
|
+
list = load
|
229
|
+
remote = list.find { |r| r[:host] == host.downcase && r[:port] == port }
|
230
|
+
return unless remote
|
231
|
+
yield remote
|
232
|
+
save(list)
|
233
|
+
end
|
234
|
+
|
233
235
|
def load
|
234
236
|
@mutex.synchronize do
|
235
237
|
raw = CSV.read(file).map do |r|
|
@@ -250,7 +252,7 @@ in #{(Time.now - start).round}s; errors=#{errors}")
|
|
250
252
|
def save(list)
|
251
253
|
@mutex.synchronize do
|
252
254
|
AtomicFile.new(file).write(
|
253
|
-
list.map do |r|
|
255
|
+
list.uniq { |r| "#{r[:host]}:#{r[:port]}" }.map do |r|
|
254
256
|
[
|
255
257
|
r[:host],
|
256
258
|
r[:port],
|