factorix 0.5.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 +7 -0
- data/CHANGELOG.md +20 -0
- data/LICENSE.txt +21 -0
- data/README.md +105 -0
- data/completion/_factorix.bash +202 -0
- data/completion/_factorix.fish +197 -0
- data/completion/_factorix.zsh +376 -0
- data/doc/factorix.1 +377 -0
- data/exe/factorix +20 -0
- data/lib/factorix/api/category.rb +69 -0
- data/lib/factorix/api/image.rb +35 -0
- data/lib/factorix/api/license.rb +71 -0
- data/lib/factorix/api/mod_download_api.rb +66 -0
- data/lib/factorix/api/mod_info.rb +166 -0
- data/lib/factorix/api/mod_management_api.rb +237 -0
- data/lib/factorix/api/mod_portal_api.rb +204 -0
- data/lib/factorix/api/release.rb +49 -0
- data/lib/factorix/api/tag.rb +95 -0
- data/lib/factorix/api.rb +7 -0
- data/lib/factorix/api_credential.rb +54 -0
- data/lib/factorix/application.rb +218 -0
- data/lib/factorix/cache/file_system.rb +307 -0
- data/lib/factorix/cli/commands/backup_support.rb +46 -0
- data/lib/factorix/cli/commands/base.rb +90 -0
- data/lib/factorix/cli/commands/cache/evict.rb +180 -0
- data/lib/factorix/cli/commands/cache/stat.rb +201 -0
- data/lib/factorix/cli/commands/command_wrapper.rb +71 -0
- data/lib/factorix/cli/commands/completion.rb +83 -0
- data/lib/factorix/cli/commands/confirmable.rb +53 -0
- data/lib/factorix/cli/commands/download_support.rb +123 -0
- data/lib/factorix/cli/commands/launch.rb +79 -0
- data/lib/factorix/cli/commands/man.rb +29 -0
- data/lib/factorix/cli/commands/mod/check.rb +99 -0
- data/lib/factorix/cli/commands/mod/disable.rb +188 -0
- data/lib/factorix/cli/commands/mod/download.rb +291 -0
- data/lib/factorix/cli/commands/mod/edit.rb +114 -0
- data/lib/factorix/cli/commands/mod/enable.rb +216 -0
- data/lib/factorix/cli/commands/mod/image/add.rb +47 -0
- data/lib/factorix/cli/commands/mod/image/edit.rb +41 -0
- data/lib/factorix/cli/commands/mod/image/list.rb +74 -0
- data/lib/factorix/cli/commands/mod/install.rb +443 -0
- data/lib/factorix/cli/commands/mod/list.rb +372 -0
- data/lib/factorix/cli/commands/mod/search.rb +134 -0
- data/lib/factorix/cli/commands/mod/settings/dump.rb +88 -0
- data/lib/factorix/cli/commands/mod/settings/restore.rb +101 -0
- data/lib/factorix/cli/commands/mod/show.rb +202 -0
- data/lib/factorix/cli/commands/mod/sync.rb +299 -0
- data/lib/factorix/cli/commands/mod/uninstall.rb +325 -0
- data/lib/factorix/cli/commands/mod/update.rb +222 -0
- data/lib/factorix/cli/commands/mod/upload.rb +90 -0
- data/lib/factorix/cli/commands/path.rb +79 -0
- data/lib/factorix/cli/commands/requires_game_stopped.rb +32 -0
- data/lib/factorix/cli/commands/version.rb +25 -0
- data/lib/factorix/cli.rb +42 -0
- data/lib/factorix/dependency/edge.rb +89 -0
- data/lib/factorix/dependency/entry.rb +124 -0
- data/lib/factorix/dependency/graph/builder.rb +108 -0
- data/lib/factorix/dependency/graph.rb +210 -0
- data/lib/factorix/dependency/list.rb +244 -0
- data/lib/factorix/dependency/mod_version_requirement.rb +73 -0
- data/lib/factorix/dependency/node.rb +60 -0
- data/lib/factorix/dependency/parser.rb +148 -0
- data/lib/factorix/dependency/validation_result.rb +138 -0
- data/lib/factorix/dependency/validator.rb +190 -0
- data/lib/factorix/errors.rb +112 -0
- data/lib/factorix/formatting.rb +56 -0
- data/lib/factorix/game_version.rb +98 -0
- data/lib/factorix/http/cache_decorator.rb +106 -0
- data/lib/factorix/http/cached_response.rb +37 -0
- data/lib/factorix/http/client.rb +187 -0
- data/lib/factorix/http/response.rb +31 -0
- data/lib/factorix/http/retry_decorator.rb +59 -0
- data/lib/factorix/http/retry_strategy.rb +80 -0
- data/lib/factorix/info_json.rb +90 -0
- data/lib/factorix/installed_mod.rb +239 -0
- data/lib/factorix/mod.rb +55 -0
- data/lib/factorix/mod_list.rb +174 -0
- data/lib/factorix/mod_settings.rb +278 -0
- data/lib/factorix/mod_state.rb +34 -0
- data/lib/factorix/mod_version.rb +99 -0
- data/lib/factorix/portal.rb +185 -0
- data/lib/factorix/progress/download_handler.rb +46 -0
- data/lib/factorix/progress/multi_presenter.rb +45 -0
- data/lib/factorix/progress/presenter.rb +67 -0
- data/lib/factorix/progress/presenter_adapter.rb +46 -0
- data/lib/factorix/progress/scan_handler.rb +33 -0
- data/lib/factorix/progress/upload_handler.rb +33 -0
- data/lib/factorix/runtime/base.rb +233 -0
- data/lib/factorix/runtime/linux.rb +32 -0
- data/lib/factorix/runtime/mac_os.rb +53 -0
- data/lib/factorix/runtime/user_configurable.rb +69 -0
- data/lib/factorix/runtime/windows.rb +85 -0
- data/lib/factorix/runtime/wsl.rb +118 -0
- data/lib/factorix/runtime.rb +32 -0
- data/lib/factorix/save_file.rb +178 -0
- data/lib/factorix/ser_des/deserializer.rb +198 -0
- data/lib/factorix/ser_des/serializer.rb +231 -0
- data/lib/factorix/ser_des/signed_integer.rb +63 -0
- data/lib/factorix/ser_des/unsigned_integer.rb +65 -0
- data/lib/factorix/service_credential.rb +127 -0
- data/lib/factorix/transfer/downloader.rb +162 -0
- data/lib/factorix/transfer/uploader.rb +232 -0
- data/lib/factorix/version.rb +6 -0
- data/lib/factorix.rb +38 -0
- data/sig/dry/auto_inject.rbs +15 -0
- data/sig/dry/cli.rbs +19 -0
- data/sig/dry/configurable.rbs +13 -0
- data/sig/dry/core/container.rbs +17 -0
- data/sig/dry/events/publisher.rbs +22 -0
- data/sig/dry/logger.rbs +16 -0
- data/sig/factorix/api/category.rbs +15 -0
- data/sig/factorix/api/image.rbs +15 -0
- data/sig/factorix/api/license.rbs +20 -0
- data/sig/factorix/api/mod_download_api.rbs +18 -0
- data/sig/factorix/api/mod_info.rbs +67 -0
- data/sig/factorix/api/mod_management_api.rbs +25 -0
- data/sig/factorix/api/mod_portal_api.rbs +31 -0
- data/sig/factorix/api/release.rbs +27 -0
- data/sig/factorix/api/tag.rbs +15 -0
- data/sig/factorix/api.rbs +8 -0
- data/sig/factorix/api_credential.rbs +17 -0
- data/sig/factorix/application.rbs +86 -0
- data/sig/factorix/cache/file_system.rbs +35 -0
- data/sig/factorix/cli/commands/base.rbs +13 -0
- data/sig/factorix/cli/commands/cache/evict.rbs +17 -0
- data/sig/factorix/cli/commands/cache/stat.rbs +17 -0
- data/sig/factorix/cli/commands/command_wrapper.rbs +13 -0
- data/sig/factorix/cli/commands/completion/zsh.rbs +15 -0
- data/sig/factorix/cli/commands/confirmable.rbs +12 -0
- data/sig/factorix/cli/commands/download_support.rbs +12 -0
- data/sig/factorix/cli/commands/launch.rbs +15 -0
- data/sig/factorix/cli/commands/mod/check.rbs +18 -0
- data/sig/factorix/cli/commands/mod/disable.rbs +20 -0
- data/sig/factorix/cli/commands/mod/download.rbs +18 -0
- data/sig/factorix/cli/commands/mod/edit.rbs +30 -0
- data/sig/factorix/cli/commands/mod/enable.rbs +20 -0
- data/sig/factorix/cli/commands/mod/image/add.rbs +19 -0
- data/sig/factorix/cli/commands/mod/image/edit.rbs +19 -0
- data/sig/factorix/cli/commands/mod/image/list.rbs +19 -0
- data/sig/factorix/cli/commands/mod/install.rbs +19 -0
- data/sig/factorix/cli/commands/mod/list.rbs +30 -0
- data/sig/factorix/cli/commands/mod/search.rbs +18 -0
- data/sig/factorix/cli/commands/mod/settings/dump.rbs +17 -0
- data/sig/factorix/cli/commands/mod/settings/restore.rbs +17 -0
- data/sig/factorix/cli/commands/mod/sync.rbs +19 -0
- data/sig/factorix/cli/commands/mod/uninstall.rbs +20 -0
- data/sig/factorix/cli/commands/mod/update.rbs +19 -0
- data/sig/factorix/cli/commands/mod/upload.rbs +24 -0
- data/sig/factorix/cli/commands/path.rbs +18 -0
- data/sig/factorix/cli/commands/requires_game_stopped.rbs +13 -0
- data/sig/factorix/cli/commands/version.rbs +13 -0
- data/sig/factorix/cli.rbs +11 -0
- data/sig/factorix/dependency/edge.rbs +32 -0
- data/sig/factorix/dependency/entry.rbs +30 -0
- data/sig/factorix/dependency/graph/builder.rbs +17 -0
- data/sig/factorix/dependency/graph.rbs +39 -0
- data/sig/factorix/dependency/list.rbs +69 -0
- data/sig/factorix/dependency/mod_version_requirement.rbs +18 -0
- data/sig/factorix/dependency/node.rbs +24 -0
- data/sig/factorix/dependency/parser.rbs +11 -0
- data/sig/factorix/dependency/validation_result.rbs +56 -0
- data/sig/factorix/dependency/validator.rbs +13 -0
- data/sig/factorix/errors.rbs +132 -0
- data/sig/factorix/formatting.rbs +8 -0
- data/sig/factorix/game_version.rbs +24 -0
- data/sig/factorix/http/cache_decorator.rbs +64 -0
- data/sig/factorix/http/client.rbs +55 -0
- data/sig/factorix/http/response.rbs +28 -0
- data/sig/factorix/http/retry_decorator.rbs +44 -0
- data/sig/factorix/http/retry_strategy.rbs +42 -0
- data/sig/factorix/info_json.rbs +19 -0
- data/sig/factorix/installed_mod.rbs +34 -0
- data/sig/factorix/mod.rbs +20 -0
- data/sig/factorix/mod_list.rbs +44 -0
- data/sig/factorix/mod_settings.rbs +47 -0
- data/sig/factorix/mod_state.rbs +18 -0
- data/sig/factorix/mod_version.rbs +23 -0
- data/sig/factorix/portal.rbs +37 -0
- data/sig/factorix/progress/download_handler.rbs +19 -0
- data/sig/factorix/progress/multi_presenter.rbs +15 -0
- data/sig/factorix/progress/presenter.rbs +17 -0
- data/sig/factorix/progress/presenter_adapter.rbs +17 -0
- data/sig/factorix/progress/scan_handler.rbs +16 -0
- data/sig/factorix/progress/upload_handler.rbs +17 -0
- data/sig/factorix/runtime/base.rbs +45 -0
- data/sig/factorix/runtime/linux.rbs +15 -0
- data/sig/factorix/runtime/mac_os.rbs +15 -0
- data/sig/factorix/runtime/user_configurable.rbs +13 -0
- data/sig/factorix/runtime/windows.rbs +23 -0
- data/sig/factorix/runtime/wsl.rbs +19 -0
- data/sig/factorix/runtime.rbs +9 -0
- data/sig/factorix/save_file.rbs +40 -0
- data/sig/factorix/ser_des/deserializer.rbs +49 -0
- data/sig/factorix/ser_des/serializer.rbs +45 -0
- data/sig/factorix/ser_des/signed_integer.rbs +37 -0
- data/sig/factorix/ser_des/unsigned_integer.rbs +37 -0
- data/sig/factorix/service_credential.rbs +19 -0
- data/sig/factorix/transfer/downloader.rbs +15 -0
- data/sig/factorix/transfer/uploader.rbs +21 -0
- data/sig/factorix.rbs +9 -0
- data/sig/tty/progressbar.rbs +18 -0
- metadata +431 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/events"
|
|
4
|
+
require "securerandom"
|
|
5
|
+
require "uri"
|
|
6
|
+
|
|
7
|
+
module Factorix
|
|
8
|
+
module Transfer
|
|
9
|
+
# File uploader with automatic retry
|
|
10
|
+
#
|
|
11
|
+
# Uploads files to given URLs using HTTP multipart/form-data.
|
|
12
|
+
# Uses Transfer::HTTP for the actual upload with event-driven progress notification.
|
|
13
|
+
class Uploader
|
|
14
|
+
# MIME type mapping with default fallback
|
|
15
|
+
MIME_TYPES = Hash.new("application/octet-stream").merge!(
|
|
16
|
+
".zip" => "application/zip",
|
|
17
|
+
".png" => "image/png",
|
|
18
|
+
".jpg" => "image/jpeg",
|
|
19
|
+
".jpeg" => "image/jpeg",
|
|
20
|
+
".gif" => "image/gif"
|
|
21
|
+
).freeze
|
|
22
|
+
private_constant :MIME_TYPES
|
|
23
|
+
|
|
24
|
+
# @!parse
|
|
25
|
+
# # @return [Dry::Logger::Dispatcher]
|
|
26
|
+
# attr_reader :logger
|
|
27
|
+
# # @return [HTTP::Client]
|
|
28
|
+
# attr_reader :client
|
|
29
|
+
include Import[:logger, client: :upload_http_client]
|
|
30
|
+
include Dry::Events::Publisher[:uploader]
|
|
31
|
+
|
|
32
|
+
register_event("upload.started")
|
|
33
|
+
register_event("upload.progress")
|
|
34
|
+
register_event("upload.completed")
|
|
35
|
+
|
|
36
|
+
# Upload a file to the given URL with optional form fields
|
|
37
|
+
#
|
|
38
|
+
# @param url [URI::HTTPS, String] URL to upload to (HTTPS only)
|
|
39
|
+
# @param file_path [Pathname] path to the file to upload
|
|
40
|
+
# @param field_name [String] form field name for the file (default: "file")
|
|
41
|
+
# @param fields [Hash<String, String>] additional form fields (e.g., metadata)
|
|
42
|
+
# @param content_type [:auto, String] MIME type (:auto detects from extension)
|
|
43
|
+
# @return [void]
|
|
44
|
+
# @raise [URLError] if the URL is not HTTPS
|
|
45
|
+
# @raise [ConfigurationError] if file doesn't exist
|
|
46
|
+
# @raise [HTTPClientError] for 4xx errors
|
|
47
|
+
# @raise [HTTPServerError] for 5xx errors
|
|
48
|
+
# @raise [HTTPError] for other HTTP errors
|
|
49
|
+
def upload(url, file_path, field_name: "file", fields: {}, content_type: :auto)
|
|
50
|
+
url = URI(url) if url.is_a?(String)
|
|
51
|
+
unless url.is_a?(URI::HTTPS)
|
|
52
|
+
logger.error("Invalid URL: must be HTTPS", url: url.to_s)
|
|
53
|
+
raise URLError, "URL must be HTTPS"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
unless file_path.exist?
|
|
57
|
+
logger.error("File does not exist", path: file_path.to_s)
|
|
58
|
+
raise ConfigurationError, "File does not exist: #{file_path}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
resolved_content_type = content_type == :auto ? detect_content_type(file_path) : content_type
|
|
62
|
+
upload_file_with_progress(url, file_path, field_name, fields, resolved_content_type)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Detect MIME type from file extension
|
|
66
|
+
#
|
|
67
|
+
# @param file_path [Pathname] file path
|
|
68
|
+
# @return [String] MIME type
|
|
69
|
+
private def detect_content_type(file_path) = MIME_TYPES[file_path.extname.downcase]
|
|
70
|
+
|
|
71
|
+
private def upload_file_with_progress(url, file_path, field_name, fields, content_type)
|
|
72
|
+
boundary = generate_boundary
|
|
73
|
+
file_size = file_path.size
|
|
74
|
+
|
|
75
|
+
publish("upload.started", total_size: file_size)
|
|
76
|
+
|
|
77
|
+
# Build multipart body parts
|
|
78
|
+
body_parts = []
|
|
79
|
+
|
|
80
|
+
# Add additional form fields first
|
|
81
|
+
fields.each do |name, value|
|
|
82
|
+
body_parts << "--#{boundary}\r\n"
|
|
83
|
+
body_parts << %[Content-Disposition: form-data; name="#{name}"\r\n]
|
|
84
|
+
body_parts << "\r\n"
|
|
85
|
+
body_parts << "#{value}\r\n"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Add file field
|
|
89
|
+
body_parts << "--#{boundary}\r\n"
|
|
90
|
+
body_parts << %[Content-Disposition: form-data; name="#{field_name}"; filename="#{file_path.basename}"\r\n]
|
|
91
|
+
body_parts << "Content-Type: #{content_type}\r\n"
|
|
92
|
+
body_parts << "\r\n"
|
|
93
|
+
|
|
94
|
+
# Calculate total size
|
|
95
|
+
header_size = body_parts.join.bytesize
|
|
96
|
+
footer_size = "\r\n--#{boundary}--\r\n".bytesize
|
|
97
|
+
total_size = header_size + file_size + footer_size
|
|
98
|
+
|
|
99
|
+
# Build the multipart stream
|
|
100
|
+
body_stream = build_multipart_stream(body_parts, file_path, boundary)
|
|
101
|
+
|
|
102
|
+
# Wrap in progress tracking IO
|
|
103
|
+
progress_stream = ProgressIO.new(body_stream, total_size) do |uploaded|
|
|
104
|
+
publish("upload.progress", current_size: uploaded, total_size:)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# POST with the multipart stream
|
|
108
|
+
response = client.post(url, body: progress_stream, headers: {"Content-Length" => total_size.to_s}, content_type: "multipart/form-data; boundary=#{boundary}")
|
|
109
|
+
|
|
110
|
+
publish("upload.completed", total_size:)
|
|
111
|
+
response
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Generate a random boundary for multipart/form-data
|
|
115
|
+
#
|
|
116
|
+
# @return [String] boundary string
|
|
117
|
+
private def generate_boundary = "----RubyFormBoundary#{SecureRandom.hex(16)}"
|
|
118
|
+
|
|
119
|
+
# Build a multipart stream from body parts, file, and boundary
|
|
120
|
+
#
|
|
121
|
+
# @param body_parts [Array<String>] header parts
|
|
122
|
+
# @param file_path [Pathname] file to upload
|
|
123
|
+
# @param boundary [String] multipart boundary
|
|
124
|
+
# @return [IO] combined IO stream
|
|
125
|
+
private def build_multipart_stream(body_parts, file_path, boundary)
|
|
126
|
+
header = StringIO.new(body_parts.join)
|
|
127
|
+
file = file_path.open("rb")
|
|
128
|
+
footer = StringIO.new("\r\n--#{boundary}--\r\n")
|
|
129
|
+
|
|
130
|
+
CombinedIO.new(header, file, footer)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Wrapper IO that tracks read progress
|
|
134
|
+
class ProgressIO
|
|
135
|
+
# @param io [IO] underlying IO stream
|
|
136
|
+
# @param total_size [Integer] total size in bytes
|
|
137
|
+
# @yield [Integer] current number of bytes read
|
|
138
|
+
def initialize(io, total_size, &block)
|
|
139
|
+
@io = io
|
|
140
|
+
@total_size = total_size
|
|
141
|
+
@current = 0
|
|
142
|
+
@callback = block
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Read data from underlying IO and track progress
|
|
146
|
+
#
|
|
147
|
+
# @param length [Integer, nil] number of bytes to read
|
|
148
|
+
# @param outbuf [String, nil] output buffer
|
|
149
|
+
# @return [String, nil] read data or nil at EOF
|
|
150
|
+
def read(length=nil, outbuf=nil)
|
|
151
|
+
data = @io.read(length, outbuf)
|
|
152
|
+
if data
|
|
153
|
+
@current += data.bytesize
|
|
154
|
+
@callback&.call(@current)
|
|
155
|
+
end
|
|
156
|
+
data
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Check if at end of stream
|
|
160
|
+
#
|
|
161
|
+
# @return [Boolean] true if at EOF
|
|
162
|
+
def eof? = @io.eof?
|
|
163
|
+
|
|
164
|
+
# Close underlying IO
|
|
165
|
+
#
|
|
166
|
+
# @return [void]
|
|
167
|
+
def close = @io.close
|
|
168
|
+
|
|
169
|
+
# Rewind underlying IO
|
|
170
|
+
#
|
|
171
|
+
# @return [void]
|
|
172
|
+
def rewind
|
|
173
|
+
@io.rewind
|
|
174
|
+
@current = 0
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Get current size
|
|
178
|
+
#
|
|
179
|
+
# @return [Integer] total size
|
|
180
|
+
def size = @total_size
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Combined IO that concatenates multiple IO streams
|
|
184
|
+
class CombinedIO
|
|
185
|
+
# @param ios [Array<IO>] IO streams to concatenate
|
|
186
|
+
def initialize(*ios)
|
|
187
|
+
@ios = ios
|
|
188
|
+
@index = 0
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Read from current IO, advancing to next when exhausted
|
|
192
|
+
#
|
|
193
|
+
# @param length [Integer, nil] number of bytes to read
|
|
194
|
+
# @param outbuf [String, nil] output buffer
|
|
195
|
+
# @return [String, nil] read data or nil at EOF
|
|
196
|
+
def read(length=nil, outbuf=nil)
|
|
197
|
+
return nil if @index >= @ios.size
|
|
198
|
+
|
|
199
|
+
data = @ios[@index].read(length, outbuf)
|
|
200
|
+
if data.nil? || data.empty?
|
|
201
|
+
@index += 1
|
|
202
|
+
return read(length, outbuf)
|
|
203
|
+
end
|
|
204
|
+
data
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Check if all streams are exhausted
|
|
208
|
+
#
|
|
209
|
+
# @return [Boolean] true if at EOF
|
|
210
|
+
def eof? = @index >= @ios.size
|
|
211
|
+
|
|
212
|
+
# Close all IO streams
|
|
213
|
+
#
|
|
214
|
+
# @return [void]
|
|
215
|
+
def close = @ios.each(&:close)
|
|
216
|
+
|
|
217
|
+
# Rewind all streams
|
|
218
|
+
#
|
|
219
|
+
# @return [void]
|
|
220
|
+
def rewind
|
|
221
|
+
@ios.each(&:rewind)
|
|
222
|
+
@index = 0
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Get total size of all streams
|
|
226
|
+
#
|
|
227
|
+
# @return [Integer] total size
|
|
228
|
+
def size = @ios.sum(&:size)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
data/lib/factorix.rb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/auto_inject"
|
|
4
|
+
require "zeitwerk"
|
|
5
|
+
require_relative "factorix/errors"
|
|
6
|
+
require_relative "factorix/version"
|
|
7
|
+
|
|
8
|
+
# Factorix provides a CLI for Factorio MOD management, settings synchronization,
|
|
9
|
+
# and MOD Portal integration.
|
|
10
|
+
module Factorix
|
|
11
|
+
loader = Zeitwerk::Loader.for_gem
|
|
12
|
+
loader.ignore("#{__dir__}/factorix/version.rb")
|
|
13
|
+
loader.ignore("#{__dir__}/factorix/errors.rb")
|
|
14
|
+
loader.inflector.inflect(
|
|
15
|
+
"api" => "API",
|
|
16
|
+
"api_credential" => "APICredential",
|
|
17
|
+
"cli" => "CLI",
|
|
18
|
+
"http" => "HTTP",
|
|
19
|
+
"info_json" => "InfoJSON",
|
|
20
|
+
"installed_mod" => "InstalledMOD",
|
|
21
|
+
"mac_os" => "MacOS",
|
|
22
|
+
"mod" => "MOD",
|
|
23
|
+
"mod_download_api" => "MODDownloadAPI",
|
|
24
|
+
"mod_info" => "MODInfo",
|
|
25
|
+
"mod_management_api" => "MODManagementAPI",
|
|
26
|
+
"mod_list" => "MODList",
|
|
27
|
+
"mod_portal_api" => "MODPortalAPI",
|
|
28
|
+
"mod_settings" => "MODSettings",
|
|
29
|
+
"mod_state" => "MODState",
|
|
30
|
+
"mod_version" => "MODVersion",
|
|
31
|
+
"mod_version_requirement" => "MODVersionRequirement",
|
|
32
|
+
"wsl" => "WSL"
|
|
33
|
+
)
|
|
34
|
+
loader.setup
|
|
35
|
+
|
|
36
|
+
Import = Dry::AutoInject(Application)
|
|
37
|
+
public_constant :Import
|
|
38
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
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 Dry
|
|
6
|
+
module AutoInject
|
|
7
|
+
interface _Builder
|
|
8
|
+
def []: (*String dependencies) -> Module
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.new: (untyped container) -> _Builder
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.AutoInject: (untyped container) -> AutoInject::_Builder
|
|
15
|
+
end
|
data/sig/dry/cli.rbs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
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 Dry
|
|
6
|
+
class CLI
|
|
7
|
+
def initialize: (Class registry) -> void
|
|
8
|
+
|
|
9
|
+
def call: (?Array[String]? arguments) -> void
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module CLI::Registry
|
|
13
|
+
def register: (String command_name, Class command_class, **untyped options) -> void
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class CLI::Command
|
|
17
|
+
def call: (**untyped) -> void
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
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 Dry
|
|
6
|
+
module Configurable
|
|
7
|
+
def setting: (Symbol, ?default: untyped, ?constructor: ^(untyped) -> untyped) ?{ () -> void } -> void
|
|
8
|
+
|
|
9
|
+
def config: () -> untyped
|
|
10
|
+
|
|
11
|
+
def configure: () { (untyped) -> void } -> void
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
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 Dry
|
|
6
|
+
module Core
|
|
7
|
+
module Container
|
|
8
|
+
module Mixin
|
|
9
|
+
def register: (Symbol | String, ?memoize: bool) ?{ () -> untyped } -> void
|
|
10
|
+
|
|
11
|
+
def resolve: (Symbol | String) -> untyped
|
|
12
|
+
|
|
13
|
+
def []: (Symbol | String) -> untyped
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
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 Dry
|
|
6
|
+
module Events
|
|
7
|
+
# Minimal type definition for Dry::Events::Event
|
|
8
|
+
class Event
|
|
9
|
+
def []: (Symbol key) -> untyped
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module Publisher
|
|
13
|
+
def self.[]: (Symbol id) -> Module
|
|
14
|
+
|
|
15
|
+
def subscribe: (untyped listener) -> void
|
|
16
|
+
|
|
17
|
+
def publish: (String event_id, **untyped payload) -> void
|
|
18
|
+
|
|
19
|
+
def self.register_event: (String event_id) -> void
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/sig/dry/logger.rbs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
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 Dry
|
|
6
|
+
module Logger
|
|
7
|
+
# Minimal type definition for Dry::Logger::Dispatcher
|
|
8
|
+
class Dispatcher
|
|
9
|
+
def debug: (String message, **untyped metadata) -> void
|
|
10
|
+
def info: (String message, **untyped metadata) -> void
|
|
11
|
+
def warn: (String message, **untyped metadata) -> void
|
|
12
|
+
def error: (String message, **untyped metadata) -> void
|
|
13
|
+
def fatal: (String message, **untyped metadata) -> void
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
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 API
|
|
7
|
+
class Category
|
|
8
|
+
attr_reader value: String
|
|
9
|
+
attr_reader name: String
|
|
10
|
+
attr_reader description: String
|
|
11
|
+
|
|
12
|
+
def self.for: (String value) -> Category
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
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 API
|
|
7
|
+
class Image
|
|
8
|
+
attr_reader id: String
|
|
9
|
+
attr_reader thumbnail: URI::HTTPS
|
|
10
|
+
attr_reader url: URI::HTTPS
|
|
11
|
+
|
|
12
|
+
def initialize: (id: String, thumbnail: String, url: String) -> void
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
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 API
|
|
7
|
+
class License
|
|
8
|
+
attr_reader id: String
|
|
9
|
+
attr_reader name: String
|
|
10
|
+
attr_reader title: String
|
|
11
|
+
attr_reader description: String
|
|
12
|
+
attr_reader url: URI::HTTPS
|
|
13
|
+
|
|
14
|
+
def self.valid_identifier?: (String value) -> bool
|
|
15
|
+
def self.identifier_values: () -> Array[String]
|
|
16
|
+
|
|
17
|
+
def initialize: (id: String, name: String, title: String, description: String, url: String) -> void
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
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 API
|
|
7
|
+
class MODDownloadAPI
|
|
8
|
+
BASE_URL: String
|
|
9
|
+
|
|
10
|
+
attr_reader downloader: Transfer::Downloader
|
|
11
|
+
attr_reader logger: Dry::Logger::Dispatcher
|
|
12
|
+
|
|
13
|
+
def initialize: (**untyped deps) -> void
|
|
14
|
+
|
|
15
|
+
def download: (String download_url, Pathname output, ?expected_sha1: String?) -> void
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
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 API
|
|
7
|
+
class MODInfo
|
|
8
|
+
attr_reader name: String
|
|
9
|
+
attr_reader title: String
|
|
10
|
+
attr_reader owner: String
|
|
11
|
+
attr_reader summary: String
|
|
12
|
+
attr_reader downloads_count: Integer
|
|
13
|
+
attr_reader category: Category
|
|
14
|
+
attr_reader score: Float
|
|
15
|
+
attr_reader thumbnail: URI::HTTPS?
|
|
16
|
+
attr_reader latest_release: Release?
|
|
17
|
+
attr_reader releases: Array[Release]
|
|
18
|
+
attr_reader detail: MODInfo::Detail?
|
|
19
|
+
|
|
20
|
+
def initialize: (
|
|
21
|
+
name: String,
|
|
22
|
+
title: String,
|
|
23
|
+
owner: String,
|
|
24
|
+
?summary: String?,
|
|
25
|
+
downloads_count: Integer,
|
|
26
|
+
?category: String?,
|
|
27
|
+
?score: Float?,
|
|
28
|
+
?thumbnail: String?,
|
|
29
|
+
?latest_release: Hash[Symbol, untyped]?,
|
|
30
|
+
?releases: Array[Hash[Symbol, untyped]]?,
|
|
31
|
+
**untyped
|
|
32
|
+
) -> void
|
|
33
|
+
|
|
34
|
+
class Detail
|
|
35
|
+
attr_reader changelog: String
|
|
36
|
+
attr_reader created_at: Time
|
|
37
|
+
attr_reader updated_at: Time
|
|
38
|
+
attr_reader last_highlighted_at: Time?
|
|
39
|
+
attr_reader description: String
|
|
40
|
+
attr_reader source_url: URI::HTTPS?
|
|
41
|
+
attr_reader homepage: URI | String
|
|
42
|
+
attr_reader faq: String
|
|
43
|
+
attr_reader tags: Array[Tag]
|
|
44
|
+
attr_reader license: License?
|
|
45
|
+
attr_reader images: Array[Image]
|
|
46
|
+
attr_reader deprecated: bool
|
|
47
|
+
|
|
48
|
+
def initialize: (
|
|
49
|
+
?changelog: String?,
|
|
50
|
+
created_at: String,
|
|
51
|
+
updated_at: String,
|
|
52
|
+
?last_highlighted_at: String?,
|
|
53
|
+
?description: String?,
|
|
54
|
+
?source_url: String?,
|
|
55
|
+
homepage: String,
|
|
56
|
+
?faq: String?,
|
|
57
|
+
?tags: Array[String]?,
|
|
58
|
+
?license: Hash[Symbol, untyped]?,
|
|
59
|
+
?images: Array[Hash[Symbol, untyped]]?,
|
|
60
|
+
?deprecated: bool?
|
|
61
|
+
) -> void
|
|
62
|
+
|
|
63
|
+
def deprecated?: () -> bool
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
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 API
|
|
7
|
+
class MODManagementAPI
|
|
8
|
+
BASE_URL: String
|
|
9
|
+
|
|
10
|
+
attr_reader client: HTTP::Client
|
|
11
|
+
attr_reader uploader: Transfer::Uploader
|
|
12
|
+
attr_reader logger: Dry::Logger::Dispatcher
|
|
13
|
+
|
|
14
|
+
def initialize: (**untyped deps) -> void
|
|
15
|
+
|
|
16
|
+
def init_publish: (String mod_name) -> URI::HTTPS
|
|
17
|
+
def init_upload: (String mod_name) -> URI::HTTPS
|
|
18
|
+
def finish_upload: (String mod_name, URI::HTTPS upload_url, Pathname | String file_path, **untyped metadata) -> void
|
|
19
|
+
def edit_details: (String mod_name, **untyped metadata) -> void
|
|
20
|
+
def init_image_upload: (String mod_name) -> URI::HTTPS
|
|
21
|
+
def finish_image_upload: (String mod_name, URI::HTTPS upload_url, Pathname | String image_file) -> Hash[String, String]
|
|
22
|
+
def edit_images: (String mod_name, Array[String] image_ids) -> void
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
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 API
|
|
7
|
+
class MODPortalAPI
|
|
8
|
+
BASE_URL: String
|
|
9
|
+
|
|
10
|
+
attr_reader logger: Dry::Logger::Dispatcher
|
|
11
|
+
attr_reader cache: Cache::FileSystem
|
|
12
|
+
attr_reader client: HTTP::Client
|
|
13
|
+
|
|
14
|
+
def get_mods: (
|
|
15
|
+
*String namelist,
|
|
16
|
+
?hide_deprecated: bool?,
|
|
17
|
+
?page: Integer?,
|
|
18
|
+
?page_size: (Integer | String)?,
|
|
19
|
+
?sort: ("name" | "created_at" | "updated_at")?,
|
|
20
|
+
?sort_order: ("asc" | "desc")?,
|
|
21
|
+
?version: ("0.13" | "0.14" | "0.15" | "0.16" | "0.17" | "0.18" | "1.0" | "1.1" | "2.0")?
|
|
22
|
+
) -> Hash[String, untyped]
|
|
23
|
+
|
|
24
|
+
def get_mod: (String name) -> Hash[String, untyped]
|
|
25
|
+
|
|
26
|
+
def get_mod_full: (String name) -> Hash[String, untyped]
|
|
27
|
+
|
|
28
|
+
def on_mod_changed: (Dry::Events::Event event) -> void
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
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 API
|
|
7
|
+
class Release
|
|
8
|
+
attr_reader download_url: URI::HTTPS
|
|
9
|
+
attr_reader file_name: String
|
|
10
|
+
attr_reader info_json: Hash[String, untyped]
|
|
11
|
+
attr_reader released_at: Time
|
|
12
|
+
attr_reader version: MODVersion
|
|
13
|
+
attr_reader sha1: String
|
|
14
|
+
attr_reader feature_flags: Array[String]
|
|
15
|
+
|
|
16
|
+
def initialize: (
|
|
17
|
+
download_url: String,
|
|
18
|
+
file_name: String,
|
|
19
|
+
info_json: Hash[String, untyped],
|
|
20
|
+
released_at: String,
|
|
21
|
+
version: String,
|
|
22
|
+
sha1: String,
|
|
23
|
+
?feature_flags: Array[String]
|
|
24
|
+
) -> void
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
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 API
|
|
7
|
+
class Tag
|
|
8
|
+
attr_reader value: String
|
|
9
|
+
attr_reader name: String
|
|
10
|
+
attr_reader description: String
|
|
11
|
+
|
|
12
|
+
def self.for: (String value) -> Tag
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
class APICredential
|
|
7
|
+
def self.load: () -> APICredential
|
|
8
|
+
|
|
9
|
+
def api_key: () -> String
|
|
10
|
+
|
|
11
|
+
def inspect: () -> String
|
|
12
|
+
|
|
13
|
+
def to_s: () -> String
|
|
14
|
+
|
|
15
|
+
def pretty_print: (untyped pp) -> void
|
|
16
|
+
end
|
|
17
|
+
end
|