zold 0.5 → 0.6
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/.rubocop.yml +4 -2
- data/bin/zold +34 -48
- data/features/cli.feature +1 -1
- data/features/step_definitions/steps.rb +1 -3
- data/features/support/env.rb +2 -0
- data/fixtures/scripts/push-and-pull.sh +6 -4
- data/lib/zold/amount.rb +17 -3
- data/lib/zold/commands/create.rb +9 -6
- data/lib/zold/commands/fetch.rb +11 -21
- data/lib/zold/commands/node.rb +7 -9
- data/lib/zold/commands/pay.rb +9 -6
- data/lib/zold/commands/propagate.rb +4 -5
- data/lib/zold/commands/push.rb +10 -5
- data/lib/zold/commands/remote.rb +22 -24
- data/lib/zold/commands/show.rb +1 -2
- data/lib/zold/commands/taxes.rb +154 -0
- data/lib/zold/http.rb +1 -3
- data/lib/zold/key.rb +1 -3
- data/lib/zold/node/entrance.rb +8 -3
- data/lib/zold/node/farm.rb +8 -6
- data/lib/zold/node/front.rb +0 -1
- data/lib/zold/patch.rb +1 -1
- data/lib/zold/remotes.rb +4 -0
- data/lib/zold/score.rb +85 -10
- data/lib/zold/signature.rb +7 -7
- data/lib/zold/tax.rb +79 -0
- data/lib/zold/txn.rb +12 -7
- data/lib/zold/version.rb +1 -1
- data/lib/zold/wallet.rb +2 -2
- data/test/commands/test_create.rb +3 -4
- data/test/commands/test_diff.rb +2 -3
- data/test/commands/test_merge.rb +4 -6
- data/test/commands/test_pay.rb +7 -5
- data/test/commands/test_remote.rb +5 -3
- data/test/commands/test_taxes.rb +66 -0
- data/test/node/fake_node.rb +1 -0
- data/test/node/test_farm.rb +2 -1
- data/test/node/test_front.rb +1 -0
- data/test/test__helper.rb +2 -0
- data/test/test_remotes.rb +0 -1
- data/test/test_score.rb +40 -21
- data/test/test_signature.rb +6 -3
- data/test/test_tax.rb +53 -0
- data/test/test_txn.rb +46 -0
- data/test/test_wallet.rb +2 -2
- data/test/test_zold.rb +1 -1
- data/wp/.gitignore +6 -0
- data/wp/wp.tex +38 -0
- data/zold.gemspec +1 -3
- metadata +12 -2
@@ -61,21 +61,20 @@ Available options:"
|
|
61
61
|
wallet.txns.select { |t| t.amount.negative? }.each do |t|
|
62
62
|
target = @wallets.find(t.bnf)
|
63
63
|
unless target.exists?
|
64
|
-
@log.debug("#{t.amount
|
64
|
+
@log.debug("#{t.amount * -1} to #{t.bnf}: wallet is absent")
|
65
65
|
next
|
66
66
|
end
|
67
67
|
next if target.has?(t.id, me)
|
68
68
|
unless Prefixes.new(target).valid?(t.prefix)
|
69
|
-
@log.info("#{t.amount
|
69
|
+
@log.info("#{t.amount * -1} to #{t.bnf}: wrong prefix")
|
70
70
|
next
|
71
71
|
end
|
72
72
|
target.add(t.inverse(me))
|
73
|
-
@log.info("#{t.amount
|
73
|
+
@log.info("#{t.amount * -1} arrived to #{t.bnf}: #{t.details}")
|
74
74
|
modified << t.id
|
75
75
|
end
|
76
76
|
modified.uniq!
|
77
|
-
@log.debug("Wallet #{me} propagated successfully,
|
78
|
-
#{modified.count} wallets affected")
|
77
|
+
@log.debug("Wallet #{me} propagated successfully, #{modified.count} wallets affected")
|
79
78
|
modified
|
80
79
|
end
|
81
80
|
end
|
data/lib/zold/commands/push.rb
CHANGED
@@ -69,12 +69,17 @@ Available options:"
|
|
69
69
|
next
|
70
70
|
end
|
71
71
|
json = JSON.parse(response.body)['score']
|
72
|
-
score = Score.
|
73
|
-
Time.parse(json['time']), json['host'],
|
74
|
-
json['port'], json['suffixes']
|
75
|
-
)
|
72
|
+
score = Score.parse_json(json)
|
76
73
|
unless score.valid?
|
77
|
-
@log.error("#{uri} invalid score")
|
74
|
+
@log.error("#{uri} invalid score: #{score}")
|
75
|
+
next
|
76
|
+
end
|
77
|
+
if score.expired?
|
78
|
+
@log.error("#{uri} expired score: #{score}")
|
79
|
+
next
|
80
|
+
end
|
81
|
+
if score.strength < Score::STRENGTH
|
82
|
+
@log.error("#{uri} score is too weak")
|
78
83
|
next
|
79
84
|
end
|
80
85
|
@log.info("#{uri} accepted: #{Rainbow(score.value).green}")
|
data/lib/zold/commands/remote.rb
CHANGED
@@ -50,9 +50,9 @@ Available commands:
|
|
50
50
|
Remove all registered remote nodes
|
51
51
|
#{Rainbow('remote reset').green}
|
52
52
|
Restore it back to the default list of nodes
|
53
|
-
#{Rainbow('remote add').green} host port
|
53
|
+
#{Rainbow('remote add').green} host [port]
|
54
54
|
Add a new remote node
|
55
|
-
#{Rainbow('remote remove').green} host port
|
55
|
+
#{Rainbow('remote remove').green} host [port]
|
56
56
|
Remove the remote node
|
57
57
|
#{Rainbow('remote update').green}
|
58
58
|
Check each registered remote node for availability
|
@@ -62,7 +62,7 @@ Available options:"
|
|
62
62
|
default: false
|
63
63
|
o.bool '--help', 'Print instructions'
|
64
64
|
end
|
65
|
-
command =
|
65
|
+
command = opts.arguments[0]
|
66
66
|
case command
|
67
67
|
when 'show'
|
68
68
|
show
|
@@ -71,9 +71,9 @@ Available options:"
|
|
71
71
|
when 'reset'
|
72
72
|
reset
|
73
73
|
when 'add'
|
74
|
-
add(opts.arguments[1], opts.arguments[2].to_i)
|
74
|
+
add(opts.arguments[1], opts.arguments[2] ? opts.arguments[2].to_i : Remotes::PORT)
|
75
75
|
when 'remove'
|
76
|
-
remove(opts.arguments[1], opts.arguments[2].to_i)
|
76
|
+
remove(opts.arguments[1], opts.arguments[2] ? opts.arguments[2].to_i : Remotes::PORT)
|
77
77
|
when 'update'
|
78
78
|
update(opts)
|
79
79
|
update(opts, false)
|
@@ -117,9 +117,7 @@ Available options:"
|
|
117
117
|
res = Http.new(uri).get
|
118
118
|
unless res.code == '200'
|
119
119
|
@remotes.remove(r[:host], r[:port])
|
120
|
-
@log.info(
|
121
|
-
"#{Rainbow(r[:host]).red} #{res.code} \"#{res.message}\" #{uri}"
|
122
|
-
)
|
120
|
+
@log.info("#{Rainbow(r[:host]).red} #{res.code} \"#{res.message}\" #{uri}")
|
123
121
|
next
|
124
122
|
end
|
125
123
|
begin
|
@@ -129,39 +127,39 @@ Available options:"
|
|
129
127
|
@log.info("#{Rainbow(r[:host]).red} \"#{e.message}\": #{res.body}")
|
130
128
|
next
|
131
129
|
end
|
132
|
-
score = Score.
|
133
|
-
Time.parse(json['score']['time']), r[:host],
|
134
|
-
r[:port], json['score']['suffixes']
|
135
|
-
)
|
130
|
+
score = Score.parse_json(json['score'])
|
136
131
|
unless score.valid?
|
137
132
|
remove(r[:host], r[:port])
|
138
133
|
@log.info("#{Rainbow(r[:host]).red} invalid score")
|
139
134
|
next
|
140
135
|
end
|
136
|
+
if score.expired?
|
137
|
+
remove(r[:host], r[:port])
|
138
|
+
@log.info("#{Rainbow(r[:host]).red} expired score")
|
139
|
+
next
|
140
|
+
end
|
141
141
|
if score.strength < Score::STRENGTH && !opts['ignore-score-weakness']
|
142
142
|
remove(r[:host], r[:port])
|
143
|
-
@log.info(
|
144
|
-
"#{Rainbow(r[:host]).red} score too weak: #{score.strength}"
|
145
|
-
)
|
143
|
+
@log.info("#{Rainbow(r[:host]).red} score too weak: #{score.strength}")
|
146
144
|
next
|
147
145
|
end
|
148
|
-
|
146
|
+
if r[:host] != score.host || r[:port] != score.port
|
147
|
+
@remotes.remove(r[:host], r[:port])
|
148
|
+
@remotes.add(score.host, score.port)
|
149
|
+
@log.info("#{r[:host]}:#{r[:port]} renamed to #{score.host}:#{score.port}")
|
150
|
+
end
|
151
|
+
@remotes.rescore(score.host, score.port, score.value)
|
149
152
|
if deep
|
150
153
|
json['all'].each do |s|
|
151
|
-
unless @remotes.exists?(s['host'], s['port'])
|
152
|
-
add(s['host'], s['port'])
|
153
|
-
end
|
154
|
+
add(s['host'], s['port']) unless @remotes.exists?(s['host'], s['port'])
|
154
155
|
end
|
155
156
|
end
|
156
|
-
@log.info("#{r[:host]}:#{r[:port]}: #{Rainbow(score.value).green}
|
157
|
-
(v.#{json['version']})")
|
157
|
+
@log.info("#{r[:host]}:#{r[:port]}: #{Rainbow(score.value).green} (v.#{json['version']})")
|
158
158
|
end
|
159
159
|
total = @remotes.all.size
|
160
160
|
if total.zero?
|
161
161
|
@log.debug("The list of remotes is #{Rainbow('empty').red}!")
|
162
|
-
@log.debug(
|
163
|
-
"Run 'zold remote add b1.zold.io 80` and then `zold update`"
|
164
|
-
)
|
162
|
+
@log.debug("Run 'zold remote add b1.zold.io` and then `zold update`")
|
165
163
|
else
|
166
164
|
@log.debug("There are #{total} known remotes")
|
167
165
|
end
|
data/lib/zold/commands/show.rb
CHANGED
@@ -60,8 +60,7 @@ Available options:"
|
|
60
60
|
def show(wallet, _)
|
61
61
|
balance = wallet.balance
|
62
62
|
wallet.txns.each do |t|
|
63
|
-
@log.info(
|
64
|
-
#{t.amount} #{t.bnf} #{t.details}")
|
63
|
+
@log.info(t.to_text)
|
65
64
|
end
|
66
65
|
@log.info("The balance of #{wallet}: #{balance}")
|
67
66
|
balance
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require 'slop'
|
22
|
+
require 'json'
|
23
|
+
require_relative 'pay'
|
24
|
+
require_relative '../log'
|
25
|
+
require_relative '../score'
|
26
|
+
require_relative '../id'
|
27
|
+
require_relative '../tax'
|
28
|
+
require_relative '../http'
|
29
|
+
|
30
|
+
# TAXES command.
|
31
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
32
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
33
|
+
# License:: MIT
|
34
|
+
module Zold
|
35
|
+
# Taxes command
|
36
|
+
class Taxes
|
37
|
+
def initialize(wallets:, remotes:, log: Log::Quiet.new)
|
38
|
+
@wallets = wallets
|
39
|
+
@remotes = remotes
|
40
|
+
@log = log
|
41
|
+
end
|
42
|
+
|
43
|
+
def run(args = [])
|
44
|
+
opts = Slop.parse(args, help: true) do |o|
|
45
|
+
o.banner = "Usage: zold taxes command [options]
|
46
|
+
Available commands:
|
47
|
+
#{Rainbow('taxes pay').green} wallet
|
48
|
+
Pay taxes for the given wallet
|
49
|
+
#{Rainbow('taxes show').green}
|
50
|
+
Show taxes status for the given wallet
|
51
|
+
#{Rainbow('taxes debt').green}
|
52
|
+
Show current debt
|
53
|
+
Available options:"
|
54
|
+
o.string '--private-key',
|
55
|
+
'The location of RSA private key (default: ~/.ssh/id_rsa)',
|
56
|
+
require: true,
|
57
|
+
default: '~/.ssh/id_rsa'
|
58
|
+
o.bool '--help', 'Print instructions'
|
59
|
+
end
|
60
|
+
command = opts.arguments[0]
|
61
|
+
case command
|
62
|
+
when 'show'
|
63
|
+
raise 'At least one wallet ID is required' unless opts.arguments[1]
|
64
|
+
opts.arguments[1..-1].each do |id|
|
65
|
+
show(@wallets.find(Id.new(id), opts))
|
66
|
+
end
|
67
|
+
when 'debt'
|
68
|
+
raise 'At least one wallet ID is required' unless opts.arguments[1]
|
69
|
+
opts.arguments[1..-1].each do |id|
|
70
|
+
debt(@wallets.find(Id.new(id), opts))
|
71
|
+
end
|
72
|
+
when 'pay'
|
73
|
+
raise 'At least one wallet ID is required' unless opts.arguments[1]
|
74
|
+
opts.arguments[1..-1].each do |id|
|
75
|
+
pay(@wallets.find(Id.new(id)), opts)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
@log.info(opts.to_s)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def pay(wallet, _)
|
83
|
+
raise 'The wallet is absent' unless wallet.exists?
|
84
|
+
tax = Tax.new(wallet)
|
85
|
+
debt = tax.debt
|
86
|
+
@log.debug("The current debt is #{debt} (#{debt.to_i} zents)")
|
87
|
+
if debt <= Tax::TRIAL
|
88
|
+
@log.debug("No need to pay taxes yet, until the debt is less than #{Tax::TRIAL} (#{Tax::TRIAL.to_i} zents)")
|
89
|
+
return
|
90
|
+
end
|
91
|
+
top = top_scores
|
92
|
+
while debt > Amount::ZERO
|
93
|
+
raise 'No acceptable remote nodes, try later' if top.empty?
|
94
|
+
best = top.shift
|
95
|
+
txn = tax.pay(Zold::Key.new(file: opts['private-key']), best)
|
96
|
+
wallet.add(txn)
|
97
|
+
debt -= txn.amount
|
98
|
+
@log.info("#{txn.amount} of taxes paid to #{txn.bnf}, #{debt} left to pay")
|
99
|
+
end
|
100
|
+
@log.info('The wallet is in good standing, all taxes paid')
|
101
|
+
end
|
102
|
+
|
103
|
+
def debt(wallet, _)
|
104
|
+
raise 'The wallet is absent' unless wallet.exists?
|
105
|
+
tax = Tax.new(wallet)
|
106
|
+
@log.info(tax.debt)
|
107
|
+
end
|
108
|
+
|
109
|
+
def show(_, _)
|
110
|
+
raise 'Not implemented yet'
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def top_scores
|
116
|
+
best = []
|
117
|
+
@remotes.all.each do |r|
|
118
|
+
uri = URI(r[:home])
|
119
|
+
name = "#{r[:host]}:#{r[:port]}"
|
120
|
+
res = Http.new(uri).get
|
121
|
+
unless res.code == '200'
|
122
|
+
@log.info("#{name}: #{Rainbow(res.code).red} \"#{res.message}\" at #{uri}")
|
123
|
+
next
|
124
|
+
end
|
125
|
+
begin
|
126
|
+
json = JSON.parse(res.body)
|
127
|
+
rescue JSON::ParserError => e
|
128
|
+
@log.info("#{name}: #{Rainbow('broken').red} JSON \"#{e.message}\": #{res.body}")
|
129
|
+
next
|
130
|
+
end
|
131
|
+
score = Score.parse_json(json['score'])
|
132
|
+
unless score.valid?
|
133
|
+
@log.info("#{name}: #{Rainbow('invalid').red} score")
|
134
|
+
next
|
135
|
+
end
|
136
|
+
if score.expired?
|
137
|
+
@log.info("#{name}: #{Rainbow('expired').red} score")
|
138
|
+
next
|
139
|
+
end
|
140
|
+
if score.strength < Score::STRENGTH
|
141
|
+
@log.info("#{name} score #{Rainbow(score.value).red} is too weak (<#{Score::STRENGTH})")
|
142
|
+
next
|
143
|
+
end
|
144
|
+
if score.value < Tax::MIN_SCORE
|
145
|
+
@log.info("#{name} score #{Rainbow(score.value).red} is too small (<#{Tax::MIN_SCORE})")
|
146
|
+
next
|
147
|
+
end
|
148
|
+
@log.info("#{score.host}:#{score.port}: #{Rainbow(score.value).green}")
|
149
|
+
best << score
|
150
|
+
end
|
151
|
+
best.sort_by(&:value).reverse
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
data/lib/zold/http.rb
CHANGED
@@ -66,9 +66,7 @@ module Zold
|
|
66
66
|
'User-Agent': "Zold #{VERSION}",
|
67
67
|
'Connection': 'close'
|
68
68
|
}
|
69
|
-
if @score.valid? && @score.value >= 3
|
70
|
-
headers[SCORE_HEADER] = score.reduced(4).to_s
|
71
|
-
end
|
69
|
+
headers[SCORE_HEADER] = score.reduced(4).to_s if @score.valid? && @score.value >= 3 && !score.expired?
|
72
70
|
headers
|
73
71
|
end
|
74
72
|
end
|
data/lib/zold/key.rb
CHANGED
@@ -34,9 +34,7 @@ module Zold
|
|
34
34
|
@body = lambda do
|
35
35
|
unless file.nil?
|
36
36
|
path = File.expand_path(file)
|
37
|
-
unless File.exist?(path)
|
38
|
-
raise "Can't find RSA key at #{file} (#{path})"
|
39
|
-
end
|
37
|
+
raise "Can't find RSA key at #{file} (#{path})" unless File.exist?(path)
|
40
38
|
return File.read(path)
|
41
39
|
end
|
42
40
|
unless text.nil?
|
data/lib/zold/node/entrance.rb
CHANGED
@@ -22,6 +22,7 @@ require 'concurrent'
|
|
22
22
|
require_relative '../log'
|
23
23
|
require_relative '../remotes'
|
24
24
|
require_relative '../copies'
|
25
|
+
require_relative '../tax'
|
25
26
|
require_relative '../commands/merge'
|
26
27
|
require_relative '../commands/fetch'
|
27
28
|
require_relative '../commands/push'
|
@@ -52,15 +53,19 @@ module Zold
|
|
52
53
|
def push_unsafe(id, body)
|
53
54
|
copies = Copies.new(File.join(@copies, id.to_s))
|
54
55
|
copies.add(body, 'remote', Remotes::PORT, 0)
|
55
|
-
|
56
|
+
Fetch.new(
|
56
57
|
remotes: @remotes, copies: copies.root, log: @log
|
57
58
|
).run([id.to_s, "--ignore-node=#{@address}"])
|
58
|
-
modified =
|
59
|
+
modified = Merge.new(
|
59
60
|
wallets: @wallets, copies: copies.root, log: @log
|
60
61
|
).run([id.to_s])
|
62
|
+
debt = Tax.new(@wallets.find(id)).debt
|
63
|
+
if debt > Tax::TRIAL
|
64
|
+
raise "Taxes are not paid, the debt is #{debt} (#{debt.to_i} zents), won't promote the wallet"
|
65
|
+
end
|
61
66
|
copies.remove('remote', Remotes::PORT)
|
62
67
|
modified.each do |m|
|
63
|
-
|
68
|
+
Push.new(
|
64
69
|
wallets: @wallets, remotes: @remotes, log: @log
|
65
70
|
).run([m.to_s])
|
66
71
|
end
|
data/lib/zold/node/farm.rb
CHANGED
@@ -30,8 +30,9 @@ module Zold
|
|
30
30
|
# Farm
|
31
31
|
class Farm
|
32
32
|
attr_reader :best
|
33
|
-
def initialize(log: Log::Quiet.new)
|
33
|
+
def initialize(invoice, log: Log::Quiet.new)
|
34
34
|
@log = log
|
35
|
+
@invoice = invoice
|
35
36
|
@scores = []
|
36
37
|
@threads = []
|
37
38
|
@best = []
|
@@ -50,7 +51,7 @@ module Zold
|
|
50
51
|
def start(host, port, strength: 8, threads: 8)
|
51
52
|
@log.debug('Zero-threads farm won\'t score anything!') if threads.zero?
|
52
53
|
@scores = Queue.new
|
53
|
-
first = Score.new(Time.now, host, port, strength: strength)
|
54
|
+
first = Score.new(Time.now, host, port, @invoice, strength: strength)
|
54
55
|
@best = [first]
|
55
56
|
@scores << first
|
56
57
|
@threads = (1..threads).map do |t|
|
@@ -64,12 +65,13 @@ module Zold
|
|
64
65
|
@best << s
|
65
66
|
after = @best.map(&:value).max
|
66
67
|
@best.reject! { |b| b.value < after }
|
67
|
-
if before != after
|
68
|
-
@log.debug("#{Thread.current.name}: best is #{@best[0]}")
|
69
|
-
end
|
68
|
+
@log.debug("#{Thread.current.name}: best is #{@best[0]}") if before != after
|
70
69
|
end
|
71
70
|
if @scores.length < 4
|
72
|
-
@scores << Score.new(
|
71
|
+
@scores << Score.new(
|
72
|
+
Time.now, host, port, @invoice,
|
73
|
+
strength: strength
|
74
|
+
)
|
73
75
|
end
|
74
76
|
@scores << s.next
|
75
77
|
end
|
data/lib/zold/node/front.rb
CHANGED
@@ -60,7 +60,6 @@ module Zold
|
|
60
60
|
if request.env[Http::SCORE_HEADER] && !settings.remotes.empty?
|
61
61
|
s = Score.parse(request.env[Http::SCORE_HEADER])
|
62
62
|
error(400, 'The score is invalid') unless s.valid?
|
63
|
-
error(400, 'The score is weak') if s.strength < Score::STRENGTH
|
64
63
|
settings.remotes.add(s.host, s.port) if s.value > 3
|
65
64
|
end
|
66
65
|
end
|
data/lib/zold/patch.rb
CHANGED
data/lib/zold/remotes.rb
CHANGED
@@ -67,6 +67,7 @@ module Zold
|
|
67
67
|
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
|
68
68
|
raise 'Port can\'t be negative' if port < 0
|
69
69
|
raise 'Port can\'t be over 65536' if port > 0xffff
|
70
|
+
raise "#{host}:#{port} alread exists" if exists?(host, port)
|
70
71
|
list = load
|
71
72
|
list << { host: host.downcase, port: port, score: 0 }
|
72
73
|
list.uniq! { |r| "#{r[:host]}:#{r[:port]}" }
|
@@ -75,6 +76,7 @@ module Zold
|
|
75
76
|
|
76
77
|
def remove(host, port = Remotes::PORT)
|
77
78
|
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
|
79
|
+
raise "#{host}:#{port} is absent" unless exists?(host, port)
|
78
80
|
list = load
|
79
81
|
list.reject! { |r| r[:host] == host.downcase && r[:port] == port }
|
80
82
|
save(list)
|
@@ -82,11 +84,13 @@ module Zold
|
|
82
84
|
|
83
85
|
def score(host, port = Remotes::PORT)
|
84
86
|
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
|
87
|
+
raise "#{host}:#{port} is absent" unless exists?(host, port)
|
85
88
|
load.find { |r| r[:host] == host.downcase && r[:port] == port }[:score]
|
86
89
|
end
|
87
90
|
|
88
91
|
def rescore(host, port, score)
|
89
92
|
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
|
93
|
+
raise "#{host}:#{port} is absent" unless exists?(host, port)
|
90
94
|
list = load
|
91
95
|
list.find do |r|
|
92
96
|
r[:host] == host.downcase && r[:port] == port
|