zold 0.16.17 → 0.16.18

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: 294ae5c8edd1bfd6c8f8567f5e19161356d656d87a04050e29c82bcf5a5303cf
4
- data.tar.gz: 63646cc0ed79fcb7de5c1c9498db578248aa6ff3e22a840138ccede01eed468e
3
+ metadata.gz: de86dbcab88573c76088a862afd47563bebee0d62df73b695bdae79dc2e47778
4
+ data.tar.gz: 76f9b1a004ff1ef24acf833626b128bff9ac7663e16bc10c7a476e4667b349fc
5
5
  SHA512:
6
- metadata.gz: 31dc5ac7025b04c949c0ee1329bcdc773fa159322437c665b48722b3e21a2295f37ba465f5bc7df13cf5d7654a3e234bfaf999399b9c0fc9bbe42881995226d5
7
- data.tar.gz: 7e79554604ca13438cd05c467ce6f46274a8bbbb7bbedfee84e3d28ea8989f4707d7ad924e6c896108e6a282baee7c02cee76533f75ec78353eb070f9f823383
6
+ metadata.gz: 68cf2ad85d6eeaf93cb9d32d1e84f8c25c96f70826ca4dc9e68140e89c32bd9d9e584fcc94e9ccc7fbfcaec0e1e9b2c3c2a51313f717af97da577bf517ae7ade
7
+ data.tar.gz: 2c45d5fee9bf53f9e2e09e9e961c3004755574fd23a5840c93767b15beba9b3c236464fd299b70b39b846a3126b4ce66792bb29f608158f5af69fbc94ae3bf9c
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 = 0.4
58
+ READ_TIMEOUT = 1
59
59
 
60
60
  # Connect timeout in seconds
61
- CONNECT_TIMEOUT = 0.2
61
+ CONNECT_TIMEOUT = 0.4
62
62
 
63
63
  def initialize(uri:, score: Score::ZERO, network: 'test')
64
64
  @uri = uri.is_a?(URI) ? uri : URI(uri)
@@ -69,11 +69,11 @@ module Zold
69
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
- http.read_timeout = Http::READ_TIMEOUT
72
+ http.read_timeout = 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(timeout) do
76
+ Timeout.timeout(timeout + Http::CONNECT_TIMEOUT) do
77
77
  http.request_get(path, headers)
78
78
  end
79
79
  rescue StandardError => e
@@ -83,11 +83,11 @@ module Zold
83
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
- http.read_timeout = Http::READ_TIMEOUT
86
+ http.read_timeout = 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(timeout) do
90
+ Timeout.timeout(timeout + Http::CONNECT_TIMEOUT) do
91
91
  http.request_put(
92
92
  path, body,
93
93
  headers.merge(
data/lib/zold/id.rb CHANGED
@@ -31,6 +31,7 @@ module Zold
31
31
  if id.nil?
32
32
  @id = rand(2**32..2**64 - 1)
33
33
  else
34
+ raise "Invalid wallet ID type: #{id.class.name}" unless id.is_a?(String)
34
35
  raise "Invalid wallet ID: #{id}" unless id =~ /^[0-9a-fA-F]{16}$/
35
36
  @id = Integer("0x#{id}", 16)
36
37
  end
@@ -38,28 +38,33 @@ module Zold
38
38
  class AsyncEntrance
39
39
  def initialize(entrance, dir, log: Log::Quiet.new, threads: [Concurrent.processor_count, 4].max)
40
40
  @entrance = entrance
41
- @dir = dir
41
+ @dir = File.expand_path(dir)
42
42
  @log = log
43
43
  @total = threads
44
- @mutex = Mutex.new
44
+ @queue = Queue.new
45
45
  end
46
46
 
47
47
  def to_json
48
48
  @entrance.to_json.merge(
49
- 'queue': queue.count,
49
+ 'queue': @queue.size,
50
50
  'threads': @threads.count
51
51
  )
52
52
  end
53
53
 
54
54
  def start
55
55
  raise 'Block must be given to start()' unless block_given?
56
+ FileUtils.mkdir_p(@dir)
57
+ DirItems.new(@dir).fetch.select { |f| f =~ /^[0-9a-f]{16}-/ }.each do |f|
58
+ file = File.join(@dir, f)
59
+ id = f.split('-')[0]
60
+ @queue << { id: Id.new(id), file: file }
61
+ end
62
+ @log.info("#{@queue.size} wallets pre-loaded into async_entrace from #{@dir}") unless @queue.size.zero?
56
63
  @entrance.start do
57
- FileUtils.mkdir_p(@dir)
58
64
  @threads = (0..@total - 1).map do |i|
59
65
  Thread.start do
60
66
  Endless.new("async-e##{i}", log: @log).run do
61
67
  take
62
- sleep(1)
63
68
  end
64
69
  end
65
70
  end
@@ -73,14 +78,15 @@ module Zold
73
78
 
74
79
  # Always returns an array with a single ID of the pushed wallet
75
80
  def push(id, body)
76
- raise "Queue is too long (#{queue.count} wallets), try again later" if queue.count > 256
81
+ raise "Queue is too long (#{@queue.size} wallets), try again later" if @queue.size > 256
77
82
  start = Time.now
78
83
  loop do
79
84
  uuid = SecureRandom.uuid
80
85
  file = File.join(@dir, "#{id}-#{uuid}")
81
86
  next if File.exist?(file)
82
87
  IO.write(file, body)
83
- @log.debug("Added #{id}/#{Size.new(body.length)} to the queue at pos.#{queue.count} \
88
+ @queue << { id: id, file: file }
89
+ @log.debug("Added #{id}/#{Size.new(body.length)} to the queue at pos.#{@queue.size} \
84
90
  in #{Age.new(start, limit: 0.05)}: #{uuid}")
85
91
  break
86
92
  end
@@ -91,23 +97,13 @@ in #{Age.new(start, limit: 0.05)}: #{uuid}")
91
97
 
92
98
  def take
93
99
  start = Time.now
94
- id, body = @mutex.synchronize do
95
- opts = queue
96
- return if opts.empty?
97
- file = File.join(@dir, opts[0])
98
- id = opts[0].split('-')[0]
99
- Thread.current.thread_variable_set(:wallet, id)
100
- body = IO.read(file)
101
- FileUtils.rm_f(file)
102
- [id, body]
103
- end
104
- @entrance.push(Id.new(id), body)
105
- @log.debug("Pushed #{id}/#{Size.new(body.length)} to #{@entrance.class.name} \
106
- in #{Age.new(start, limit: 0.1)} (#{queue.count} still in the queue)")
107
- end
108
-
109
- def queue
110
- DirItems.new(@dir).fetch.select { |f| f =~ /^[0-9a-f]{16}-/ }
100
+ item = @queue.pop
101
+ Thread.current.thread_variable_set(:wallet, item[:id].to_s)
102
+ body = IO.read(item[:file])
103
+ FileUtils.rm_f(item[:file])
104
+ @entrance.push(item[:id], body)
105
+ @log.debug("Pushed #{item[:id]}/#{Size.new(body.length)} to #{@entrance.class.name} \
106
+ in #{Age.new(start, limit: 0.1)} (#{@queue.size} still in the queue)")
111
107
  end
112
108
  end
113
109
  end
@@ -92,7 +92,7 @@ module Zold
92
92
  @history.shift if @history.length >= 16
93
93
  @speed.shift if @speed.length >= 64
94
94
  @wallets.find(id) do |wallet|
95
- @history << "#{id}/#{sec}/#{modified.count}/#{wallet.mnemo}"
95
+ @history << "#{sec}/#{modified.count}/#{wallet.mnemo}"
96
96
  end
97
97
  @speed << sec
98
98
  end
@@ -71,7 +71,7 @@ for #{score.value}/#{score.strength} at #{score.host}:#{score.port}")
71
71
  buffer = +''
72
72
  loop do
73
73
  begin
74
- buffer << stdout.read_nonblock(1024)
74
+ buffer << stdout.read_nonblock(16 * 1024)
75
75
  # rubocop:disable Lint/HandleExceptions
76
76
  rescue IO::WaitReadable => _
77
77
  # rubocop:enable Lint/HandleExceptions
@@ -85,7 +85,7 @@ for #{score.value}/#{score.strength} at #{score.host}:#{score.port}")
85
85
  raise "Failed to calculate the score (##{thr.value}): #{buffer}" unless thr.value.to_i.zero?
86
86
  break
87
87
  end
88
- sleep(10)
88
+ sleep(1)
89
89
  Thread.current.thread_variable_set(:buffer, buffer.length.to_s)
90
90
  end
91
91
  after = Score.parse(buffer.strip)
@@ -230,7 +230,7 @@ in #{Age.new(@start, limit: 1)}")
230
230
  score: score.to_h,
231
231
  wallets: total_wallets,
232
232
  mtime: wallet.mtime.utc.iso8601,
233
- size: File.size(wallet.path),
233
+ size: wallet.size,
234
234
  digest: wallet.digest,
235
235
  copies: Copies.new(File.join(settings.copies, id)).all.count,
236
236
  balance: wallet.balance.to_i,
@@ -313,7 +313,7 @@ in #{Age.new(@start, limit: 1)}")
313
313
  "Balance: #{wallet.balance.to_zld(8)} ZLD (#{wallet.balance.to_i} zents)",
314
314
  "Transactions: #{wallet.txns.count}",
315
315
  "Taxes: #{Tax.new(wallet).paid} paid, the debt is #{Tax.new(wallet).debt}",
316
- "File size: #{File.size(wallet.path)} bytes (#{Copies.new(File.join(settings.copies, id)).all.count} copies)",
316
+ "File size: #{wallet.size} bytes (#{Copies.new(File.join(settings.copies, id)).all.count} copies)",
317
317
  "Modified: #{wallet.mtime.utc.iso8601} (#{Age.new(wallet.mtime.utc.iso8601)} ago)",
318
318
  "Digest: #{wallet.digest}"
319
319
  ].join("\n")
@@ -21,6 +21,7 @@
21
21
  # SOFTWARE.
22
22
 
23
23
  require 'tempfile'
24
+ require 'openssl'
24
25
  require_relative '../log'
25
26
  require_relative '../size'
26
27
  require_relative '../wallet'
@@ -33,11 +34,8 @@ module Zold
33
34
  # The safe entrance
34
35
  class NoDupEntrance
35
36
  def initialize(entrance, wallets, log: Log::Quiet.new)
36
- raise 'Entrance can\'t be nil' if entrance.nil?
37
37
  @entrance = entrance
38
- raise 'Wallets can\'t be nil' if wallets.nil?
39
38
  @wallets = wallets
40
- raise 'Log can\'t be nil' if log.nil?
41
39
  @log = log
42
40
  end
43
41
 
@@ -52,25 +50,14 @@ module Zold
52
50
 
53
51
  # Returns a list of modifed wallets (as Zold::Id)
54
52
  def push(id, body)
55
- raise 'Id can\'t be nil' if id.nil?
56
- raise 'Id must be of type Id' unless id.is_a?(Id)
57
- raise 'Body can\'t be nil' if body.nil?
58
- Tempfile.open(['', Wallet::EXT]) do |f|
59
- IO.write(f, body)
60
- wallet = Wallet.new(f.path)
61
- wallet.refurbish
62
- after = IO.read(wallet.path)
63
- before = @wallets.find(id) do |w|
64
- w.exists? ? IO.read(w.path).to_s : ''
65
- end
66
- if before == after
67
- @log.info("Duplicate of #{Size.new(after.length)} #{wallet.mnemo} ignored")
68
- return []
69
- end
70
- @log.info("New content for #{wallet.mnemo} arrived, \
71
- #{Size.new(before.length)} before and #{Size.new(after.length)} after")
72
- @entrance.push(id, body)
53
+ before = @wallets.find(id) { |w| w.exists? ? w.digest : '' }
54
+ after = OpenSSL::Digest::SHA256.new(body).hexdigest
55
+ if before == after
56
+ @log.debug("Duplicate of #{id} ignored (#{Size.new(body.length)} bytes)")
57
+ return []
73
58
  end
59
+ @log.debug("New content for #{id} arrived (#{Size.new(body.length)} bytes)")
60
+ @entrance.push(id, body)
74
61
  end
75
62
  end
76
63
  end
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.17'
28
+ VERSION = '0.16.18'
29
29
  PROTOCOL = 2
30
30
  end
data/lib/zold/wallet.rb CHANGED
@@ -72,7 +72,7 @@ module Zold
72
72
  end
73
73
 
74
74
  def mnemo
75
- "#{id}/#{balance.to_zld(4)}/#{txns.count}t/#{digest[0, 6]}/#{Size.new(File.size(@file))}"
75
+ "#{id}/#{balance.to_zld(4)}/#{txns.count}t/#{digest[0, 6]}/#{Size.new(size)}"
76
76
  end
77
77
 
78
78
  def to_text
@@ -195,6 +195,11 @@ module Zold
195
195
  list.empty? ? 0 : (Time.now - list.min_by(&:date).date) / (60 * 60)
196
196
  end
197
197
 
198
+ # Size of the wallet file in bytes
199
+ def size
200
+ File.size(path)
201
+ end
202
+
198
203
  def txns
199
204
  @txns.fetch
200
205
  end
data/test/test_http.rb CHANGED
@@ -25,6 +25,7 @@ require 'tmpdir'
25
25
  require 'uri'
26
26
  require 'webmock/minitest'
27
27
  require 'zold/score'
28
+ require_relative 'test__helper'
28
29
  require_relative '../lib/zold/http'
29
30
 
30
31
  # Http test.
@@ -78,6 +79,26 @@ class TestHttp < Zold::Test
78
79
  assert_equal('599', res.code)
79
80
  end
80
81
 
82
+ def test_doesnt_terminate_on_long_call
83
+ require 'random-port'
84
+ WebMock.allow_net_connect!
85
+ RandomPort::Pool::SINGLETON.acquire do |port|
86
+ thread = Thread.start do
87
+ server = TCPServer.new(port)
88
+ loop do
89
+ client = server.accept
90
+ sleep 1
91
+ client.puts("HTTP/1.1 200 OK\nContent-Length: 4\n\nGood")
92
+ client.close
93
+ end
94
+ end
95
+ res = Zold::Http.new(uri: "http://localhost:#{port}/").get(timeout: 2)
96
+ assert_equal('200', res.code, res)
97
+ thread.kill
98
+ thread.join
99
+ end
100
+ end
101
+
81
102
  def test_sends_valid_version_header
82
103
  stub_request(:get, 'http://some-host-3/')
83
104
  .with(headers: { 'X-Zold-Version' => Zold::VERSION })
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.17
4
+ version: 0.16.18
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-08 00:00:00.000000000 Z
11
+ date: 2018-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace