zold 0.16.16 → 0.16.17

Sign up to get free protection for your applications and to get access to all the features.
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