class Zold::Remotes

All remotes

Constants

MASTERS

Default nodes and their ports

MAX_NODES

Default number of nodes to fetch.

PORT

The default TCP port all nodes are supposed to use.

TOLERANCE

At what amount of errors we delete the remote automatically

Public Class Methods

new(file:, network: 'test', timeout: 60) click to toggle source
# File lib/zold/remotes.rb, line 153
def initialize(file:, network: 'test', timeout: 60)
  @file = file
  @network = network
  @timeout = timeout
end

Public Instance Methods

add(host, port = PORT) click to toggle source
# File lib/zold/remotes.rb, line 189
def add(host, port = PORT)
  assert_host_info(host, port)
  modify do |list|
    list + [{ host: host.downcase, port: port, score: 0, errors: 0 }]
  end
  unerror(host, port)
end
all() click to toggle source
# File lib/zold/remotes.rb, line 159
def all
  list = Futex.new(@file).open(false) { load }
  max_score = list.empty? ? 0 : list.max_by { |r| r[:score] }[:score]
  max_score = 1 if max_score.zero?
  max_errors = list.empty? ? 0 : list.max_by { |r| r[:errors] }[:errors]
  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
clean() click to toggle source
# File lib/zold/remotes.rb, line 170
def clean
  modify { [] }
end
error(host, port = PORT) click to toggle source
# File lib/zold/remotes.rb, line 239
def error(host, port = PORT)
  assert_host_info(host, port)
  if_present(host, port) { |r| r[:errors] += 1 }
end
exists?(host, port = PORT) click to toggle source
# File lib/zold/remotes.rb, line 183
def exists?(host, port = PORT)
  assert_host_info(host, port)
  list = Futex.new(@file).open(false) { load }
  !list.find { |r| r[:host] == host.downcase && r[:port] == port }.nil?
end
iterate(log, farm: Farm::Empty.new, threads: 1) { |node| ... } click to toggle source

Go through the list of remotes and call a provided block for each of them. See how it's used, for example, in fetch.rb.

# File lib/zold/remotes.rb, line 206
def iterate(log, farm: Farm::Empty.new, threads: 1)
  raise 'Log can\'t be nil' if log.nil?
  raise 'Farm can\'t be nil' if farm.nil?
  Hands.exec(threads, all) do |r, idx|
    Thread.current.name = "remotes-#{idx}@#{r[:host]}:#{r[:port]}"
    start = Time.now
    best = farm.best[0]
    node = RemoteNode.new(
      host: r[:host],
      port: r[:port],
      score: best.nil? ? Score::ZERO : best,
      idx: idx,
      master: master?(r[:host], r[:port]),
      log: log,
      network: @network
    )
    begin
      yield node
      raise 'Took too long to execute' if (Time.now - start).round > @timeout
      unerror(r[:host], r[:port]) if node.touched
    rescue StandardError => e
      error(r[:host], r[:port])
      if e.is_a?(RemoteNode::CantAssert) || e.is_a?(Fetch::Error)
        log.debug("#{Rainbow(node).red}: \"#{e.message.strip}\" in #{Age.new(start)}")
      else
        log.info("#{Rainbow(node).red}: \"#{e.message.strip}\" in #{Age.new(start)}")
        log.debug(Backtrace.new(e).to_s)
      end
      remove(r[:host], r[:port]) if r[:errors] > TOLERANCE
    end
  end
end
master?(host, port) click to toggle source
# File lib/zold/remotes.rb, line 263
def master?(host, port)
  !MASTERS.find { |r| r[:host] == host && r[:port] == port }.nil?
end
masters() { |r, r| ... } click to toggle source
# File lib/zold/remotes.rb, line 174
def masters
  MASTERS.each do |r|
    if block_given?
      next unless yield(r[:host], r[:port])
    end
    add(r[:host], r[:port])
  end
end
mtime() click to toggle source
# File lib/zold/remotes.rb, line 259
def mtime
  File.exist?(@file) ? File.mtime(@file) : Time.now
end
remove(host, port = PORT) click to toggle source
# File lib/zold/remotes.rb, line 197
def remove(host, port = PORT)
  assert_host_info(host, port)
  modify do |list|
    list.reject { |r| r[:host] == host.downcase && r[:port] == port }
  end
end
rescore(host, port, score) click to toggle source
# File lib/zold/remotes.rb, line 251
def rescore(host, port, score)
  assert_host_info(host, port)
  raise 'Score can\'t be nil' if score.nil?
  raise 'Score has to be of type Integer' unless score.is_a?(Integer)
  if_present(host, port) { |r| r[:score] = score }
  unerror(host, port)
end
unerror(host, port = PORT) click to toggle source
# File lib/zold/remotes.rb, line 244
def unerror(host, port = PORT)
  assert_host_info(host, port)
  if_present(host, port) do |remote|
    remote[:errors] -= 1 if (remote[:errors]).positive?
  end
end

Private Instance Methods

assert_host_info(host, port) click to toggle source
# File lib/zold/remotes.rb, line 316
def assert_host_info(host, port)
  raise 'Host can\'t be nil' if host.nil?
  raise 'Host can\'t be empty' if host.empty?
  raise 'Host IP is wrong, can\'t be all zeros' if host == '0.0.0.0'
  raise 'Port can\'t be nil' if port.nil?
  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
end
if_present(host, port) { |remote| ... } click to toggle source
# File lib/zold/remotes.rb, line 287
def if_present(host, port)
  modify do |list|
    remote = list.find { |r| r[:host] == host.downcase && r[:port] == port }
    return unless remote
    yield remote
    list
  end
end
load() click to toggle source
# File lib/zold/remotes.rb, line 296
def load
  if File.exist?(@file)
    raw = CSV.read(@file).map do |row|
      {
        host: row[0],
        port: row[1].to_i,
        score: row[2].to_i,
        errors: row[3].to_i,
        master: master?(row[0], row[1].to_i)
      }
    end
    raw.reject { |r| !r[:host] || r[:port].zero? || r[:host] == '0.0.0.0' }.map do |r|
      r[:home] = URI("http://#{r[:host]}:#{r[:port]}/")
      r
    end
  else
    []
  end
end
modify() { |load| ... } click to toggle source
# File lib/zold/remotes.rb, line 269
def modify
  FileUtils.mkdir_p(File.dirname(@file))
  Futex.new(@file).open do
    list = yield(load)
    IO.write(
      @file,
      list.uniq { |r| "#{r[:host]}:#{r[:port]}" }.map do |r|
        [
          r[:host],
          r[:port],
          r[:score],
          r[:errors]
        ].join(',')
      end.join("\n")
    )
  end
end