zold 0.9.10 → 0.9.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eb875c3b804c4d045fc34d2e00ad415d2d29a370
4
- data.tar.gz: 9562b642f01203ff7560dcd43d72c7edab08cb2d
3
+ metadata.gz: 76a4eedb7d10def207298c7f125a6c9fbe392bec
4
+ data.tar.gz: 04f8e073cea64e11e7989d1c943a629295e45425
5
5
  SHA512:
6
- metadata.gz: ac0fc271a65b8fd7284398dba3e67ab515f7d06942e12a10d27e654433907191ab1abeabb9767384296bb5259ff3387cb4ecf3a59b917d6f9c6b1a09a4ea698b
7
- data.tar.gz: 5be7344fecc4fc4d9376b16c45c43a5a25ca6a451386b4ecca734a73358c3257c91e8e5a1a98fd73323c683c4c81be854b8497548ea0529ae4c81e6e9ed24edc
6
+ metadata.gz: b70bdc247fa5230a8a6709578d603f1e7a87f8b3a758abc663dc5cf603136f49f8049a1df90fb709c728cf8a9d8b4ca9fcedbc9b0e15ee209ec2556cffe996be
7
+ data.tar.gz: 9dbfe9ece397a9ef7a6ee65e771ac560fe4aacc2ceb1ac77d291bb53b0d263ddc4349ae45e00ecc8c47564dab15f304a639e6440828325a7cded1a2e7de4db52
@@ -64,50 +64,28 @@ Available options:"
64
64
 
65
65
  def fetch(id, cps, opts)
66
66
  total = 0
67
- @remotes.all.each do |r|
68
- done = fetch_one(id, r, cps, opts)
69
- if done
70
- total += 1
71
- else
72
- @remotes.error(r[:host], r[:port])
73
- end
67
+ @remotes.iterate(@log) do |r|
68
+ fetch_one(id, r, cps, opts)
69
+ total += 1
74
70
  end
75
71
  @log.debug("#{total} copies of #{id} fetched, there are #{cps.all.count} available locally")
76
72
  end
77
73
 
78
74
  def fetch_one(id, r, cps, opts)
79
- address = "#{r[:host]}:#{r[:port]}".downcase
80
- if opts['ignore-node'].include?(address)
81
- @log.info("#{address} ignored because of --ignore-node")
82
- return false
83
- end
84
- uri = URI("#{r[:home]}wallet/#{id}")
85
- res = Http.new(uri).get
86
- if res.code == '404'
87
- @log.info("#{address} wallet #{id} #{Rainbow('not found').red}")
88
- return false
89
- end
90
- unless res.code == '200'
91
- @log.error("#{address} #{Rainbow(res.code).red}/#{res.message} at #{uri}")
75
+ if opts['ignore-node'].include?(r.to_s)
76
+ @log.info("#{r} ignored because of --ignore-node")
92
77
  return false
93
78
  end
79
+ res = r.http("/wallet/#{id}").get
80
+ raise "Wallet #{id} not found" if res.code == '404'
81
+ raise "#{res.code} \"#{res.message}\"" unless res.code == '200'
94
82
  json = JSON.parse(res.body)
95
83
  score = Score.parse_json(json['score'])
96
- unless score.valid?
97
- @log.error("#{address}: invalid score: #{score}")
98
- return false
99
- end
100
- if score.expired?
101
- @log.error("#{address}: score expired: #{score}")
102
- return false
103
- end
104
- if score.strength < Score::STRENGTH && !opts['ignore-score-weakness']
105
- @log.error("#{address} score is too weak (#{score.strength}<#{Score::STRENGTH}): #{score}")
106
- return false
107
- end
84
+ raise "Invalid score #{score}" unless score.valid?
85
+ raise "Score expired #{score}" if score.expired?
86
+ raise "Score is too weak #{score.strength}" if score.strength < Score::STRENGTH && !opts['ignore-score-weakness']
108
87
  cps.add(json['body'], score.host, score.port, score.value)
109
- @log.info("#{address} #{json['body'].length}b/#{Rainbow(score.value).green} (#{json['version']})")
110
- true
88
+ @log.info("#{r} #{json['body'].length}b/#{Rainbow(score.value).green} (#{json['version']})")
111
89
  end
112
90
  end
113
91
  end
@@ -112,6 +112,9 @@ module Zold
112
112
  threads: opts[:threads], strength: opts[:strength]
113
113
  )
114
114
  Zold::Front.set(:farm, farm)
115
+ Thread.start do
116
+ Zold::Remote.new(remotes: remotes, farm: farm, log: @log).run(%w[remote update]) unless best.nil?
117
+ end
115
118
  @log.debug('Starting up the web front...')
116
119
  begin
117
120
  Zold::Front.run!
@@ -49,44 +49,27 @@ Available options:"
49
49
  mine = Args.new(opts, @log).take || return
50
50
  mine = @wallets.all if mine.empty?
51
51
  mine.each do |id|
52
- push(@wallets.find(Id.new(id)), opts)
52
+ wallet = @wallets.find(Id.new(id))
53
+ raise "The wallet #{id} is absent" unless wallet.exists?
54
+ push(wallet, opts)
53
55
  end
54
56
  end
55
57
 
56
58
  def push(wallet, _)
57
- raise 'The wallet is absent' unless wallet.exists?
58
59
  total = 0
59
- @remotes.all.each do |r|
60
- uri = URI("#{r[:home]}wallet/#{wallet.id}")
61
- response = Http.new(uri).put(File.read(wallet.path))
60
+ @remotes.iterate(@log) do |r|
61
+ response = r.http("/wallet/#{wallet.id}").put(File.read(wallet.path))
62
62
  if response.code == '304'
63
- @log.info("#{uri}: same version there")
64
- next
65
- end
66
- unless response.code == '200'
67
- @remotes.error(r[:host], r[:port])
68
- @log.error("#{uri} failed as #{response.code}/#{response.message}")
69
- @log.debug(response.body) unless response.body.empty?
63
+ @log.info("#{r}: same version there")
70
64
  next
71
65
  end
66
+ raise "#{response.code} \"#{response.message}\" at #{response.body}" unless response.code == '200'
72
67
  json = JSON.parse(response.body)['score']
73
68
  score = Score.parse_json(json)
74
- unless score.valid?
75
- @remotes.error(r[:host], r[:port])
76
- @log.error("#{uri} invalid score: #{score}")
77
- next
78
- end
79
- if score.expired?
80
- @remotes.error(r[:host], r[:port])
81
- @log.error("#{uri} expired score: #{score}")
82
- next
83
- end
84
- if score.strength < Score::STRENGTH
85
- @remotes.error(r[:host], r[:port])
86
- @log.error("#{uri} score is too weak")
87
- next
88
- end
89
- @log.info("#{uri} accepted: #{Rainbow(score.value).green}")
69
+ raise "Invalid score #{score}" unless score.valid?
70
+ raise "Expired score #{score}" if score.expired?
71
+ raise "Score is too weak #{score}" if score.strength < Score::STRENGTH
72
+ @log.info("#{r} accepted: #{Rainbow(score.value).green}")
90
73
  total += score.value
91
74
  end
92
75
  @log.info("Total score is #{total}")
@@ -115,42 +115,15 @@ Available options:"
115
115
 
116
116
  def update(opts, deep = true)
117
117
  capacity = []
118
- @remotes.all.each do |r|
119
- uri = URI("#{r[:home]}remotes")
120
- res = Http.new(uri).get
121
- unless res.code == '200'
122
- @remotes.error(r[:host], r[:port])
123
- @log.info("#{Rainbow(r[:host]).red} #{res.code} \"#{res.message}\" #{uri}")
124
- next
125
- end
126
- begin
127
- json = JSON.parse(res.body)
128
- rescue JSON::ParserError => e
129
- error(r[:host], r[:port])
130
- @log.info("#{Rainbow(r[:host]).red} \"#{e.message}\": #{res.body}")
131
- next
132
- end
118
+ @remotes.iterate(@log) do |r|
119
+ res = r.http('/remotes').get
120
+ raise "#{res.code} \"#{res.message}\"" unless res.code == '200'
121
+ json = JSON.parse(res.body)
133
122
  score = Score.parse_json(json['score'])
134
- unless score.valid?
135
- error(r[:host], r[:port])
136
- @log.info("#{Rainbow(r[:host]).red} invalid score: #{score}")
137
- next
138
- end
139
- if score.expired?
140
- error(r[:host], r[:port])
141
- @log.info("#{Rainbow(r[:host]).red} expired score: #{score}")
142
- next
143
- end
144
- if score.strength < Score::STRENGTH && !opts['ignore-score-weakness']
145
- error(r[:host], r[:port])
146
- @log.info("#{Rainbow(r[:host]).red} score too weak: #{score.strength}")
147
- next
148
- end
149
- if r[:host] != score.host || r[:port] != score.port
150
- @remotes.error(r[:host], r[:port])
151
- @remotes.add(score.host, score.port)
152
- @log.info("#{r[:host]}:#{r[:port]} renamed to #{score.host}:#{score.port}")
153
- end
123
+ raise "Invalid score #{score}" unless score.valid?
124
+ raise "Expired score #{score}" if score.expired?
125
+ raise "Score too weak: #{score.strength}" if score.strength < Score::STRENGTH && !opts['ignore-score-weakness']
126
+ raise "Masqueraded as #{score.host}:#{score.port}" if r.host != score.host || r.port != score.port
154
127
  @remotes.rescore(score.host, score.port, score.value)
155
128
  if deep
156
129
  json['all'].each do |s|
@@ -158,7 +131,7 @@ Available options:"
158
131
  end
159
132
  end
160
133
  capacity << { host: score.host, port: score.port, count: json['all'].count }
161
- @log.info("#{r[:host]}:#{r[:port]}: #{Rainbow(score.value).green} (#{json['version']})")
134
+ @log.info("#{r}: #{Rainbow(score.value).green} (#{json['version']})")
162
135
  end
163
136
  max_capacity = capacity.map { |c| c[:count] }.max || 0
164
137
  capacity.each do |c|
@@ -117,37 +117,15 @@ Available options:"
117
117
 
118
118
  def top_scores
119
119
  best = []
120
- @remotes.all.each do |r|
121
- uri = URI(r[:home])
122
- name = "#{r[:host]}:#{r[:port]}"
123
- res = Http.new(uri).get
124
- unless res.code == '200'
125
- @log.info("#{name}: #{Rainbow(res.code).red} \"#{res.message}\" at #{uri}")
126
- next
127
- end
128
- begin
129
- json = JSON.parse(res.body)
130
- rescue JSON::ParserError => e
131
- @log.info("#{name}: #{Rainbow('broken').red} JSON \"#{e.message}\": #{res.body}")
132
- next
133
- end
120
+ @remotes.iterate(@log) do |r|
121
+ res = r.http.get
122
+ raise "#{res.code} \"#{res.message}\" at #{res.body}" unless res.code == '200'
123
+ json = JSON.parse(res.body)
134
124
  score = Score.parse_json(json['score'])
135
- unless score.valid?
136
- @log.info("#{name}: #{Rainbow('invalid').red} score")
137
- next
138
- end
139
- if score.expired?
140
- @log.info("#{name}: #{Rainbow('expired').red} score")
141
- next
142
- end
143
- if score.strength < Score::STRENGTH
144
- @log.info("#{name} score #{Rainbow(score.value).red} is too weak (<#{Score::STRENGTH})")
145
- next
146
- end
147
- if score.value < Tax::EXACT_SCORE
148
- @log.info("#{name} score #{Rainbow(score.value).red} is too small (<#{Tax::EXACT_SCORE})")
149
- next
150
- end
125
+ raise "Invalid score #{score}" unless score.valid?
126
+ raise "Expired score #{score}" if score.expired?
127
+ raise "Score is too weak (<#{Score::STRENGTH}) #{score}" if score.strength < Score::STRENGTH
128
+ raise "Score is too small (<#{Tax::EXACT_SCORE})" if score.value < Tax::EXACT_SCORE
151
129
  @log.info("#{score.host}:#{score.port}: #{Rainbow(score.value).green}")
152
130
  best << score
153
131
  end
data/lib/zold/http.rb CHANGED
@@ -75,7 +75,7 @@ module Zold
75
75
  'Connection': 'close'
76
76
  }
77
77
  headers[Http::VERSION_HEADER] = VERSION
78
- headers[Http::SCORE_HEADER] = score.reduced(4).to_s if @score.valid? && @score.value >= 3 && !score.expired?
78
+ headers[Http::SCORE_HEADER] = @score.reduced(4).to_s if @score.valid? && @score.value >= 3 && !score.expired?
79
79
  headers
80
80
  end
81
81
  end
@@ -29,6 +29,13 @@ require_relative '../score'
29
29
  module Zold
30
30
  # Farm
31
31
  class Farm
32
+ # Empty farm
33
+ class Empty
34
+ def best
35
+ []
36
+ end
37
+ end
38
+
32
39
  attr_reader :best
33
40
  def initialize(invoice, log: Log::Quiet.new)
34
41
  @log = log
data/lib/zold/remotes.rb CHANGED
@@ -21,6 +21,7 @@
21
21
  require 'csv'
22
22
  require 'uri'
23
23
  require 'fileutils'
24
+ require_relative 'node/farm'
24
25
 
25
26
  # The list of remotes.
26
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -29,6 +30,7 @@ require 'fileutils'
29
30
  module Zold
30
31
  # All remotes
31
32
  class Remotes
33
+ # The default TCP port all nodes are supposed to use.
32
34
  PORT = 4096
33
35
 
34
36
  # Empty, for standalone mode
@@ -36,10 +38,34 @@ module Zold
36
38
  def all
37
39
  []
38
40
  end
41
+
42
+ def iterate(_)
43
+ # Nothing to do here
44
+ end
45
+ end
46
+
47
+ # One remote.
48
+ class Remote
49
+ attr_reader :host, :port
50
+ def initialize(host, port, score)
51
+ @host = host
52
+ @port = port
53
+ @score = score
54
+ end
55
+
56
+ def http(path = '/')
57
+ uri = URI("http://#{@host}:#{@port}#{path}")
58
+ Http.new(uri, @score)
59
+ end
60
+
61
+ def to_s
62
+ "#{@host}:#{@port}"
63
+ end
39
64
  end
40
65
 
41
- def initialize(file)
66
+ def initialize(file, farm = Farm::Empty.new)
42
67
  @file = file
68
+ @farm = farm
43
69
  end
44
70
 
45
71
  def all
@@ -89,16 +115,19 @@ module Zold
89
115
  save(list)
90
116
  end
91
117
 
92
- def score(host, port = Remotes::PORT)
93
- raise 'Port has to be of type Integer' unless port.is_a?(Integer)
94
- raise "#{host}:#{port} is absent" unless exists?(host, port)
95
- load.find { |r| r[:host] == host.downcase && r[:port] == port }[:score]
96
- end
97
-
98
- def errors(host, port = Remotes::PORT)
99
- raise 'Port has to be of type Integer' unless port.is_a?(Integer)
100
- raise "#{host}:#{port} is absent" unless exists?(host, port)
101
- load.find { |r| r[:host] == host.downcase && r[:port] == port }[:errors]
118
+ def iterate(log)
119
+ best = @farm.best[0]
120
+ require_relative 'score'
121
+ score = best.nil? ? Score::ZERO : best
122
+ all.each do |r|
123
+ begin
124
+ yield Remotes::Remote.new(r[:host], r[:port], score)
125
+ rescue StandardError => e
126
+ error(r[:host], r[:port])
127
+ log.info("#{Rainbow("#{r[:host]}:#{r[:port]}").red}: #{e.message}")
128
+ log.debug(e.backtrace[0..5].join("\n\t"))
129
+ end
130
+ end
102
131
  end
103
132
 
104
133
  def error(host, port = Remotes::PORT)
data/lib/zold/score.rb CHANGED
@@ -48,10 +48,8 @@ module Zold
48
48
  @strength = strength
49
49
  end
50
50
 
51
- ZERO = Score.new(
52
- Time.now, 'localhost',
53
- Remotes::PORT, 'NOPREFIX@ffffffffffffffff'
54
- )
51
+ # The default no-value score.
52
+ ZERO = Score.new(Time.now, 'localhost', 80, 'NOPREFIX@ffffffffffffffff')
55
53
 
56
54
  def self.parse_json(json)
57
55
  raise "Time in JSON is broken: #{json}" unless json['time'] =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/
data/lib/zold/version.rb CHANGED
@@ -23,5 +23,5 @@
23
23
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
24
24
  # License:: MIT
25
25
  module Zold
26
- VERSION = '0.9.10'.freeze
26
+ VERSION = '0.9.11'.freeze
27
27
  end
data/test/test_remotes.rb CHANGED
@@ -65,7 +65,9 @@ class TestRemotes < Minitest::Test
65
65
  remotes = Zold::Remotes.new(file)
66
66
  remotes.add('127.0.0.1', 80)
67
67
  remotes.rescore('127.0.0.1', 80, 15)
68
- assert_equal(remotes.score('127.0.0.1', 80), 15)
68
+ remotes.all.each do |r|
69
+ assert_equal(15, r[:score])
70
+ end
69
71
  end
70
72
  end
71
73
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.10
4
+ version: 0.9.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko