class Zold::Copies

All copies

Constants

EXT

Extension for copy files

Public Class Methods

new(dir, log: Log::NULL) click to toggle source
# File lib/zold/copies.rb, line 43
def initialize(dir, log: Log::NULL)
  @dir = dir
  @log = log
end

Public Instance Methods

add(content, host, port, score, time: Time.now, master: false) click to toggle source

Returns the name of the copy

# File lib/zold/copies.rb, line 104
def add(content, host, port, score, time: Time.now, master: false)
  raise "Content can't be empty" if content.empty?
  raise 'TCP port must be of type Integer' unless port.is_a?(Integer)
  raise "TCP port can't be negative: #{port}" if port.negative?
  raise 'Time must be of type Time' unless time.is_a?(Time)
  raise "Time must be in the past: #{time}" if time > Time.now
  raise 'Score must be Integer' unless score.is_a?(Integer)
  raise "Score can't be negative: #{score}" if score.negative?
  FileUtils.mkdir_p(@dir)
  Futex.new(file, log: @log).open do
    list = load
    target = list.find do |s|
      f = File.join(@dir, "#{s[:name]}#{Copies::EXT}")
      digest = OpenSSL::Digest::SHA256.new(content).hexdigest
      File.exist?(f) && OpenSSL::Digest::SHA256.file(f).hexdigest == digest
    end
    if target.nil?
      max = DirItems.new(@dir).fetch
        .select { |f| File.basename(f, Copies::EXT) =~ /^[0-9]+$/ }
        .map(&:to_i)
        .max
      max = 0 if max.nil?
      name = (max + 1).to_s
      IO.write(File.join(@dir, "#{name}#{Copies::EXT}"), content)
    else
      name = target[:name]
    end
    list.reject! { |s| s[:host] == host && s[:port] == port }
    list << {
      name: name,
      host: host,
      port: port,
      score: score,
      time: time,
      master: master
    }
    save(list)
    name
  end
end
all(masters_first: true) click to toggle source
# File lib/zold/copies.rb, line 145
def all(masters_first: true)
  Futex.new(file, log: @log).open(false) do
    list = load.group_by { |s| s[:name] }.map do |name, scores|
      {
        name: name,
        path: File.join(@dir, "#{name}#{Copies::EXT}"),
        total: scores.count,
        master: scores.any? { |s| s[:master] },
        score: scores.select { |s| s[:time] > Time.now - 24 * 60 * 60 }
          .map { |s| s[:score] }
          .inject(&:+) || 0
      }
    end.select { |c| File.exist?(c[:path]) }
    if masters_first
      list.sort_by! { |c| [c[:master] ? 1 : 0, c[:score].to_s.rjust(5, '0')] }
    else
      list.sort_by! { |c| c[:score] }
    end
    list.reverse
  end
end
clean(max: 24 * 60 * 60) click to toggle source

Delete all copies that are older than the “max” age provided, in seconds.

# File lib/zold/copies.rb, line 57
def clean(max: 24 * 60 * 60)
  Futex.new(file, log: @log).open do
    list = load
    list.reject! do |s|
      if s[:time] >= Time.now - max
        false
      else
        @log.debug("Copy ##{s[:name]}/#{s[:host]}:#{s[:port]} is too old, over #{Age.new(s[:time])}")
        true
      end
    end
    save(list)
    deleted = 0
    files.each do |f|
      next unless list.find { |s| s[:name] == File.basename(f, Copies::EXT) }.nil?
      file = File.join(@dir, f)
      size = File.size(file)
      File.delete(file)
      @log.debug("Copy at #{f} deleted: #{Size.new(size)}")
      deleted += 1
    end
    list.select! do |s|
      cp = File.join(@dir, "#{s[:name]}#{Copies::EXT}")
      wallet = Wallet.new(cp)
      begin
        wallet.refurbish
        raise "Invalid protocol #{wallet.protocol} in #{cp}" unless wallet.protocol == Zold::PROTOCOL
        true
      rescue StandardError => e
        FileUtils.rm_rf(cp)
        @log.debug("Copy at #{cp} deleted: #{Backtrace.new(e)}")
        deleted += 1
        false
      end
    end
    save(list)
    deleted
  end
end
load() click to toggle source
# File lib/zold/copies.rb, line 167
def load
  FileUtils.mkdir_p(File.dirname(file))
  FileUtils.touch(file)
  CSV.read(file).select { |s| s.count == 6 }.map do |s|
    {
      name: s[0],
      host: s[1],
      port: s[2].to_i,
      score: s[3].to_i,
      time: Txn.parse_time(s[4]),
      master: s[5] == 'M'
    }
  end
end
remove(host, port) click to toggle source
# File lib/zold/copies.rb, line 97
def remove(host, port)
  Futex.new(file, log: @log).open do
    save(load.reject { |s| s[:host] == host && s[:port] == port })
  end
end
root() click to toggle source
# File lib/zold/copies.rb, line 48
def root
  File.expand_path(File.join(@dir, '..'))
end
to_s() click to toggle source
# File lib/zold/copies.rb, line 52
def to_s
  File.basename(@dir)
end

Private Instance Methods

file() click to toggle source
# File lib/zold/copies.rb, line 204
def file
  File.join(@dir, "scores#{Copies::EXT}")
end
files() click to toggle source
# File lib/zold/copies.rb, line 200
def files
  DirItems.new(@dir).fetch.select { |f| File.basename(f, Copies::EXT) =~ /^[0-9]+$/ }
end
save(list) click to toggle source
# File lib/zold/copies.rb, line 184
def save(list)
  IO.write(
    file,
    list.map do |r|
      [
        r[:name],
        r[:host],
        r[:port],
        r[:score],
        r[:time].utc.iso8601,
        r[:master] ? 'M' : 'E'
      ].join(',')
    end.join("\n")
  )
end