Module: Sfdown::Metadata

Defined in:
lib/sfdown.rb

Overview

Serializes the Node tree to metadata.json: recursive and filesystem-like, enough to rebuild the tree and bootstrap stage 2 without re-scraping.

Constant Summary collapse

Error =
Class.new(StandardError)

Class Method Summary collapse

Class Method Details

.join(parent, name) ⇒ Object



698
699
700
# File 'lib/sfdown.rb', line 698

def join(parent, name)
  parent.empty? ? name.to_s : "#{parent}/#{name}"
end

.node_from(h, path) ⇒ Object



684
685
686
687
688
689
690
691
692
693
694
695
696
# File 'lib/sfdown.rb', line 684

def node_from(h, path)
  Node.new(
    name: h["name"],
    type: h["type"] == "d" ? :d : :f,
    path: path,
    timestamp: parse_ts(h["timestamp"]),
    size: h["size"] || 0,
    downloads: h["downloads"] || 0,
    md5: h["md5"],
    sha1: h["sha1"],
    children: Array(h["content"]).map { |c| node_from(c, join(path, c["name"])) }
  )
end

.parse_ts(str) ⇒ Object



702
703
704
705
706
# File 'lib/sfdown.rb', line 702

def parse_ts(str)
  str && !str.empty? ? Time.parse(str).utc : nil
rescue ArgumentError
  nil
end

.read(file) ⇒ Object

Rebuild the root Node tree from a metadata file. Paths aren't stored in the JSON, so they're reconstructed from the tree structure (root path = ""). Raises Metadata::Error on a structurally invalid document; lets Errno::ENOENT / JSON::ParserError propagate to the caller.



675
676
677
678
679
680
681
682
# File 'lib/sfdown.rb', line 675

def read(file)
  data = JSON.parse(File.read(file))
  unless data.is_a?(Hash) && data["name"] && data["type"] == "d"
    raise Error, "not a valid sfdown metadata document (expected a directory root object)"
  end

  node_from(data, "")
end

.to_h(node) ⇒ Object



651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
# File 'lib/sfdown.rb', line 651

def to_h(node)
  h = {
    "name" => node.name,
    "type" => node.type.to_s,
    "size" => node.size,
    "downloads" => node.downloads,
    "timestamp" => node.timestamp&.strftime("%Y-%m-%d %H:%M:%S UTC")
  }
  if node.file?
    h["md5"] = node.md5 if node.md5
    h["sha1"] = node.sha1 if node.sha1
  end
  h["content"] = node.children.map { |c| to_h(c) }
  h
end

.write(root, path) ⇒ Object



667
668
669
# File 'lib/sfdown.rb', line 667

def write(root, path)
  File.write(path, JSON.pretty_generate(to_h(root)))
end