lib/zold/remotes.rb in zold-0.14.39 vs lib/zold/remotes.rb in zold-0.14.40
- old
+ new
@@ -37,36 +37,47 @@
# Author:: Yegor Bugayenko (yegor256@gmail.com)
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
# License:: MIT
module Zold
# All remotes
- class Remotes
+ class Remotes < Dry::Struct
# The default TCP port all nodes are supposed to use.
PORT = 4096
# At what amount of errors we delete the remote automatically
TOLERANCE = 8
# Default number of nodes to fetch.
MAX_NODES = 16
+ # Mutex object
+ MUTEX = Mutex.new
+
+ attribute :file, Types::Strict::String
+ attribute :network, Types::Strict::String.optional.default('test')
+ attribute :timeout, Types::Strict::Integer.optional.default(16)
+
# Empty, for standalone mode
class Empty < Remotes
def all
[]
end
def iterate(_)
# Nothing to do here
end
+
+ def mtime
+ Time.now
+ end
end
# One remote.
class Remote < Dry::Struct
attribute :host, Types::Strict::String
attribute :port, Types::Strict::Integer.constrained(gteq: 0, lt: 65_535)
- attribute :score, Object
+ attribute :score, Score
attribute :idx, Types::Strict::Integer
attribute :network, Types::Strict::String.optional.default('test')
attribute :log, (Types::Class.constructor do |value|
value.nil? ? Log::Quiet.new : value
end)
@@ -104,39 +115,30 @@
def assert_score_value(score, min)
raise "Score is too small (<#{min}): #{score}" if score.value < min
end
end
- def initialize(file:, network: 'test', mutex: Mutex.new, timeout: 16)
- @file = file
- @network = network
- @mutex = mutex
- @timeout = timeout
- end
-
def all
- @mutex.synchronize do
- list = load
- max_score = list.map { |r| r[:score] }.max || 0
- max_score = 1 if max_score.zero?
- max_errors = list.map { |r| r[:errors] }.max || 0
- max_errors = 1 if max_errors.zero?
- list.sort_by do |r|
- (1 - r[:errors] / max_errors) * 5 + (r[:score] / max_score)
- end.reverse
- end
+ list = load
+ max_score = list.map { |r| r[:score] }.max || 0
+ max_score = 1 if max_score.zero?
+ max_errors = list.map { |r| r[:errors] }.max || 0
+ max_errors = 1 if max_errors.zero?
+ list.sort_by do |r|
+ (1 - r[:errors] / max_errors) * 5 + (r[:score] / max_score)
+ end.reverse
end
def clean
modify { [] }
end
def reset
- FileUtils.mkdir_p(File.dirname(@file))
+ FileUtils.mkdir_p(File.dirname(file))
FileUtils.copy(
File.join(File.dirname(__FILE__), '../../resources/remotes'),
- @file
+ file
)
end
def exists?(host, port = Remotes::PORT)
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
@@ -152,11 +154,11 @@
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
raise 'Port can\'t be zero' if port.zero?
raise 'Port can\'t be negative' if port.negative?
raise 'Port can\'t be over 65536' if port > 0xffff
modify do |list|
- list + [{ host: host.downcase, port: port, score: 0 }]
+ list + [{ host: host.downcase, port: port, score: 0, errors: 0 }]
end
end
def remove(host, port = Remotes::PORT)
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
@@ -187,14 +189,14 @@
host: r[:host],
port: r[:port],
score: score,
idx: idx,
log: log,
- network: @network
+ network: network
)
idx += 1
- raise 'Took too long to execute' if (Time.now - start).round > @timeout
+ raise 'Took too long to execute' if (Time.now - start).round > timeout
rescue StandardError => e
error(r[:host], r[:port])
log.info("#{Rainbow("#{r[:host]}:#{r[:port]}").red}: #{e.message} \
in #{(Time.now - start).round}s")
log.debug(Backtrace.new(e).to_s)
@@ -219,14 +221,18 @@
raise 'Score can\'t be nil' if score.nil?
raise 'Port has to be of type Integer' unless port.is_a?(Integer)
if_present(host, port) { |r| r[:score] = score }
end
+ def mtime
+ File.mtime(file)
+ end
+
private
def modify
- @mutex.synchronize do
+ Remotes::MUTEX.synchronize do
save(yield(load))
end
end
def if_present(host, port)
@@ -237,26 +243,26 @@
list
end
end
def load
- reset unless File.exist?(@file)
- raw = CSV.read(@file).map do |r|
+ reset unless File.exist?(file)
+ raw = CSV.read(file).map do |row|
{
- host: r[0],
- port: r[1].to_i,
- score: r[2].to_i,
- errors: r[3].to_i
+ host: row[0],
+ port: row[1].to_i,
+ score: row[2].to_i,
+ errors: row[3].to_i
}
end
raw.reject { |r| !r[:host] || r[:port].zero? }.map do |r|
r[:home] = URI("http://#{r[:host]}:#{r[:port]}/")
r
end
end
def save(list)
- AtomicFile.new(@file).write(
+ AtomicFile.new(file).write(
list.uniq { |r| "#{r[:host]}:#{r[:port]}" }.map do |r|
[
r[:host],
r[:port],
r[:score],