zold 0.11.7 → 0.11.8

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
  SHA1:
3
- metadata.gz: 12b394868e7a954a6a72411f2326339ca57cd6c2
4
- data.tar.gz: e39cfab10878262a6431c4bd2bd5a06a3939a973
3
+ metadata.gz: 73c4792176a13df605a885ea46e4cb92b0df76c6
4
+ data.tar.gz: 6ca3f32b2975db9dcf533aeb746e80e775224427
5
5
  SHA512:
6
- metadata.gz: b414866acdc3a4a099e293c5ec6358d9ad0ffbd223306469e38477736430818d84b5bc7eda44e120f69af5c9aa202e5ebae1989a8b5257f7e8a7ff8e5e701977
7
- data.tar.gz: 6edc6beb6b837bf7f9151cb3f9e652bd737c2c8362d558d0c039a6edc6806f2344bec791bda91fb3544966bd78a8508ebcd0fe7e31b85feccfaabcd2a4633097
6
+ metadata.gz: 6982d8437738d658d3d530c69525a501cc409237d2ae42c8affe8edc046636e83e06ae1cb51d0fbe8cefa0da9ae30e1a2da43a72c19037b721c631cb765fee73
7
+ data.tar.gz: 14a0e10962910847fea075ea48b26063e2baac9ed91e1b46453cee53764ebbc641b773bb0de5d8aeb854881852941bad46a15e208e379b5f266017da98d8ce33
@@ -26,6 +26,7 @@ require_relative 'args'
26
26
  require_relative '../log'
27
27
  require_relative '../patch'
28
28
  require_relative '../wallet'
29
+ require_relative '../atomic_file'
29
30
 
30
31
  # DIFF command.
31
32
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -69,7 +70,7 @@ Available options:"
69
70
  cps[1..-1].each do |c|
70
71
  patch.join(Wallet.new(c[:path]))
71
72
  end
72
- before = File.read(wallet.path)
73
+ before = AtomicFile.new(wallet.path).read
73
74
  after = ''
74
75
  Tempfile.open do |f|
75
76
  patch.save(f, overwrite: true)
@@ -98,9 +98,8 @@ module Zold
98
98
  Front.set(:copies, copies)
99
99
  address = "#{opts[:host]}:#{opts[:port]}".downcase
100
100
  Front.set(:address, address)
101
- Front.set(
102
- :entrance, Entrance.new(wallets, remotes, copies, address, log: @log)
103
- )
101
+ entrance = Entrance.new(wallets, remotes, copies, address, log: @log)
102
+ Front.set(:entrance, entrance)
104
103
  Front.set(:root, Dir.pwd)
105
104
  Front.set(:port, opts['bind-port'])
106
105
  Front.set(:reboot, !opts['never-reboot'])
@@ -26,6 +26,7 @@ require_relative 'args'
26
26
  require_relative '../log'
27
27
  require_relative '../id'
28
28
  require_relative '../http'
29
+ require_relative '../atomic_file'
29
30
 
30
31
  # PUSH command.
31
32
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -77,7 +78,7 @@ Available options:"
77
78
  return 0
78
79
  end
79
80
  start = Time.now
80
- content = File.read(wallet.path)
81
+ content = AtomicFile.new(wallet.path).read
81
82
  response = r.http("/wallet/#{wallet.id}#{opts['sync'] ? '?sync=true' : ''}").put(content)
82
83
  if response.code == '304'
83
84
  @log.info("#{r}: same version of #{wallet.id} there")
@@ -141,7 +141,7 @@ Available options:"
141
141
 
142
142
  def trim(opts)
143
143
  @remotes.all.each do |r|
144
- remove(r[:host], r[:port], opts) if r[:errors] > 20
144
+ remove(r[:host], r[:port], opts) if r[:errors] > Remotes::TOLERANCE
145
145
  end
146
146
  @log.info("The list of remotes trimmed, #{@remotes.all.count} nodes left there")
147
147
  end
data/lib/zold/copies.rb CHANGED
@@ -66,7 +66,7 @@ module Zold
66
66
  list = load
67
67
  target = list.find do |s|
68
68
  f = File.join(@dir, s[:name])
69
- File.exist?(f) && File.read(f) == content
69
+ File.exist?(f) && AtomicFile.new(f).read == content
70
70
  end
71
71
  if target.nil?
72
72
  max = Dir.new(@dir)
data/lib/zold/key.rb CHANGED
@@ -22,6 +22,7 @@ gem 'openssl'
22
22
  require 'openssl'
23
23
  require 'base64'
24
24
  require 'tempfile'
25
+ require_relative 'atomic_file'
25
26
 
26
27
  # The RSA key (either private or public).
27
28
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -35,7 +36,7 @@ module Zold
35
36
  unless file.nil?
36
37
  path = File.expand_path(file)
37
38
  raise "Can't find RSA key at #{file} (#{path})" unless File.exist?(path)
38
- return File.read(path)
39
+ return AtomicFile.new(path).read
39
40
  end
40
41
  unless text.nil?
41
42
  return text if text.start_with?('-----')
@@ -44,7 +44,29 @@ module Zold
44
44
  @address = address
45
45
  @log = log
46
46
  @semaphores = Concurrent::Map.new
47
+ @push_mutex = Mutex.new
48
+ @modified = Set.new
47
49
  @pool = Concurrent::FixedThreadPool.new(16, max_queue: 64, fallback_policy: :abort)
50
+ @pushes = Concurrent::FixedThreadPool.new(1, max_queue: 64, fallback_policy: :abort)
51
+ end
52
+
53
+ def to_json
54
+ {
55
+ 'semaphores': @semaphores.size,
56
+ 'modified': @modified.length,
57
+ 'pool': {
58
+ 'completed_task_count': @pool.completed_task_count,
59
+ 'largest_length': @pool.largest_length,
60
+ 'length': @pool.length,
61
+ 'queue_length': @pool.queue_length
62
+ },
63
+ 'pushes': {
64
+ 'completed_task_count': @pushes.completed_task_count,
65
+ 'largest_length': @pushes.largest_length,
66
+ 'length': @pushes.length,
67
+ 'queue_length': @pushes.queue_length
68
+ }
69
+ }
48
70
  end
49
71
 
50
72
  def push(id, body, sync: true)
@@ -75,6 +97,9 @@ module Zold
75
97
  end
76
98
  end
77
99
 
100
+ private
101
+
102
+ # Returns a list of modifed wallets (as Zold::Id)
78
103
  def push_sync(id, body)
79
104
  @semaphores.put_if_absent(id, Mutex.new)
80
105
  @semaphores.get(id).synchronize do
@@ -85,6 +110,7 @@ module Zold
85
110
  end
86
111
  end
87
112
 
113
+ # Returns a list of modifed wallets (as Zold::Id)
88
114
  def push_unsafe(id, body)
89
115
  copies = Copies.new(File.join(@copies, id.to_s))
90
116
  copies.add(body, '0.0.0.0', Remotes::PORT, 0)
@@ -96,10 +122,19 @@ module Zold
96
122
  ).run(['merge', id.to_s])
97
123
  Clean.new(wallets: @wallets, copies: copies.root, log: @log).run(['clean', id.to_s])
98
124
  copies.remove('remote', Remotes::PORT)
99
- Push.new(
100
- wallets: @wallets, remotes: @remotes, log: @log
101
- ).run(['push', "--ignore-node=#{@address}"] + modified.map(&:to_s))
125
+ @push_mutex.synchronize { @modified += modified }
126
+ @pushes.post { push_one } if @pushes.length < 2
102
127
  modified
103
128
  end
129
+
130
+ def push_one
131
+ @push_mutex.synchronize do
132
+ id = @modified.to_a[0]
133
+ return if id.nil?
134
+ Push.new(
135
+ wallets: @wallets, remotes: @remotes, log: @log
136
+ ).run(['push', "--ignore-node=#{@address}"] + [id.to_s])
137
+ end
138
+ end
104
139
  end
105
140
  end
@@ -111,7 +111,8 @@ module Zold
111
111
 
112
112
  def history(max = 16)
113
113
  if File.exist?(@cache)
114
- File.readlines(@cache)
114
+ AtomicFile.new(@cache).read
115
+ .split(/\n/)
115
116
  .map { |t| Score.parse(t) }
116
117
  .reject(&:expired?)
117
118
  .sort_by(&:value)
@@ -29,6 +29,7 @@ require_relative '../wallet'
29
29
  require_relative '../log'
30
30
  require_relative '../id'
31
31
  require_relative '../http'
32
+ require_relative '../atomic_file'
32
33
 
33
34
  # The web front of the node.
34
35
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -40,7 +41,7 @@ module Zold
40
41
  configure do
41
42
  set :bind, '0.0.0.0'
42
43
  set :suppress_messages, true
43
- set :dump_errors, true
44
+ set :dump_errors, false
44
45
  set :start, Time.now
45
46
  set :lock, false
46
47
  set :show_exceptions, false
@@ -123,6 +124,7 @@ module Zold
123
124
  wallets: settings.wallets.all.count,
124
125
  remotes: settings.remotes.all.count,
125
126
  farm: settings.farm.to_json,
127
+ entrance: settings.entrance.to_json,
126
128
  date: `date --iso-8601=seconds -u`.strip,
127
129
  hours_alive: ((Time.now - settings.start) / (60 * 60)).round(2),
128
130
  home: 'https://www.zold.io'
@@ -137,7 +139,7 @@ module Zold
137
139
  {
138
140
  version: VERSION,
139
141
  score: score.to_h,
140
- body: File.read(wallet.path)
142
+ body: AtomicFile.new(wallet.path).read
141
143
  }.to_json
142
144
  end
143
145
 
@@ -146,7 +148,7 @@ module Zold
146
148
  wallet = settings.wallets.find(id)
147
149
  request.body.rewind
148
150
  body = request.body.read
149
- if wallet.exists? && File.read(wallet.path) == body
151
+ if wallet.exists? && AtomicFile.new(wallet.path).read == body
150
152
  status 304
151
153
  return
152
154
  end
data/lib/zold/patch.rb CHANGED
@@ -20,6 +20,7 @@
20
20
 
21
21
  require_relative 'wallet'
22
22
  require_relative 'signature'
23
+ require_relative 'atomic_file'
23
24
 
24
25
  # Patch.
25
26
  #
@@ -54,11 +55,11 @@ module Zold
54
55
  # Returns TRUE if the file was actually modified
55
56
  def save(file, overwrite: false)
56
57
  before = ''
57
- before = File.read(file) if File.exist?(file)
58
+ before = AtomicFile.new(file).read if File.exist?(file)
58
59
  wallet = Wallet.new(file)
59
60
  wallet.init(@id, @key, overwrite: overwrite, network: @network)
60
61
  @txns.each { |t| wallet.add(t) }
61
- after = File.read(file)
62
+ after = AtomicFile.new(file).read
62
63
  before != after
63
64
  end
64
65
  end
data/lib/zold/remotes.rb CHANGED
@@ -34,6 +34,9 @@ module Zold
34
34
  # The default TCP port all nodes are supposed to use.
35
35
  PORT = 4096
36
36
 
37
+ # At what amount of errors we delete the remote automatically
38
+ TOLERANCE = 50
39
+
37
40
  # Empty, for standalone mode
38
41
  class Empty
39
42
  def all
@@ -138,12 +141,21 @@ module Zold
138
141
  yield Remotes::Remote.new(r[:host], r[:port], score, log: log)
139
142
  rescue StandardError => e
140
143
  error(r[:host], r[:port])
141
- log.info("#{Rainbow("#{r[:host]}:#{r[:port]}").red}: #{e.message}")
144
+ errors = errors(r[:host], r[:port])
145
+ log.info("#{Rainbow("#{r[:host]}:#{r[:port]}").red}: #{e.message}; errors=#{errors}")
142
146
  log.debug(e.backtrace[0..5].join("\n\t"))
147
+ remove(r[:host], r[:port]) if errors > Remotes::TOLERANCE
143
148
  end
144
149
  end
145
150
  end
146
151
 
152
+ def errors(host, port = Remotes::PORT)
153
+ raise 'Port has to be of type Integer' unless port.is_a?(Integer)
154
+ list = load
155
+ raise "#{host}:#{port} is absent among #{list.count} remotes" unless exists?(host, port)
156
+ list.find { |r| r[:host] == host.downcase && r[:port] == port }[:errors]
157
+ end
158
+
147
159
  def error(host, port = Remotes::PORT)
148
160
  raise 'Port has to be of type Integer' unless port.is_a?(Integer)
149
161
  list = load
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.11.7'.freeze
26
+ VERSION = '0.11.8'.freeze
27
27
  end
data/lib/zold/wallet.rb CHANGED
@@ -161,7 +161,7 @@ module Zold
161
161
 
162
162
  def lines
163
163
  raise "File '#{@file}' is absent" unless File.exist?(@file)
164
- File.readlines(@file)
164
+ AtomicFile.new(@file).read.split(/\n/)
165
165
  end
166
166
  end
167
167
  end
@@ -34,6 +34,14 @@ require_relative '../../lib/zold/commands/pay'
34
34
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
35
35
  # License:: MIT
36
36
  class TestEntrance < Minitest::Test
37
+ def test_renders_json
38
+ FakeHome.new.run do |home|
39
+ wallet = home.create_wallet(Zold::Id.new)
40
+ entrance = Zold::Entrance.new(home.wallets, home.remotes, home.copies(wallet).root, 'x', log: test_log)
41
+ assert_equal(0, entrance.to_json[:modified])
42
+ end
43
+ end
44
+
37
45
  def test_pushes_wallet
38
46
  sid = Zold::Id.new
39
47
  tid = Zold::Id.new
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.11.7
4
+ version: 0.11.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko