zold 0.16.16 → 0.16.17

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
  SHA256:
3
- metadata.gz: 6df1ca2906e963f7d5b796c1a4137dfe1acfb0257024f4959a6b388b16efbc66
4
- data.tar.gz: 7b18acb15ec0cda28d4fd6bbe180fe637ae90406986f8b4504d62c96499e379d
3
+ metadata.gz: 294ae5c8edd1bfd6c8f8567f5e19161356d656d87a04050e29c82bcf5a5303cf
4
+ data.tar.gz: 63646cc0ed79fcb7de5c1c9498db578248aa6ff3e22a840138ccede01eed468e
5
5
  SHA512:
6
- metadata.gz: 1f6b06a21a062f19147dc06fd58468864e38690c990bd3336a62a0cdf5adfa551cfa28566138a78cd46fbc593c62d1b1cfaf3c7d616df267f9101edf3550a4ba
7
- data.tar.gz: 1397f88d2069a418da2b3c33f35589aa02b16685a4b14f8f9a45929ec5f53614248a4dd73e45ef5a04c6a87f0eb32d6eb49eedb1441e4f5ae919a56e0c595351
6
+ metadata.gz: 31dc5ac7025b04c949c0ee1329bcdc773fa159322437c665b48722b3e21a2295f37ba465f5bc7df13cf5d7654a3e234bfaf999399b9c0fc9bbe42881995226d5
7
+ data.tar.gz: 7e79554604ca13438cd05c467ce6f46274a8bbbb7bbedfee84e3d28ea8989f4707d7ad924e6c896108e6a282baee7c02cee76533f75ec78353eb070f9f823383
data/README.md CHANGED
@@ -13,6 +13,7 @@
13
13
  [![Gem Version](https://badge.fury.io/rb/zold.svg)](http://badge.fury.io/rb/zold)
14
14
  [![Test Coverage](https://img.shields.io/codecov/c/github/zold-io/zold.svg)](https://codecov.io/github/zold-io/zold?branch=master)
15
15
 
16
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/zold-io/zold/master/frames)
16
17
  [![Maintainability](https://api.codeclimate.com/v1/badges/2861728929db934eb376/maintainability)](https://codeclimate.com/github/zold-io/zold/maintainability)
17
18
 
18
19
  **NOTICE**: It's an experiment and a very early draft! Please, feel free to
@@ -19,9 +19,9 @@
19
19
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
- require 'pathname'
23
- require_relative 'id'
24
- require_relative 'wallet'
22
+
23
+ require 'zache'
24
+ require_relative 'endless'
25
25
 
26
26
  # Cached collection of wallets.
27
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -32,8 +32,13 @@ module Zold
32
32
  class CachedWallets
33
33
  def initialize(wallets)
34
34
  @wallets = wallets
35
- @cache = {}
36
- @mutex = Mutex.new
35
+ @zache = Zache.new
36
+ @clean = Thread.start do
37
+ Endless.new('cached_wallets').run do
38
+ sleep 60
39
+ @zache.clean
40
+ end
41
+ end
37
42
  end
38
43
 
39
44
  def to_s
@@ -50,11 +55,7 @@ module Zold
50
55
 
51
56
  def find(id)
52
57
  @wallets.find(id) do |wallet|
53
- w = @mutex.synchronize do
54
- @cache[id] = wallet unless @cache[id]
55
- @cache[id]
56
- end
57
- yield w
58
+ yield @zache.get(id.to_s, lifetime: 5 * 60) { wallet }
58
59
  end
59
60
  end
60
61
  end
@@ -55,24 +55,23 @@ Available options:"
55
55
  end
56
56
  mine = Args.new(opts, @log).take || return
57
57
  (mine.empty? ? @wallets.all : mine.map { |i| Id.new(i) }).each do |id|
58
- clean(id, Copies.new(File.join(@copies, id), log: @log), opts)
58
+ clean(Copies.new(File.join(@copies, id), log: @log), opts)
59
59
  end
60
60
  end
61
61
 
62
- def clean(id, cps, _)
63
- Futex.new(File.join(@copies, "#{id}-clean"), log: @log).open do
64
- start = Time.now
65
- deleted = cps.clean
66
- @log.debug(
67
- "#{deleted} expired local copies removed for #{cps} \
68
- in #{Age.new(start, limit: 0.01)}, #{cps.all.count} left:\n" +
69
- cps.all.map do |c|
70
- wallet = Wallet.new(c[:path])
71
- " #{c[:name]}: #{c[:score]} #{wallet.mnemo} \
62
+ def clean(cps, _)
63
+ start = Time.now
64
+ deleted = cps.clean
65
+ list = cps.all.map do |c|
66
+ wallet = Wallet.new(c[:path])
67
+ " #{c[:name]}: #{c[:score]} #{wallet.mnemo} \
72
68
  #{Size.new(File.size(c[:path]))}/#{Age.new(File.mtime(c[:path]))}"
73
- end.join("\n")
74
- )
75
69
  end
70
+ @log.debug(
71
+ "#{deleted} expired local copies removed for #{cps} \
72
+ in #{Age.new(start, limit: 0.01)}, \
73
+ #{list.empty? ? 'nothing left' : "#{list.count} left:\n#{list.join("\n")}"}"
74
+ )
76
75
  end
77
76
  end
78
77
  end
@@ -90,12 +90,11 @@ Available options:"
90
90
  raise "No nodes out of #{nodes.value} have the wallet #{id}" if done.value.zero? && !opts['quiet-if-absent']
91
91
  @log.info("#{done.value} copies of #{id} fetched in #{Age.new(start)} with the total score of \
92
92
  #{total.value} from #{nodes.value} nodes")
93
- @log.debug("#{cps.all.count} local copies:")
94
- cps.all.each do |c|
95
- wallet = Wallet.new(c[:path])
96
- @log.debug(" #{c[:name]}: #{c[:score]} #{wallet.mnemo} \
97
- #{Size.new(File.size(c[:path]))}/#{Age.new(File.mtime(c[:path]))}")
93
+ list = cps.all.map do |c|
94
+ " ##{c[:name]}: #{c[:score]} #{Wallet.new(c[:path]).mnemo} \
95
+ #{Size.new(File.size(c[:path]))}/#{Age.new(File.mtime(c[:path]))}"
98
96
  end
97
+ @log.debug("#{cps.all.count} local copies of #{id}:\n#{list.join("\n")}")
99
98
  end
100
99
 
101
100
  def fetch_one(id, r, cps, opts)
@@ -105,7 +104,7 @@ Available options:"
105
104
  return 0
106
105
  end
107
106
  uri = "/wallet/#{id}"
108
- res = r.http(uri).get
107
+ res = r.http(uri).get(timeout: 60)
109
108
  raise "Wallet #{id} not found" if res.code == '404'
110
109
  r.assert_code(200, res)
111
110
  json = JsonPage.new(res.body, uri).to_hash
@@ -38,7 +38,7 @@ module Zold
38
38
  def run(_ = [])
39
39
  @wallets.all.each do |id|
40
40
  @wallets.find(id) do |wallet|
41
- msg = "#{id}: #{wallet.mnemo}"
41
+ msg = wallet.mnemo
42
42
  msg += " (net:#{wallet.network})" if wallet.network != Wallet::MAIN_NETWORK
43
43
  @log.info(msg)
44
44
  end
@@ -63,31 +63,30 @@ Available options:"
63
63
  start = Time.now
64
64
  modified = []
65
65
  total = 0
66
- @wallets.find(id) do |wallet|
67
- wallet.txns.select { |t| t.amount.negative? }.each do |t|
68
- total += 1
69
- if t.bnf == id
70
- @log.error("Paying itself in #{id}? #{t}")
66
+ network = @wallets.find(id, &:network)
67
+ @wallets.find(id, &:txns).select { |t| t.amount.negative? }.each do |t|
68
+ total += 1
69
+ if t.bnf == id
70
+ @log.error("Paying itself in #{id}? #{t}")
71
+ next
72
+ end
73
+ @wallets.find(t.bnf) do |target|
74
+ unless target.exists?
75
+ @log.debug("#{t.amount * -1} to #{t.bnf}: wallet is absent")
76
+ next
77
+ end
78
+ unless target.network == network
79
+ @log.error("#{t.amount * -1} to #{t.bnf}: network mismatch, '#{target.network}'!='#{network}'")
71
80
  next
72
81
  end
73
- @wallets.find(t.bnf) do |target|
74
- unless target.exists?
75
- @log.debug("#{t.amount * -1} to #{t.bnf}: wallet is absent")
76
- next
77
- end
78
- unless target.network == wallet.network
79
- @log.error("#{t.amount * -1} to #{t.bnf}: network mismatch, '#{target.network}'!='#{wallet.network}'")
80
- next
81
- end
82
- next if target.includes_positive?(t.id, id)
83
- unless target.prefix?(t.prefix)
84
- @log.error("#{t.amount * -1} to #{t.bnf}: wrong prefix")
85
- next
86
- end
87
- target.add(t.inverse(id))
88
- @log.info("#{t.amount * -1} arrived to #{t.bnf}: #{t.details}")
89
- modified << t.bnf
82
+ next if target.includes_positive?(t.id, id)
83
+ unless target.prefix?(t.prefix)
84
+ @log.error("#{t.amount * -1} to #{t.bnf}: wrong prefix")
85
+ next
90
86
  end
87
+ target.add(t.inverse(id))
88
+ @log.info("#{t.amount * -1} arrived to #{t.bnf}: #{t.details}")
89
+ modified << t.bnf
91
90
  end
92
91
  end
93
92
  modified.uniq!
@@ -92,7 +92,7 @@ total score for #{id} is #{total}")
92
92
  IO.read(wallet.path)
93
93
  end
94
94
  uri = "/wallet/#{id}"
95
- response = r.http(uri).put(content)
95
+ response = r.http(uri).put(content, timeout: 60)
96
96
  @wallets.find(id) do |wallet|
97
97
  if response.code == '304'
98
98
  @log.info("#{r}: same version of #{wallet.mnemo} there, in #{Age.new(start, limit: 0.5)}")
@@ -96,6 +96,9 @@ Available options:"
96
96
  o.bool '--skip-ping',
97
97
  'Don\'t ping back the node when adding it (not recommended)',
98
98
  default: false
99
+ o.integer '--depth',
100
+ 'The amount of update cycles to run, in order to fetch as many nodes as possible (default: 2)',
101
+ default: 2
99
102
  o.string '--network',
100
103
  "The name of the network we work in (default: #{Wallet::MAIN_NETWORK}",
101
104
  required: true,
@@ -139,7 +142,6 @@ Available options:"
139
142
  trim(opts)
140
143
  when 'update'
141
144
  update(opts)
142
- update(opts, false)
143
145
  when 'select'
144
146
  select(opts)
145
147
  else
@@ -157,8 +159,9 @@ Available options:"
157
159
  end
158
160
 
159
161
  def clean
162
+ before = @remotes.all.count
160
163
  @remotes.clean
161
- @log.debug('All remote nodes deleted')
164
+ @log.debug("All #{before} remote nodes deleted")
162
165
  end
163
166
 
164
167
  def reset
@@ -217,44 +220,53 @@ Available options:"
217
220
  all = @remotes.all
218
221
  all.each do |r|
219
222
  next if r[:errors] <= opts['tolerate']
220
- remove(r[:host], r[:port], opts)
223
+ @remotes.remove(r[:host], r[:port])
221
224
  @log.info("#{r[:host]}:#{r[:port]} removed because of #{r[:errors]} errors (over #{opts['tolerate']})")
222
225
  end
223
226
  @log.info("The list of #{all.count} remotes trimmed, #{@remotes.all.count} nodes left there")
224
227
  end
225
228
 
226
- def update(opts, deep = true)
229
+ def update(opts)
230
+ st = Time.now
227
231
  capacity = []
228
- @remotes.iterate(@log, farm: @farm) do |r|
229
- start = Time.now
230
- uri = '/remotes'
231
- res = r.http(uri).get
232
- r.assert_code(200, res)
233
- json = JsonPage.new(res.body, uri).to_hash
234
- score = Score.parse_json(json['score'])
235
- r.assert_valid_score(score)
236
- r.assert_score_ownership(score)
237
- r.assert_score_strength(score) unless opts['ignore-score-weakness']
238
- @remotes.rescore(score.host, score.port, score.value)
239
- gem = Zold::Gem.new
240
- if Semantic::Version.new(VERSION) < Semantic::Version.new(json['version']) ||
241
- Semantic::Version.new(VERSION) < Semantic::Version.new(gem.last_version)
242
- if opts['reboot']
243
- @log.info("#{r}: their version #{json['version']} is higher than mine #{VERSION}, reboot! \
244
- (use --never-reboot to avoid this from happening)")
245
- terminate
232
+ opts['depth'].times do |cycle|
233
+ @remotes.iterate(@log, farm: @farm) do |r|
234
+ start = Time.now
235
+ uri = '/remotes'
236
+ res = r.http(uri).get
237
+ r.assert_code(200, res)
238
+ json = JsonPage.new(res.body, uri).to_hash
239
+ score = Score.parse_json(json['score'])
240
+ r.assert_valid_score(score)
241
+ r.assert_score_ownership(score)
242
+ r.assert_score_strength(score) unless opts['ignore-score-weakness']
243
+ @remotes.rescore(score.host, score.port, score.value)
244
+ gem = Zold::Gem.new
245
+ if Semantic::Version.new(VERSION) < Semantic::Version.new(json['version']) ||
246
+ Semantic::Version.new(VERSION) < Semantic::Version.new(gem.last_version)
247
+ if opts['reboot']
248
+ @log.info("#{r}: their version #{json['version']} is higher than mine #{VERSION}, reboot! \
249
+ (use --never-reboot to avoid this from happening)")
250
+ terminate
251
+ end
252
+ @log.debug("#{r}: their version #{json['version']} is higher than mine #{VERSION}, \
253
+ it's recommended to reboot, but I don't do it because of --never-reboot")
246
254
  end
247
- @log.debug("#{r}: their version #{json['version']} is higher than mine #{VERSION}, \
248
- it's recommended to reboot, but I don't do it because of --never-reboot")
249
- end
250
- if deep
251
- json['all'].each do |s|
252
- add(s['host'], s['port'], opts)
253
- @log.info("#{s['host']}:#{s['port']} found at #{r} and added")
255
+ if cycle.positive?
256
+ json['all'].each do |s|
257
+ if opts['ignore-node'].include?("#{s['host']}:#{s['port']}")
258
+ @log.debug("#{s['host']}:#{s['port']}, which is found at #{r} \
259
+ won't be added since it's in the --ignore-node list")
260
+ next
261
+ end
262
+ next if @remotes.exists?(s['host'], s['port'])
263
+ @remotes.add(s['host'], s['port'])
264
+ @log.info("#{s['host']}:#{s['port']} found at #{r} and added to the list of #{@remotes.all.count}")
265
+ end
254
266
  end
267
+ capacity << { host: score.host, port: score.port, count: json['all'].count }
268
+ @log.info("#{r}: the score is #{Rainbow(score.value).green} (#{json['version']}) in #{Age.new(start)}")
255
269
  end
256
- capacity << { host: score.host, port: score.port, count: json['all'].count }
257
- @log.info("#{r}: the score is #{Rainbow(score.value).green} (#{json['version']}) in #{Age.new(start)}")
258
270
  end
259
271
  max_capacity = capacity.map { |c| c[:count] }.max || 0
260
272
  capacity.each do |c|
@@ -264,7 +276,7 @@ it's recommended to reboot, but I don't do it because of --never-reboot")
264
276
  if total.zero?
265
277
  @log.info("The list of remotes is #{Rainbow('empty').red}, run 'zold remote reset'!")
266
278
  else
267
- @log.info("There are #{total} known remotes")
279
+ @log.info("There are #{total} known remotes after update in #{Age.new(st)}")
268
280
  end
269
281
  end
270
282
 
data/lib/zold/copies.rb CHANGED
@@ -67,13 +67,13 @@ module Zold
67
67
  deleted += 1
68
68
  end
69
69
  files.each do |f|
70
- file = File.join(@dir, f)
71
- wallet = Wallet.new(file)
70
+ cp = File.join(@dir, f)
71
+ wallet = Wallet.new(cp)
72
72
  begin
73
73
  wallet.refurbish
74
- raise "Invalid protocol #{wallet.protocol} in #{file}" unless wallet.protocol == Zold::PROTOCOL
74
+ raise "Invalid protocol #{wallet.protocol} in #{cp}" unless wallet.protocol == Zold::PROTOCOL
75
75
  rescue StandardError => e
76
- FileUtils.rm_rf(file)
76
+ FileUtils.rm_rf(cp)
77
77
  @log.debug("Copy at #{f} deleted: #{Backtrace.new(e)}")
78
78
  deleted += 1
79
79
  end
data/lib/zold/http.rb CHANGED
@@ -55,10 +55,10 @@ module Zold
55
55
  PROTOCOL_HEADER = 'X-Zold-Protocol'
56
56
 
57
57
  # Read timeout in seconds
58
- READ_TIMEOUT = 32
58
+ READ_TIMEOUT = 0.4
59
59
 
60
60
  # Connect timeout in seconds
61
- CONNECT_TIMEOUT = 4
61
+ CONNECT_TIMEOUT = 0.2
62
62
 
63
63
  def initialize(uri:, score: Score::ZERO, network: 'test')
64
64
  @uri = uri.is_a?(URI) ? uri : URI(uri)
@@ -66,28 +66,28 @@ module Zold
66
66
  @network = network
67
67
  end
68
68
 
69
- def get
69
+ def get(timeout: Http::READ_TIMEOUT + Http::CONNECT_TIMEOUT)
70
70
  http = Net::HTTP.new(@uri.host, @uri.port)
71
71
  http.use_ssl = @uri.scheme == 'https'
72
72
  http.read_timeout = Http::READ_TIMEOUT
73
73
  http.open_timeout = Http::CONNECT_TIMEOUT
74
74
  path = @uri.path
75
75
  path += '?' + @uri.query if @uri.query
76
- Timeout.timeout(Http::READ_TIMEOUT + Http::CONNECT_TIMEOUT) do
76
+ Timeout.timeout(timeout) do
77
77
  http.request_get(path, headers)
78
78
  end
79
79
  rescue StandardError => e
80
80
  Error.new(e)
81
81
  end
82
82
 
83
- def put(body)
83
+ def put(body, timeout: Http::READ_TIMEOUT + Http::CONNECT_TIMEOUT)
84
84
  http = Net::HTTP.new(@uri.host, @uri.port)
85
85
  http.use_ssl = @uri.scheme == 'https'
86
86
  http.read_timeout = Http::READ_TIMEOUT
87
87
  http.open_timeout = Http::CONNECT_TIMEOUT
88
88
  path = @uri.path
89
89
  path += '?' + @uri.query if @uri.query
90
- Timeout.timeout(Http::READ_TIMEOUT + Http::CONNECT_TIMEOUT) do
90
+ Timeout.timeout(timeout) do
91
91
  http.request_put(
92
92
  path, body,
93
93
  headers.merge(
data/lib/zold/version.rb CHANGED
@@ -25,6 +25,6 @@
25
25
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Zold
28
- VERSION = '0.16.16'
28
+ VERSION = '0.16.17'
29
29
  PROTOCOL = 2
30
30
  end
@@ -22,6 +22,7 @@
22
22
 
23
23
  require 'minitest/autorun'
24
24
  require 'tmpdir'
25
+ require_relative 'test__helper'
25
26
  require_relative 'fake_home'
26
27
  require_relative '../lib/zold/key'
27
28
  require_relative '../lib/zold/id'
data/zold.gemspec CHANGED
@@ -75,7 +75,7 @@ and suggests a different architecture for digital wallet maintenance.'
75
75
  s.add_runtime_dependency 'threads', '0.3.0'
76
76
  s.add_runtime_dependency 'usagewatch_ext', '0.2.1'
77
77
  s.add_runtime_dependency 'xcop', '0.6'
78
- s.add_runtime_dependency 'zache', '0.2.0'
78
+ s.add_runtime_dependency 'zache', '0.3.0'
79
79
  s.add_runtime_dependency 'zold-score', '0.2.0'
80
80
  s.add_development_dependency 'codecov', '0.1.13'
81
81
  s.add_development_dependency 'minitest', '5.11.3'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.16
4
+ version: 0.16.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-06 00:00:00.000000000 Z
11
+ date: 2018-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -310,14 +310,14 @@ dependencies:
310
310
  requirements:
311
311
  - - '='
312
312
  - !ruby/object:Gem::Version
313
- version: 0.2.0
313
+ version: 0.3.0
314
314
  type: :runtime
315
315
  prerelease: false
316
316
  version_requirements: !ruby/object:Gem::Requirement
317
317
  requirements:
318
318
  - - '='
319
319
  - !ruby/object:Gem::Version
320
- version: 0.2.0
320
+ version: 0.3.0
321
321
  - !ruby/object:Gem::Dependency
322
322
  name: zold-score
323
323
  requirement: !ruby/object:Gem::Requirement