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],