Class: Factorix::InfoJSON

Inherits:
Data
  • Object
show all
Defined in:
lib/factorix/info_json.rb,
lib/factorix/info_json.rb

Overview

Factorio MOD info.json representation

Represents the metadata file that must be present in every Factorio MOD. Only required fields (name, version, title, author) are enforced.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#authorObject (readonly)

Returns the value of attribute author

Returns:

  • (Object)

    the current value of author



8
9
10
# File 'lib/factorix/info_json.rb', line 8

def author
  @author
end

#dependenciesObject (readonly)

Returns the value of attribute dependencies

Returns:

  • (Object)

    the current value of dependencies



8
9
10
# File 'lib/factorix/info_json.rb', line 8

def dependencies
  @dependencies
end

#descriptionObject (readonly)

Returns the value of attribute description

Returns:

  • (Object)

    the current value of description



8
9
10
# File 'lib/factorix/info_json.rb', line 8

def description
  @description
end

#factorio_versionObject (readonly)

Returns the value of attribute factorio_version

Returns:

  • (Object)

    the current value of factorio_version



8
9
10
# File 'lib/factorix/info_json.rb', line 8

def factorio_version
  @factorio_version
end

#nameObject (readonly)

Returns the value of attribute name

Returns:

  • (Object)

    the current value of name



8
9
10
# File 'lib/factorix/info_json.rb', line 8

def name
  @name
end

#titleObject (readonly)

Returns the value of attribute title

Returns:

  • (Object)

    the current value of title



8
9
10
# File 'lib/factorix/info_json.rb', line 8

def title
  @title
end

#versionObject (readonly)

Returns the value of attribute version

Returns:

  • (Object)

    the current value of version



8
9
10
# File 'lib/factorix/info_json.rb', line 8

def version
  @version
end

Class Method Details

.from_json(json_string) ⇒ InfoJSON

Parse info.json from JSON string

Parameters:

  • json_string (String)

    JSON content

Returns:

Raises:



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/factorix/info_json.rb', line 22

def self.from_json(json_string)
  data = JSON.parse(json_string)

  required_fields = %w[name version title author]
  missing = required_fields - data.keys
  raise FileFormatError, "Missing required fields: #{missing.join(", ")}" unless missing.empty?

  parser = Dependency::Parser.new
  dependencies = (data["dependencies"] || []).map {|dep_str| parser.parse(dep_str) }

  new(name: data["name"], version: MODVersion.from_string(data["version"]), title: data["title"], author: data["author"], description: data["description"] || "", factorio_version: data["factorio_version"], dependencies:)
rescue JSON::ParserError => e
  raise FileFormatError, "Invalid JSON: #{e.message}"
rescue VersionParseError, DependencyParseError => e
  raise FileFormatError, e.message
end

.from_zip(zip_path) ⇒ InfoJSON

Extract from zip file

Uses caching to avoid repeated ZIP extraction for the same file. Cache key is based on file path (MOD ZIPs are immutable after download). Uses double-checked locking to prevent concurrent extraction while avoiding lock overhead on cache hits.

Parameters:

  • zip_path (Pathname)

    path to MOD zip file

Returns:

  • (InfoJSON)

    parsed info.json from zip

Raises:



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/factorix/info_json.rb', line 49

def self.from_zip(zip_path)
  cache = Container.resolve(:info_json_cache)
  logger = Container.resolve(:logger)
  cache_key = zip_path.to_s

  if (cached_json = cache.read(cache_key))
    logger.debug("info.json cache hit", path: zip_path.to_s)
    return from_json((+cached_json).force_encoding(Encoding::UTF_8))
  end

  logger.debug("info.json cache miss", path: zip_path.to_s)

  cache.with_lock(cache_key) do
    if (cached_json = cache.read(cache_key))
      logger.debug("info.json cache hit (after lock)", path: zip_path.to_s)
      return from_json((+cached_json).force_encoding(Encoding::UTF_8))
    end

    json_string = Zip::File.open(zip_path) {|zip_file|
      info_entry = zip_file.find {|entry| entry.name.end_with?("/info.json") }
      raise FileFormatError, "info.json not found in #{zip_path}" unless info_entry

      info_entry.get_input_stream.read
    }

    temp_file = Tempfile.new("info_json_cache")
    begin
      temp_file.write(json_string)
      temp_file.close
      cache.store(cache_key, Pathname(temp_file.path))
      logger.debug("Stored info.json in cache", path: zip_path.to_s)
    ensure
      temp_file.unlink
    end

    from_json(json_string)
  end
rescue Zip::Error => e
  raise FileFormatError, "Invalid zip file: #{e.message}"
end