factorix 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/exe/factorix +17 -0
- data/lib/factorix/api/mod_download_api.rb +10 -5
- data/lib/factorix/api/mod_portal_api.rb +6 -49
- data/lib/factorix/cache/base.rb +116 -0
- data/lib/factorix/cache/entry.rb +25 -0
- data/lib/factorix/cache/file_system.rb +137 -57
- data/lib/factorix/cache/redis.rb +287 -0
- data/lib/factorix/cache/s3.rb +388 -0
- data/lib/factorix/cli/commands/cache/evict.rb +17 -22
- data/lib/factorix/cli/commands/cache/stat.rb +57 -58
- data/lib/factorix/cli/commands/download_support.rb +1 -6
- data/lib/factorix/cli/commands/mod/download.rb +2 -3
- data/lib/factorix/cli/commands/mod/edit.rb +1 -4
- data/lib/factorix/cli/commands/mod/image/add.rb +1 -4
- data/lib/factorix/cli/commands/mod/image/edit.rb +1 -4
- data/lib/factorix/cli/commands/mod/image/list.rb +1 -4
- data/lib/factorix/cli/commands/mod/install.rb +2 -3
- data/lib/factorix/cli/commands/mod/search.rb +2 -3
- data/lib/factorix/cli/commands/mod/show.rb +2 -3
- data/lib/factorix/cli/commands/mod/sync.rb +2 -3
- data/lib/factorix/cli/commands/mod/update.rb +6 -39
- data/lib/factorix/cli/commands/mod/upload.rb +1 -4
- data/lib/factorix/cli/commands/portal_support.rb +27 -0
- data/lib/factorix/container.rb +27 -13
- data/lib/factorix/errors.rb +3 -0
- data/lib/factorix/http/cache_decorator.rb +5 -5
- data/lib/factorix/info_json.rb +5 -5
- data/lib/factorix/portal.rb +3 -2
- data/lib/factorix/transfer/downloader.rb +19 -11
- data/lib/factorix/version.rb +1 -1
- data/lib/factorix.rb +45 -53
- data/sig/factorix/api/mod_download_api.rbs +1 -2
- data/sig/factorix/cache/base.rbs +28 -0
- data/sig/factorix/cache/entry.rbs +14 -0
- data/sig/factorix/cache/file_system.rbs +7 -6
- data/sig/factorix/cache/redis.rbs +36 -0
- data/sig/factorix/cache/s3.rbs +38 -0
- data/sig/factorix/errors.rbs +3 -0
- data/sig/factorix/portal.rbs +1 -1
- metadata +25 -2
|
@@ -50,9 +50,9 @@ module Factorix
|
|
|
50
50
|
# Don't cache streaming requests
|
|
51
51
|
return client.get(uri, headers:, &block) if block
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
cache_key = uri.to_s
|
|
54
54
|
|
|
55
|
-
cached_body = cache.read(
|
|
55
|
+
cached_body = cache.read(cache_key)
|
|
56
56
|
if cached_body
|
|
57
57
|
logger.debug("Cache hit", uri: uri.to_s)
|
|
58
58
|
publish("cache.hit", url: uri.to_s)
|
|
@@ -63,9 +63,9 @@ module Factorix
|
|
|
63
63
|
publish("cache.miss", url: uri.to_s)
|
|
64
64
|
|
|
65
65
|
# Locking prevents concurrent downloads of the same resource
|
|
66
|
-
cache.with_lock(
|
|
66
|
+
cache.with_lock(cache_key) do
|
|
67
67
|
# Double-check: another thread might have filled the cache
|
|
68
|
-
cached_body = cache.read(
|
|
68
|
+
cached_body = cache.read(cache_key)
|
|
69
69
|
if cached_body
|
|
70
70
|
publish("cache.hit", url: uri.to_s)
|
|
71
71
|
return CachedResponse.new(cached_body)
|
|
@@ -77,7 +77,7 @@ module Factorix
|
|
|
77
77
|
with_temporary_file do |temp|
|
|
78
78
|
temp.write(response.body)
|
|
79
79
|
temp.close
|
|
80
|
-
cache.store(
|
|
80
|
+
cache.store(cache_key, Pathname(temp.path))
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
83
|
|
data/lib/factorix/info_json.rb
CHANGED
|
@@ -49,19 +49,19 @@ module Factorix
|
|
|
49
49
|
def self.from_zip(zip_path)
|
|
50
50
|
cache = Container.resolve(:info_json_cache)
|
|
51
51
|
logger = Container.resolve(:logger)
|
|
52
|
-
cache_key =
|
|
52
|
+
cache_key = zip_path.to_s
|
|
53
53
|
|
|
54
|
-
if (cached_json = cache.read(cache_key
|
|
54
|
+
if (cached_json = cache.read(cache_key))
|
|
55
55
|
logger.debug("info.json cache hit", path: zip_path.to_s)
|
|
56
|
-
return from_json(cached_json)
|
|
56
|
+
return from_json((+cached_json).force_encoding(Encoding::UTF_8))
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
logger.debug("info.json cache miss", path: zip_path.to_s)
|
|
60
60
|
|
|
61
61
|
cache.with_lock(cache_key) do
|
|
62
|
-
if (cached_json = cache.read(cache_key
|
|
62
|
+
if (cached_json = cache.read(cache_key))
|
|
63
63
|
logger.debug("info.json cache hit (after lock)", path: zip_path.to_s)
|
|
64
|
-
return from_json(cached_json)
|
|
64
|
+
return from_json((+cached_json).force_encoding(Encoding::UTF_8))
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
json_string = Zip::File.open(zip_path) {|zip_file|
|
data/lib/factorix/portal.rb
CHANGED
|
@@ -72,12 +72,13 @@ module Factorix
|
|
|
72
72
|
#
|
|
73
73
|
# @param release [API::Release] release object containing download_url and sha1
|
|
74
74
|
# @param output [Pathname] output file path
|
|
75
|
+
# @param handler [Object, nil] event handler for download progress (optional)
|
|
75
76
|
# @return [void]
|
|
76
77
|
# @raise [DigestMismatchError] if SHA1 verification fails
|
|
77
|
-
def download_mod(release, output)
|
|
78
|
+
def download_mod(release, output, handler: nil)
|
|
78
79
|
# Extract path from URI::HTTPS
|
|
79
80
|
download_path = release.download_url.path
|
|
80
|
-
mod_download_api.download(download_path, output, expected_sha1: release.sha1)
|
|
81
|
+
mod_download_api.download(download_path, output, expected_sha1: release.sha1, handler:)
|
|
81
82
|
end
|
|
82
83
|
|
|
83
84
|
# Upload a MOD file to the portal
|
|
@@ -53,9 +53,9 @@ module Factorix
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
logger.info("Starting download", output: output.to_s)
|
|
56
|
-
|
|
56
|
+
cache_key = strip_query(url)
|
|
57
57
|
|
|
58
|
-
case try_cache_hit(
|
|
58
|
+
case try_cache_hit(cache_key, output, expected_sha1:)
|
|
59
59
|
when :hit
|
|
60
60
|
return
|
|
61
61
|
when :miss
|
|
@@ -68,14 +68,14 @@ module Factorix
|
|
|
68
68
|
raise RuntimeError, "Unexpected cache state"
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
cache.with_lock(
|
|
72
|
-
return if try_cache_hit(
|
|
71
|
+
cache.with_lock(cache_key) do
|
|
72
|
+
return if try_cache_hit(cache_key, output, expected_sha1:) == :hit
|
|
73
73
|
|
|
74
74
|
with_temporary_file do |temp_file|
|
|
75
75
|
download_file_with_progress(url, temp_file)
|
|
76
76
|
verify_sha1(temp_file, expected_sha1) if expected_sha1
|
|
77
|
-
cache.store(
|
|
78
|
-
cache.
|
|
77
|
+
cache.store(cache_key, temp_file)
|
|
78
|
+
cache.write_to(cache_key, output)
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
end
|
|
@@ -112,21 +112,21 @@ module Factorix
|
|
|
112
112
|
# If the cached file exists but fails SHA1 verification, the cache entry
|
|
113
113
|
# is invalidated and :corrupted is returned to trigger re-download.
|
|
114
114
|
#
|
|
115
|
-
# @param
|
|
115
|
+
# @param cache_key [String] logical cache key (URL string)
|
|
116
116
|
# @param output [Pathname] path to save the cached file
|
|
117
117
|
# @param expected_sha1 [String, nil] expected SHA1 digest for verification (optional)
|
|
118
118
|
# @return [Symbol] :hit if cache hit with valid SHA1, :miss if not cached, :corrupted if SHA1 mismatch
|
|
119
|
-
private def try_cache_hit(
|
|
120
|
-
return :miss unless cache.
|
|
119
|
+
private def try_cache_hit(cache_key, output, expected_sha1:)
|
|
120
|
+
return :miss unless cache.write_to(cache_key, output)
|
|
121
121
|
|
|
122
122
|
logger.info("Cache hit", output: output.to_s)
|
|
123
123
|
verify_sha1(output, expected_sha1) if expected_sha1
|
|
124
|
-
total_size = cache.size(
|
|
124
|
+
total_size = cache.size(cache_key)
|
|
125
125
|
publish("cache.hit", output: output.to_s, total_size:)
|
|
126
126
|
:hit
|
|
127
127
|
rescue DigestMismatchError => e
|
|
128
128
|
logger.warn("Cache corrupted, invalidating", output: output.to_s, error: e.message)
|
|
129
|
-
cache.delete(
|
|
129
|
+
cache.delete(cache_key)
|
|
130
130
|
:corrupted
|
|
131
131
|
end
|
|
132
132
|
|
|
@@ -144,6 +144,14 @@ module Factorix
|
|
|
144
144
|
raise DigestMismatchError, "SHA1 mismatch: expected #{expected_sha1}, got #{actual_sha1}"
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
+
# Strip query parameters from a URI to create a safe cache key.
|
|
148
|
+
# This prevents sensitive data (e.g., authentication tokens) from being
|
|
149
|
+
# stored in cache metadata.
|
|
150
|
+
#
|
|
151
|
+
# @param uri [URI] the URI to strip
|
|
152
|
+
# @return [String] URI string without query parameters
|
|
153
|
+
private def strip_query(uri) = uri.dup.tap {|u| u.query = nil }.to_s
|
|
154
|
+
|
|
147
155
|
# Create a temporary file for downloading, ensuring cleanup after use.
|
|
148
156
|
#
|
|
149
157
|
# @yield [Pathname] the temporary file path
|
data/lib/factorix/version.rb
CHANGED
data/lib/factorix.rb
CHANGED
|
@@ -35,29 +35,65 @@ module Factorix
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
# Cache settings
|
|
38
|
+
# Each cache type can have its own backend with hierarchical configuration.
|
|
39
|
+
# Common settings (backend, ttl) apply to all backends.
|
|
40
|
+
# Backend-specific settings are nested under the backend name.
|
|
38
41
|
setting :cache do
|
|
39
42
|
# Download cache settings (for MOD files)
|
|
40
43
|
setting :download do
|
|
41
|
-
setting :
|
|
44
|
+
setting :backend, default: :file_system
|
|
42
45
|
setting :ttl, default: nil # nil for unlimited (MOD files are immutable)
|
|
43
|
-
setting :
|
|
44
|
-
|
|
46
|
+
setting :file_system do
|
|
47
|
+
setting :max_file_size, default: nil # nil for unlimited
|
|
48
|
+
setting :compression_threshold, default: nil # nil for no compression (binary files)
|
|
49
|
+
end
|
|
50
|
+
setting :redis do
|
|
51
|
+
setting :url, default: nil # nil falls back to REDIS_URL env, then localhost:6379
|
|
52
|
+
setting :lock_timeout, default: 30
|
|
53
|
+
end
|
|
54
|
+
setting :s3 do
|
|
55
|
+
setting :bucket, default: nil # required when using S3 backend
|
|
56
|
+
setting :region, default: nil # nil falls back to AWS_REGION env or SDK default
|
|
57
|
+
setting :lock_timeout, default: 30
|
|
58
|
+
end
|
|
45
59
|
end
|
|
46
60
|
|
|
47
61
|
# API cache settings (for API responses)
|
|
48
62
|
setting :api do
|
|
49
|
-
setting :
|
|
63
|
+
setting :backend, default: :file_system
|
|
50
64
|
setting :ttl, default: 3600 # 1 hour (API responses may change)
|
|
51
|
-
setting :
|
|
52
|
-
|
|
65
|
+
setting :file_system do
|
|
66
|
+
setting :max_file_size, default: 10 * 1024 * 1024 # 10MiB (JSON responses)
|
|
67
|
+
setting :compression_threshold, default: 0 # always compress (JSON is highly compressible)
|
|
68
|
+
end
|
|
69
|
+
setting :redis do
|
|
70
|
+
setting :url, default: nil # nil falls back to REDIS_URL env, then localhost:6379
|
|
71
|
+
setting :lock_timeout, default: 30
|
|
72
|
+
end
|
|
73
|
+
setting :s3 do
|
|
74
|
+
setting :bucket, default: nil # required when using S3 backend
|
|
75
|
+
setting :region, default: nil # nil falls back to AWS_REGION env or SDK default
|
|
76
|
+
setting :lock_timeout, default: 30
|
|
77
|
+
end
|
|
53
78
|
end
|
|
54
79
|
|
|
55
80
|
# info.json cache settings (for MOD metadata from ZIP files)
|
|
56
81
|
setting :info_json do
|
|
57
|
-
setting :
|
|
82
|
+
setting :backend, default: :file_system
|
|
58
83
|
setting :ttl, default: nil # nil for unlimited (info.json is immutable within a MOD ZIP)
|
|
59
|
-
setting :
|
|
60
|
-
|
|
84
|
+
setting :file_system do
|
|
85
|
+
setting :max_file_size, default: nil # nil for unlimited (info.json is small)
|
|
86
|
+
setting :compression_threshold, default: 0 # always compress (JSON is highly compressible)
|
|
87
|
+
end
|
|
88
|
+
setting :redis do
|
|
89
|
+
setting :url, default: nil # nil falls back to REDIS_URL env, then localhost:6379
|
|
90
|
+
setting :lock_timeout, default: 30
|
|
91
|
+
end
|
|
92
|
+
setting :s3 do
|
|
93
|
+
setting :bucket, default: nil # required when using S3 backend
|
|
94
|
+
setting :region, default: nil # nil falls back to AWS_REGION env or SDK default
|
|
95
|
+
setting :lock_timeout, default: 30
|
|
96
|
+
end
|
|
61
97
|
end
|
|
62
98
|
end
|
|
63
99
|
|
|
@@ -108,48 +144,4 @@ module Factorix
|
|
|
108
144
|
|
|
109
145
|
Import = Dry::AutoInject(Container)
|
|
110
146
|
public_constant :Import
|
|
111
|
-
|
|
112
|
-
# Initialize cache directory defaults after Container is loaded
|
|
113
|
-
runtime = Container.resolve(:runtime)
|
|
114
|
-
config.cache.download.dir = runtime.factorix_cache_dir / "download"
|
|
115
|
-
config.cache.api.dir = runtime.factorix_cache_dir / "api"
|
|
116
|
-
config.cache.info_json.dir = runtime.factorix_cache_dir / "info_json"
|
|
117
|
-
|
|
118
|
-
# @deprecated Use {Container} for DI and {Factorix} for configuration. Will be removed in v1.0.
|
|
119
|
-
class Application
|
|
120
|
-
# @!method [](key)
|
|
121
|
-
# @deprecated Use {Container.[]} instead
|
|
122
|
-
def self.[](key)
|
|
123
|
-
warn "[factorix] Factorix::Application is deprecated, use Factorix::Container for DI"
|
|
124
|
-
Container[key]
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
# @!method resolve(key)
|
|
128
|
-
# @deprecated Use {Container.resolve} instead
|
|
129
|
-
def self.resolve(key)
|
|
130
|
-
warn "[factorix] Factorix::Application is deprecated, use Factorix::Container for DI"
|
|
131
|
-
Container.resolve(key)
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# @!method register(...)
|
|
135
|
-
# @deprecated Use {Container.register} instead
|
|
136
|
-
def self.register(...)
|
|
137
|
-
warn "[factorix] Factorix::Application is deprecated, use Factorix::Container for DI"
|
|
138
|
-
Container.register(...)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# @!method config
|
|
142
|
-
# @deprecated Use {Factorix.config} instead
|
|
143
|
-
def self.config
|
|
144
|
-
warn "[factorix] Factorix::Application is deprecated, use Factorix.config for configuration"
|
|
145
|
-
Factorix.config
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
# @!method configure(&block)
|
|
149
|
-
# @deprecated Use {Factorix.configure} instead
|
|
150
|
-
def self.configure(&)
|
|
151
|
-
warn "[factorix] Factorix::Application is deprecated, use Factorix.configure for configuration"
|
|
152
|
-
Factorix.configure(&)
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
147
|
end
|
|
@@ -7,12 +7,11 @@ module Factorix
|
|
|
7
7
|
class MODDownloadAPI
|
|
8
8
|
BASE_URL: String
|
|
9
9
|
|
|
10
|
-
attr_reader downloader: Transfer::Downloader
|
|
11
10
|
attr_reader logger: Dry::Logger::Dispatcher
|
|
12
11
|
|
|
13
12
|
def initialize: (**untyped deps) -> void
|
|
14
13
|
|
|
15
|
-
def download: (String download_url, Pathname output, ?expected_sha1: String?) -> void
|
|
14
|
+
def download: (String download_url, Pathname output, ?expected_sha1: String?, ?handler: untyped?) -> void
|
|
16
15
|
end
|
|
17
16
|
end
|
|
18
17
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# RBS type signature file
|
|
2
|
+
|
|
3
|
+
module Factorix
|
|
4
|
+
module Cache
|
|
5
|
+
class Base
|
|
6
|
+
attr_reader ttl: Integer?
|
|
7
|
+
|
|
8
|
+
def initialize: (?ttl: Integer?) -> void
|
|
9
|
+
|
|
10
|
+
def exist?: (String key) -> bool
|
|
11
|
+
def read: (String key) -> String?
|
|
12
|
+
def store: (String key, Pathname src) -> bool
|
|
13
|
+
def delete: (String key) -> bool
|
|
14
|
+
def clear: () -> void
|
|
15
|
+
|
|
16
|
+
def with_lock: (String key) { () -> void } -> void
|
|
17
|
+
|
|
18
|
+
def age: (String key) -> Float?
|
|
19
|
+
def expired?: (String key) -> bool
|
|
20
|
+
def size: (String key) -> Integer?
|
|
21
|
+
|
|
22
|
+
def each: () -> Enumerator[[String, Entry], void]
|
|
23
|
+
| () { ([String, Entry]) -> void } -> void
|
|
24
|
+
|
|
25
|
+
def backend_info: () -> Hash[Symbol, untyped]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -4,18 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
module Factorix
|
|
6
6
|
module Cache
|
|
7
|
-
class FileSystem
|
|
7
|
+
class FileSystem < Base
|
|
8
8
|
LOCK_FILE_LIFETIME: Integer
|
|
9
9
|
|
|
10
|
-
def initialize: (
|
|
11
|
-
|
|
12
|
-
def key_for: (String url_string) -> String
|
|
10
|
+
def initialize: (cache_type: Symbol, ?ttl: Integer?, ?max_file_size: Integer?, ?compression_threshold: Integer?) -> void
|
|
13
11
|
|
|
14
12
|
def exist?: (String key) -> bool
|
|
15
13
|
|
|
16
|
-
def
|
|
14
|
+
def write_to: (String key, Pathname output) -> bool
|
|
17
15
|
|
|
18
|
-
def read: (String key
|
|
16
|
+
def read: (String key) -> String?
|
|
19
17
|
|
|
20
18
|
def store: (String key, Pathname src) -> bool
|
|
21
19
|
|
|
@@ -30,6 +28,9 @@ module Factorix
|
|
|
30
28
|
def size: (String key) -> Integer?
|
|
31
29
|
|
|
32
30
|
def with_lock: [T] (String key) { () -> T } -> T
|
|
31
|
+
|
|
32
|
+
def each: () { (String, Entry) -> void } -> void
|
|
33
|
+
| () -> Enumerator[[String, Entry], void]
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# RBS type signature file
|
|
2
|
+
# NOTE: Do not include private method definitions in RBS files.
|
|
3
|
+
# Only public interfaces should be documented here.
|
|
4
|
+
|
|
5
|
+
module Factorix
|
|
6
|
+
module Cache
|
|
7
|
+
class Redis < Base
|
|
8
|
+
DEFAULT_LOCK_TIMEOUT: Integer
|
|
9
|
+
|
|
10
|
+
def initialize: (?url: String?, cache_type: String | Symbol, ?lock_timeout: Integer, ?ttl: Integer?) -> void
|
|
11
|
+
|
|
12
|
+
def exist?: (String key) -> bool
|
|
13
|
+
|
|
14
|
+
def read: (String key) -> String?
|
|
15
|
+
|
|
16
|
+
def write_to: (String key, Pathname output) -> bool
|
|
17
|
+
|
|
18
|
+
def store: (String key, Pathname src) -> bool
|
|
19
|
+
|
|
20
|
+
def delete: (String key) -> bool
|
|
21
|
+
|
|
22
|
+
def clear: () -> void
|
|
23
|
+
|
|
24
|
+
def age: (String key) -> Integer?
|
|
25
|
+
|
|
26
|
+
def expired?: (String key) -> bool
|
|
27
|
+
|
|
28
|
+
def size: (String key) -> Integer?
|
|
29
|
+
|
|
30
|
+
def with_lock: [T] (String key) { () -> T } -> T
|
|
31
|
+
|
|
32
|
+
def each: () { (String, Entry) -> void } -> void
|
|
33
|
+
| () -> Enumerator[[String, Entry], void]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# RBS type signature file
|
|
2
|
+
# NOTE: Do not include private method definitions in RBS files.
|
|
3
|
+
# Only public interfaces should be documented here.
|
|
4
|
+
|
|
5
|
+
module Factorix
|
|
6
|
+
module Cache
|
|
7
|
+
class S3 < Base
|
|
8
|
+
DEFAULT_LOCK_TIMEOUT: Integer
|
|
9
|
+
|
|
10
|
+
def initialize: (bucket: String, cache_type: String | Symbol, ?region: String?, ?lock_timeout: Integer, ?ttl: Integer?) -> void
|
|
11
|
+
|
|
12
|
+
def exist?: (String key) -> bool
|
|
13
|
+
|
|
14
|
+
def read: (String key) -> String?
|
|
15
|
+
|
|
16
|
+
def write_to: (String key, Pathname output) -> bool
|
|
17
|
+
|
|
18
|
+
def store: (String key, Pathname src) -> bool
|
|
19
|
+
|
|
20
|
+
def delete: (String key) -> bool
|
|
21
|
+
|
|
22
|
+
def clear: () -> void
|
|
23
|
+
|
|
24
|
+
def age: (String key) -> Integer?
|
|
25
|
+
|
|
26
|
+
def expired?: (String key) -> bool
|
|
27
|
+
|
|
28
|
+
def size: (String key) -> Integer?
|
|
29
|
+
|
|
30
|
+
def with_lock: [T] (String key) { () -> T } -> T
|
|
31
|
+
|
|
32
|
+
def each: () { (String, Entry) -> void } -> void
|
|
33
|
+
| () -> Enumerator[[String, Entry], void]
|
|
34
|
+
|
|
35
|
+
def backend_info: () -> Hash[Symbol, untyped]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/sig/factorix/errors.rbs
CHANGED
data/sig/factorix/portal.rbs
CHANGED
|
@@ -18,7 +18,7 @@ module Factorix
|
|
|
18
18
|
|
|
19
19
|
def get_mod_full: (String name) -> API::MODInfo
|
|
20
20
|
|
|
21
|
-
def download_mod: (API::Release release, Pathname output) -> void
|
|
21
|
+
def download_mod: (API::Release release, Pathname output, ?handler: untyped?) -> void
|
|
22
22
|
|
|
23
23
|
def upload_mod: (String mod_name, Pathname file_path, **untyped metadata) -> void
|
|
24
24
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: factorix
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- OZAWA Sakuro
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-01-
|
|
11
|
+
date: 2026-01-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
@@ -94,6 +94,20 @@ dependencies:
|
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '1.1'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: dry-inflector
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '1.0'
|
|
104
|
+
type: :runtime
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '1.0'
|
|
97
111
|
- !ruby/object:Gem::Dependency
|
|
98
112
|
name: dry-logger
|
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -221,7 +235,11 @@ files:
|
|
|
221
235
|
- lib/factorix/api/release.rb
|
|
222
236
|
- lib/factorix/api/tag.rb
|
|
223
237
|
- lib/factorix/api_credential.rb
|
|
238
|
+
- lib/factorix/cache/base.rb
|
|
239
|
+
- lib/factorix/cache/entry.rb
|
|
224
240
|
- lib/factorix/cache/file_system.rb
|
|
241
|
+
- lib/factorix/cache/redis.rb
|
|
242
|
+
- lib/factorix/cache/s3.rb
|
|
225
243
|
- lib/factorix/cli.rb
|
|
226
244
|
- lib/factorix/cli/commands/backup_support.rb
|
|
227
245
|
- lib/factorix/cli/commands/base.rb
|
|
@@ -252,6 +270,7 @@ files:
|
|
|
252
270
|
- lib/factorix/cli/commands/mod/update.rb
|
|
253
271
|
- lib/factorix/cli/commands/mod/upload.rb
|
|
254
272
|
- lib/factorix/cli/commands/path.rb
|
|
273
|
+
- lib/factorix/cli/commands/portal_support.rb
|
|
255
274
|
- lib/factorix/cli/commands/requires_game_stopped.rb
|
|
256
275
|
- lib/factorix/cli/commands/version.rb
|
|
257
276
|
- lib/factorix/container.rb
|
|
@@ -322,7 +341,11 @@ files:
|
|
|
322
341
|
- sig/factorix/api/release.rbs
|
|
323
342
|
- sig/factorix/api/tag.rbs
|
|
324
343
|
- sig/factorix/api_credential.rbs
|
|
344
|
+
- sig/factorix/cache/base.rbs
|
|
345
|
+
- sig/factorix/cache/entry.rbs
|
|
325
346
|
- sig/factorix/cache/file_system.rbs
|
|
347
|
+
- sig/factorix/cache/redis.rbs
|
|
348
|
+
- sig/factorix/cache/s3.rbs
|
|
326
349
|
- sig/factorix/cli.rbs
|
|
327
350
|
- sig/factorix/cli/commands/base.rbs
|
|
328
351
|
- sig/factorix/cli/commands/cache/evict.rbs
|