chore: initial sanitized public snapshot

This commit is contained in:
Aria2 Rust Pro Contributors
2026-07-18 14:04:26 +08:00
commit 7b3816441c
320 changed files with 76813 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "aria2-rust-pro-compat"
version.workspace = true
edition.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
keywords.workspace = true
categories.workspace = true
rust-version.workspace = true
[lib]
name = "aria2_rust_pro_compat"
path = "src/lib.rs"
[lints]
workspace = true
+137
View File
@@ -0,0 +1,137 @@
//! Compatibility inventory and baseline ledger helpers.
use crate::options::{OPTION_SPECS, OptionFamily, OptionSource, OptionStatus};
/// Protocols that the compat layer treats as part of the required surface.
pub const REQUIRED_PROTOCOLS: &[&str] = &[
"cli",
"config",
"json-rpc",
"xml-rpc",
"http",
"https",
"ftp",
"sftp",
"metalink",
"bittorrent",
"magnet",
"docker",
];
/// Compatibility depth for a surfaced feature.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CompatLevel {
/// The feature exists at the API or metadata layer.
Surface,
/// The feature is expected to match legacy behavior.
Behavioral,
/// The feature is expected to be effectively identical to the baseline.
StrictEquivalent,
}
/// Top-level feature areas tracked by the compat ledger.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FeatureSurface {
/// Command-line and config option handling.
Option,
/// Config-file loading and normalization.
Config,
/// RPC method and field compatibility.
Rpc,
/// BitTorrent-related surface area.
Bt,
/// Metalink-related surface area.
Metalink,
/// Session import or export semantics.
Session,
/// Input-file parsing and expansion behavior.
InputFile,
/// Error reporting and mapping behavior.
ErrorMap,
/// Help text and user-facing documentation outputs.
HelpText,
}
/// One row in the compatibility inventory.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CompatLedgerEntry {
/// Canonical item name.
pub name: &'static str,
/// Feature area where the item belongs.
pub surface: FeatureSurface,
/// Expected depth of compatibility for the item.
pub level: CompatLevel,
/// Current implementation status for the item.
pub status: OptionStatus,
/// Short human-readable note describing the item.
pub note: &'static str,
}
/// Free-form compatibility note attached to the ledger.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CompatNote {
/// Stable identifier for the note.
pub id: &'static str,
/// User-facing note text.
pub text: &'static str,
}
/// Full compatibility ledger snapshot.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CompatLedger {
/// Itemized compatibility entries.
pub entries: Vec<CompatLedgerEntry>,
/// Additional notes that summarize current caveats.
pub notes: Vec<CompatNote>,
}
/// Returns the static compatibility notes for the current rewrite snapshot.
#[must_use]
pub fn compatibility_notes() -> Vec<CompatNote> {
vec![
CompatNote {
id: "rapid-rewrite",
text: "Public compatibility surfaces are scaffolded for follow-up behavioral parity.",
},
CompatNote {
id: "bt-options",
text: "BT option family exists with metadata and parser stubs.",
},
CompatNote {
id: "metalink-options",
text: "Metalink option family exists with metadata and parser stubs.",
},
]
}
/// Builds the current compatibility ledger from the option registry.
#[must_use]
pub fn compat_ledger() -> CompatLedger {
let mut entries = Vec::new();
for spec in OPTION_SPECS.iter() {
let surface = match spec.metadata.family {
OptionFamily::Bt => FeatureSurface::Bt,
OptionFamily::Metalink => FeatureSurface::Metalink,
OptionFamily::Rpc => FeatureSurface::Rpc,
OptionFamily::Session => FeatureSurface::Session,
OptionFamily::Input => FeatureSurface::InputFile,
_ => FeatureSurface::Option,
};
let level = match spec.source {
OptionSource::Original => CompatLevel::Behavioral,
OptionSource::Pro
| OptionSource::CompatibilityAlias
| OptionSource::RpcAlias
| OptionSource::Experimental => CompatLevel::Surface,
};
entries.push(CompatLedgerEntry {
name: spec.name,
surface,
level,
status: spec.status,
note: spec.metadata.compatibility_note,
});
}
CompatLedger {
entries,
notes: compatibility_notes(),
}
}
+396
View File
@@ -0,0 +1,396 @@
//! Config parsing and normalization helpers for aria2-style option files.
use crate::options::{OptionScope, option_spec, reserved_option_names};
/// Where a compat config document originated.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ConfigLocationKind {
/// The document was loaded from a file on disk.
File,
/// The document was provided inline as raw text.
Inline,
/// The document originated from an RPC payload.
Rpc,
/// The document originated from environment variables.
Env,
/// The document originated from CLI arguments.
Cli,
}
/// Scope inferred for a config document or directive set.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ConfigScope {
/// Only global options are expected.
Global,
/// Only per-download options are expected.
PerDownload,
/// The document can contain both global and per-download options.
Mixed,
}
/// Source category for parsed config data.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ConfigSource {
/// User-authored config file such as `aria2.conf`.
UserConfig,
/// Persisted session file content.
SessionFile,
/// Input-file content that expands downloads.
InputFile,
/// Runtime overrides originating from transient inputs.
RuntimeOverride,
/// Named profile content.
Profile,
}
/// A single `name=value` config directive.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConfigDirective {
/// Directive name after canonicalization.
pub name: String,
/// Optional directive value.
pub value: Option<String>,
}
/// Parsed config directives with source metadata.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConfigAst {
/// Ordered directives found in the source input.
pub directives: Vec<ConfigDirective>,
/// Origin category for the parsed directives.
pub source: ConfigSource,
}
/// Parsed config document with location metadata.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConfigDocument {
/// Ordered directives found in the document.
pub directives: Vec<ConfigDirective>,
/// Where the document was loaded from.
pub location: ConfigLocationKind,
/// Scope classification for the document.
pub scope: ConfigScope,
}
/// Session save/load compatibility metadata.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SessionFileModel {
/// Path where the session file is stored.
pub session_path: String,
/// Optional input file associated with the session.
pub input_path: Option<String>,
/// Autosave interval for session persistence.
pub autosave_interval_secs: u64,
}
/// Named profile loaded through compat config handling.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConfigProfile {
/// Profile name.
pub name: String,
/// Source category for the profile.
pub source: ConfigSource,
/// Parsed profile document.
pub document: ConfigDocument,
}
/// Errors produced while parsing compat config input.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ConfigParseError {
/// A line could not be parsed as a valid directive.
InvalidDirective(String),
/// A directive that requires a value omitted one.
MissingValue(String),
/// A directive named an unknown option.
UnknownOption(String),
/// A directive used an option name reserved for internal use.
ReservedOption(String),
}
impl std::fmt::Display for ConfigParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::InvalidDirective(line) => write!(f, "invalid config directive: {line}"),
Self::MissingValue(name) => write!(f, "missing value for option: {name}"),
Self::UnknownOption(name) => write!(f, "unknown option: {name}"),
Self::ReservedOption(name) => write!(f, "reserved option name: {name}"),
}
}
}
impl std::error::Error for ConfigParseError {}
/// Canonicalizes a config option name through the option registry.
fn canonicalize_option_name(name: &str) -> String {
let name = normalize_option_token(name);
option_spec(name).map_or_else(|| name.to_owned(), |spec| spec.name.to_owned())
}
/// Removes a UTF-8 byte-order mark when one prefixes a text fragment.
fn strip_utf8_bom(text: &str) -> &str {
text.strip_prefix('\u{feff}').unwrap_or(text)
}
/// Normalizes a CLI- or config-style option token to its raw name form.
fn normalize_option_token(name: &str) -> &str {
let name = strip_utf8_bom(name.trim());
name.strip_prefix("--").unwrap_or_else(|| {
name.strip_prefix('-')
.filter(|value| !value.is_empty())
.map_or(name, |name| name)
})
}
/// Removes trailing comments that are safely separated from a value.
fn strip_safe_trailing_comment(value: &str) -> &str {
for (index, ch) in value.char_indices() {
let Some(prefix) = value.get(..index) else {
continue;
};
if (ch == '#' || ch == ';') && prefix.chars().next_back().is_some_and(char::is_whitespace) {
return prefix.trim_end();
}
}
value.trim()
}
/// Parses a single aria2-style config line, ignoring blank lines and comments.
///
/// # Errors
///
/// Returns [`ConfigParseError`] when the line is malformed or omits a required value.
pub fn parse_config_line(line: &str) -> Result<Option<ConfigDirective>, ConfigParseError> {
let trimmed = strip_utf8_bom(line).trim();
if trimmed.is_empty() || trimmed.starts_with('#') || trimmed.starts_with(';') {
return Ok(None);
}
let (name, value) = trimmed
.split_once('=')
.ok_or_else(|| ConfigParseError::InvalidDirective(trimmed.to_owned()))?;
let name = normalize_option_token(name);
if name.is_empty() {
return Err(ConfigParseError::InvalidDirective(trimmed.to_owned()));
}
let value = strip_safe_trailing_comment(value);
if value.is_empty() {
return Err(ConfigParseError::MissingValue(name.to_owned()));
}
Ok(Some(ConfigDirective {
name: canonicalize_option_name(name),
value: Some(value.to_owned()),
}))
}
/// Parses a single config line and enforces the known-option / non-reserved subset.
///
/// # Errors
///
/// Returns [`ConfigParseError`] when the line is malformed, reserved, or names an unknown option.
pub fn parse_config_line_strict(line: &str) -> Result<Option<ConfigDirective>, ConfigParseError> {
let directive = parse_config_line(line)?;
if let Some(ref d) = directive {
if reserved_option_names().iter().any(|r| r.name == d.name) {
return Err(ConfigParseError::ReservedOption(d.name.clone()));
}
if option_spec(d.name.as_str()).is_none() {
return Err(ConfigParseError::UnknownOption(d.name.clone()));
}
}
Ok(directive)
}
/// Parses a full config document using strict option validation.
///
/// # Errors
///
/// Returns [`ConfigParseError`] when any non-comment line is malformed, reserved, or unknown.
pub fn parse_config(text: &str) -> Result<Vec<ConfigDirective>, ConfigParseError> {
let mut directives = Vec::new();
for line in text.lines() {
if let Some(d) = parse_config_line_strict(line)? {
directives.push(d);
}
}
Ok(directives)
}
/// Parses a full config document while tolerating unknown options.
///
/// # Errors
///
/// Returns [`ConfigParseError`] when any non-comment line is malformed or omits a required value.
pub fn parse_config_lenient(text: &str) -> Result<Vec<ConfigDirective>, ConfigParseError> {
let mut directives = Vec::new();
for line in text.lines() {
if let Some(d) = parse_config_line(line)? {
directives.push(d);
}
}
Ok(directives)
}
/// Infers config scope for a named option when the option is known.
#[must_use]
pub fn infer_scope(name: &str) -> Option<ConfigScope> {
option_spec(name).map(|s| match s.metadata.scope {
OptionScope::Global => ConfigScope::Global,
OptionScope::PerDownload => ConfigScope::PerDownload,
OptionScope::Both => ConfigScope::Mixed,
})
}
/// Returns a document whose directive names have been canonicalized.
#[must_use]
pub fn normalize_document(mut document: ConfigDocument) -> ConfigDocument {
for directive in &mut document.directives {
directive.name = canonicalize_option_name(&directive.name);
}
document
}
/// Loads an inline named profile using lenient parsing semantics.
///
/// # Errors
///
/// Returns [`ConfigParseError`] when the profile text contains malformed directives.
pub fn load_profile(name: &str, text: &str) -> Result<ConfigProfile, ConfigParseError> {
let directives = parse_config_lenient(text)?;
Ok(ConfigProfile {
name: name.to_owned(),
source: ConfigSource::Profile,
document: ConfigDocument {
directives,
location: ConfigLocationKind::Inline,
scope: ConfigScope::Mixed,
},
})
}
#[cfg(test)]
mod tests {
use super::{
ConfigDirective, ConfigDocument, ConfigLocationKind, ConfigParseError, ConfigScope,
ConfigSource, load_profile, normalize_document, parse_config_line,
parse_config_line_strict,
};
#[test]
fn parse_config_line_strict_canonicalizes_known_alias_names() {
let directive = parse_config_line_strict("http-want-digest=true")
.expect("strict alias parse should succeed")
.expect("directive should be present");
assert_eq!(directive.name, "no-want-digest-header");
assert_eq!(directive.value.as_deref(), Some("true"));
}
#[test]
fn parse_config_line_lenient_canonicalizes_known_alias_names() {
let directive = parse_config_line("http-want-digest=true")
.expect("lenient alias parse should succeed")
.expect("directive should be present");
assert_eq!(directive.name, "no-want-digest-header");
assert_eq!(directive.value.as_deref(), Some("true"));
}
#[test]
fn load_profile_keeps_profile_metadata_while_canonicalizing_known_aliases() {
let profile = load_profile(
"demo",
"# comment\nhttp-want-digest=true\nrpc-listen-all=true\n",
)
.expect("profile should load");
assert_eq!(profile.name, "demo");
assert_eq!(profile.source, ConfigSource::Profile);
assert_eq!(profile.document.location, ConfigLocationKind::Inline);
assert_eq!(profile.document.scope, ConfigScope::Mixed);
let [first, second] = profile.document.directives.as_slice() else {
panic!("profile should contain exactly two directives");
};
assert_eq!(first.name, "no-want-digest-header");
assert_eq!(second.name, "rpc-listen-all");
}
#[test]
fn parse_config_line_strict_still_rejects_unknown_options() {
let error = parse_config_line_strict("not-a-real-option=true")
.expect_err("unknown option should still be rejected");
assert_eq!(
error,
ConfigParseError::UnknownOption("not-a-real-option".to_owned())
);
}
#[test]
fn parse_config_line_accepts_bom_and_cli_style_option_spellings() {
let parameterized = parse_config_line_strict("\u{feff}--parameterized-uri=true")
.expect("long CLI spelling should parse")
.expect("directive should be present");
assert_eq!(parameterized.name, "parameterized-uri");
assert_eq!(parameterized.value.as_deref(), Some("true"));
let remote_time = parse_config_line_strict("-R=true")
.expect("short CLI alias should parse")
.expect("directive should be present");
assert_eq!(remote_time.name, "remote-time");
assert_eq!(remote_time.value.as_deref(), Some("true"));
}
#[test]
fn parse_config_line_strips_safe_trailing_comments_but_preserves_uri_fragments() {
let referer = parse_config_line_strict(
"referer=http://example.invalid/download#frag # copied note",
)
.expect("referer with fragment should parse")
.expect("directive should be present");
assert_eq!(referer.name, "referer");
assert_eq!(
referer.value.as_deref(),
Some("http://example.invalid/download#frag")
);
let tracker = parse_config_line("bt-tracker=udp://tracker.invalid:80/announce ; mirror")
.expect("tracker line should parse")
.expect("directive should be present");
assert_eq!(tracker.name, "bt-tracker");
assert_eq!(
tracker.value.as_deref(),
Some("udp://tracker.invalid:80/announce")
);
}
#[test]
fn load_profile_canonicalizes_extended_cli_spellings_and_comments() {
let profile = load_profile(
"compat",
"\u{feff}--select-file=1-3,5 # keep files\n-R=true\n",
)
.expect("profile should load");
let [first, second] = profile.document.directives.as_slice() else {
panic!("profile should contain exactly two directives");
};
assert_eq!(first.name, "select-file");
assert_eq!(first.value.as_deref(), Some("1-3,5"));
assert_eq!(second.name, "remote-time");
assert_eq!(second.value.as_deref(), Some("true"));
}
#[test]
fn normalize_document_canonicalizes_cli_style_and_bom_prefixed_names() {
let normalized = normalize_document(ConfigDocument {
directives: vec![
ConfigDirective {
name: "\u{feff}--parameterized-uri".to_owned(),
value: Some("true".to_owned()),
},
ConfigDirective {
name: "-R".to_owned(),
value: Some("true".to_owned()),
},
],
location: ConfigLocationKind::Inline,
scope: ConfigScope::Mixed,
});
let [first, second] = normalized.directives.as_slice() else {
panic!("normalized document should contain exactly two directives");
};
assert_eq!(first.name, "parameterized-uri");
assert_eq!(second.name, "remote-time");
}
}
+427
View File
@@ -0,0 +1,427 @@
//! Help-text and version-banner rendering for the compat surface.
use std::fmt::Write as _;
use crate::{
BASELINE_COMMIT, PRODUCT_NAME, VERSION,
options::{OptionKind, live_option_specs},
version_line,
};
/// Usage block shown at the top of compat help output.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct UsageSection {
/// Section title or identifier.
pub title: &'static str,
/// Ordered lines rendered in the section.
pub lines: Vec<String>,
}
/// Named help section containing pre-rendered blocks.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HelpSection {
/// Section heading.
pub name: &'static str,
/// Pre-rendered blocks within the section.
pub body: Vec<String>,
}
/// Full help document returned by compat helpers.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HelpDocument {
/// Usage sections rendered before option details.
pub usage: Vec<UsageSection>,
/// Detail sections rendered after usage.
pub sections: Vec<HelpSection>,
}
/// Query selectors accepted by the compat help surface.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum HelpQuery {
/// Request all help entries.
All,
/// Request entries matching a help tag.
Tag(String),
/// Request entries matching a keyword search.
Keyword(String),
}
/// Internal rendered representation of a help option entry.
#[derive(Clone, Debug, Eq, PartialEq)]
struct HelpOptionEntry {
/// Combined CLI switch spellings.
switches: String,
/// User-facing description line.
description: String,
/// Optional human-readable value hints.
possible_values: Option<String>,
/// Optional default value summary.
default_value: Option<String>,
/// Help tags associated with the entry.
tags: Vec<&'static str>,
}
/// Help tags recognized by the compat help renderer.
const ALL_HELP_TAGS: &[&str] = &[
"#basic",
"#advanced",
"#http",
"#https",
"#ftp",
"#metalink",
"#bittorrent",
"#cookie",
"#hook",
"#file",
"#rpc",
"#checksum",
"#experimental",
"#deprecated",
"#help",
"#all",
];
/// Returns the top-level usage section rendered by compat help.
#[must_use]
pub fn usage_sections() -> Vec<UsageSection> {
vec![UsageSection {
title: "main",
lines: vec!["aria2c [OPTIONS] [URI | MAGNET | TORRENT_FILE | METALINK_FILE]...".to_owned()],
}]
}
/// Returns the default help sections for the compat help output.
#[must_use]
pub fn help_sections() -> Vec<HelpSection> {
vec![HelpSection {
name: "Options",
body: render_option_entries(&option_entries()),
}]
}
/// Returns manpage metadata fields exposed by the compat help layer.
#[must_use]
pub fn manpage_metadata() -> Vec<(String, String)> {
vec![
("NAME".to_owned(), PRODUCT_NAME.to_owned()),
("VERSION".to_owned(), version_line()),
("BASELINE_COMMIT".to_owned(), BASELINE_COMMIT.to_owned()),
(
"IMPLEMENTED_OPTION_COUNT".to_owned(),
live_option_specs().len().to_string(),
),
]
}
/// Returns the aria2-style version banner for the compat CLI.
#[must_use]
pub fn cli_version_text() -> String {
let lines = vec![
"aria2 version 1.37.0".to_owned(),
format!("Rust rewrite package: {PRODUCT_NAME} {VERSION}"),
format!("Compatibility baseline: {BASELINE_COMMIT}"),
String::new(),
"** Configuration **".to_owned(),
"Enabled Features: Async DNS, BitTorrent, GZip, HTTPS, Message Digest, Metalink, XML-RPC, SFTP".to_owned(),
"Hash Algorithms: sha-1, sha-224, sha-256, sha-384, sha-512, md5, adler32".to_owned(),
"Libraries: tokio, reqwest, rustls, quick-xml".to_owned(),
format!(
"System: {} ({})",
std::env::consts::OS,
std::env::consts::ARCH
),
String::new(),
"Report bugs to https://github.com/aria2/aria2/issues".to_owned(),
"Visit https://aria2.github.io/".to_owned(),
];
lines.join("\n")
}
/// Returns the default compatibility help text.
#[must_use]
pub fn compatibility_help_text() -> String {
help_text()
}
/// Returns the default rendered help text.
#[must_use]
pub fn help_text() -> String {
help_text_for_query(None)
}
/// Returns rendered help text filtered by an optional query.
#[must_use]
pub fn help_text_for_query(query: Option<&str>) -> String {
render_help(
&HelpDocument {
usage: usage_sections(),
sections: help_sections_for_query(query),
},
query.and_then(parse_help_query),
)
}
/// Builds the internal help-entry list from built-ins and option specs.
fn option_entries() -> Vec<HelpOptionEntry> {
let mut entries = vec![
HelpOptionEntry {
switches: "-v, --version".to_owned(),
description: "Print the version number and exit.".to_owned(),
possible_values: None,
default_value: None,
tags: vec!["#basic"],
},
HelpOptionEntry {
switches: "-h, --help[=TAG|KEYWORD]".to_owned(),
description: "Print usage and exit.".to_owned(),
possible_values: Some(ALL_HELP_TAGS.join(", ")),
default_value: Some("#basic".to_owned()),
tags: vec!["#basic", "#help"],
},
];
entries.extend(live_option_specs().into_iter().map(|spec| HelpOptionEntry {
switches: spec.help_synopsis(),
description: spec.metadata.compatibility_note.to_owned(),
possible_values: possible_values(spec.kind, spec.value_hint(), spec.metadata.validator),
default_value: (!spec.default_value.is_empty()).then(|| spec.default_value.to_owned()),
tags: help_tags_for_option(spec.name, spec.metadata.family, spec.metadata.tags),
}));
entries
}
/// Builds help sections filtered by a parsed query.
fn help_sections_for_query(query: Option<&str>) -> Vec<HelpSection> {
let entries = option_entries();
let filtered = match query.and_then(parse_help_query) {
None | Some(HelpQuery::All) => entries,
Some(HelpQuery::Tag(tag)) => entries
.into_iter()
.filter(|entry| entry.tags.iter().any(|value| *value == tag))
.collect(),
Some(HelpQuery::Keyword(keyword)) => {
let needle = keyword.to_ascii_lowercase();
entries
.into_iter()
.filter(|entry| {
entry.switches.to_ascii_lowercase().contains(&needle)
|| entry.description.to_ascii_lowercase().contains(&needle)
})
.collect()
}
};
vec![HelpSection {
name: "Options",
body: render_option_entries(&filtered),
}]
}
/// Parses a user-facing help query string.
fn parse_help_query(query: &str) -> Option<HelpQuery> {
let trimmed = query.trim();
if trimmed.is_empty() {
return None;
}
if trimmed.eq_ignore_ascii_case("#all") {
return Some(HelpQuery::All);
}
if trimmed.starts_with('#') {
return Some(HelpQuery::Tag(trimmed.to_ascii_lowercase()));
}
Some(HelpQuery::Keyword(trimmed.to_ascii_lowercase()))
}
/// Computes human-readable possible values for a help entry.
fn possible_values(kind: OptionKind, value_hint: &str, validator: &str) -> Option<String> {
match kind {
OptionKind::Bool => Some("true, false".to_owned()),
OptionKind::Path | OptionKind::Text if validator == "any" => None,
OptionKind::Path if validator == "path" || validator == "non-empty path" => {
Some("/path/to/file".to_owned())
}
OptionKind::Text if matches!(value_hint, "FILE" | "COMMAND" | "URI" | "HEADER") => {
Some(value_hint.to_owned())
}
OptionKind::List if value_hint == "URI,..." => Some("URI,...".to_owned()),
OptionKind::List if value_hint == "HOST,..." => Some("HOST,...".to_owned()),
_ if validator.is_empty() || validator == "any" => None,
_ if value_hint == "VALUE" => Some(validator.to_owned()),
_ => Some(value_hint.to_owned()),
}
}
/// Maps option metadata to help tags used by filtered help output.
fn help_tags_for_option(
name: &str,
family: crate::options::OptionFamily,
extra_tags: &[crate::options::OptionTag],
) -> Vec<&'static str> {
let mut tags = vec!["#basic"];
match family {
crate::options::OptionFamily::Core
| crate::options::OptionFamily::Input
| crate::options::OptionFamily::Session => {}
crate::options::OptionFamily::Http => tags.push("#http"),
crate::options::OptionFamily::Ftp | crate::options::OptionFamily::Sftp => tags.push("#ftp"),
crate::options::OptionFamily::Rpc => tags.push("#rpc"),
crate::options::OptionFamily::Bt => tags.push("#bittorrent"),
crate::options::OptionFamily::Metalink => tags.push("#metalink"),
crate::options::OptionFamily::Checksum => tags.push("#checksum"),
crate::options::OptionFamily::Proxy => {
tags.push("#http");
tags.push("#ftp");
}
crate::options::OptionFamily::Security => tags.push("#https"),
crate::options::OptionFamily::Performance => {
if matches!(
name,
"max-overall-download-limit"
| "max-download-limit"
| "max-overall-upload-limit"
| "max-upload-limit"
) {
tags.extend(["#http", "#ftp", "#bittorrent"]);
} else {
tags.extend(["#http", "#ftp"]);
}
}
}
for tag in extra_tags {
match tag {
crate::options::OptionTag::Deprecated => tags.push("#deprecated"),
crate::options::OptionTag::Bt => tags.push("#bittorrent"),
crate::options::OptionTag::Metalink => tags.push("#metalink"),
crate::options::OptionTag::Rpc => tags.push("#rpc"),
crate::options::OptionTag::GlobalOnly | crate::options::OptionTag::PerDownloadOnly => {
tags.push("#advanced");
}
crate::options::OptionTag::InputFile => tags.push("#basic"),
crate::options::OptionTag::SessionFile => tags.push("#advanced"),
crate::options::OptionTag::Alias => tags.push("#experimental"),
crate::options::OptionTag::HighRisk | crate::options::OptionTag::RequiredCompat => {}
}
}
tags.sort_unstable();
tags.dedup();
tags
}
/// Renders each help entry into a block of text.
fn render_option_entries(entries: &[HelpOptionEntry]) -> Vec<String> {
entries.iter().map(format_option_entry).collect()
}
/// Formats one help entry block in an aria2-style layout.
fn format_option_entry(entry: &HelpOptionEntry) -> String {
let mut block = Vec::new();
if entry.switches.len() >= 34 {
block.push(format!(" {}", entry.switches));
block.push(format!(
" {}",
entry.description
));
} else {
block.push(format!(" {:<34}{}", entry.switches, entry.description));
}
if let Some(values) = &entry.possible_values {
block.push(String::new());
block.push(format!(
" Possible Values: {values}"
));
}
if let Some(default_value) = &entry.default_value {
block.push(format!(
" Default: {default_value}"
));
}
if !entry.tags.is_empty() {
block.push(format!(
" Tags: {}",
entry.tags.join(", ")
));
}
block.push(String::new());
block.join("\n")
}
/// Renders a full help document to user-facing text.
fn render_help(document: &HelpDocument, query: Option<HelpQuery>) -> String {
let mut text = String::new();
if let Some(usage_line) = document
.usage
.first()
.and_then(|section| section.lines.first())
{
text.push_str("Usage: ");
text.push_str(usage_line);
text.push('\n');
}
match query {
None | Some(HelpQuery::All) => text.push_str("Printing all options.\n"),
Some(HelpQuery::Tag(tag)) => {
let _ = writeln!(text, "Printing options tagged with \"{tag}\".");
}
Some(HelpQuery::Keyword(keyword)) => {
let _ = writeln!(text, "Printing options whose name includes \"{keyword}\".");
}
}
for section in &document.sections {
text.push_str(section.name);
text.push_str(":\n");
for block in &section.body {
text.push_str(block);
if !block.ends_with('\n') {
text.push('\n');
}
}
}
text.push_str("Refer to man page for more information.\n");
text
}
#[cfg(test)]
mod tests {
use super::{cli_version_text, help_text, help_text_for_query};
#[test]
fn version_text_uses_aria2_style_banner() {
let version = cli_version_text();
assert!(version.contains("aria2 version 1.37.0"));
assert!(version.contains("Rust rewrite package: aria2-rust-pro"));
assert!(version.contains("Enabled Features:"));
}
#[test]
fn help_text_uses_aria2_style_usage_and_options() {
let help = help_text();
assert!(help.starts_with("Usage: aria2c [OPTIONS]"));
assert!(help.contains("Printing all options."));
assert!(help.contains("Options:"));
assert!(help.contains("-h, --help[=TAG|KEYWORD]"));
assert!(help.contains("--retry-on-400[=true|false]"));
assert!(help.contains("Refer to man page for more information."));
}
#[test]
fn help_text_for_tag_filters_to_matching_entries() {
let help = help_text_for_query(Some("#http"));
assert!(help.contains("Printing options tagged with \"#http\"."));
assert!(help.contains("--user-agent=VALUE, -U"));
assert!(help.contains("--retry-on-400[=true|false]"));
assert!(!help.contains("--bt-save-metadata[=true|false]"));
}
#[test]
fn help_text_for_keyword_filters_to_matching_entries() {
let help = help_text_for_query(Some("rpc"));
assert!(help.contains("Printing options whose name includes \"rpc\"."));
assert!(help.contains("--rpc-listen-port=PORT"));
assert!(help.contains("--rpc-secret=VALUE"));
assert!(!help.contains("--bt-tracker=URI,..."));
}
}
+133
View File
@@ -0,0 +1,133 @@
//! Compatibility-facing metadata and helpers for `aria2-rust-pro`.
//!
//! This crate centralizes the option registry, config parsing surface, help
//! text scaffolding, and compatibility bookkeeping that mirror the historical
//! `aria2` user-facing contract.
#![forbid(unsafe_code)]
/// Compatibility ledger types and baseline coverage metadata.
pub mod compat;
/// Config parsing and normalization helpers for aria2-style inputs.
pub mod config;
/// Help-text rendering and CLI version banner helpers.
pub mod help;
/// Canonical option metadata used by the compat surface.
pub mod options;
pub use compat::{
CompatLedger, CompatLedgerEntry, CompatLevel, CompatNote, FeatureSurface, REQUIRED_PROTOCOLS,
compatibility_notes,
};
pub use config::{
ConfigAst, ConfigDirective, ConfigDocument, ConfigLocationKind, ConfigParseError,
ConfigProfile, ConfigScope, ConfigSource, SessionFileModel, parse_config, parse_config_lenient,
parse_config_line, parse_config_line_strict,
};
pub use help::{
HelpDocument, HelpQuery, HelpSection, UsageSection, cli_version_text, compatibility_help_text,
help_text, help_text_for_query, manpage_metadata,
};
pub use options::{
OPTION_SPECS, OptionFamily, OptionKind, OptionMetadata, OptionParser, OptionScope,
OptionSource, OptionSpec, OptionStatus, OptionTag, ReservedOptionName, env_var_for_option,
global_option_specs, is_required_pro_option, option_spec, per_download_option_specs,
reserved_option_names, rpc_option_name,
};
/// Commit hash for the upstream baseline used by the compat layer.
pub const BASELINE_COMMIT: &str = "1f1323128cae942f5440c035cb5f42788b3de33f";
/// Product name shown by compat-oriented outputs.
pub const PRODUCT_NAME: &str = "aria2-rust-pro";
/// Crate version exposed by compatibility banners.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// Errors produced while translating older compatibility inputs.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CompatError {
/// The requested option name is not part of the compat registry.
UnknownOption(String),
/// The requested protocol name is not part of the required surface.
UnknownProtocol(String),
/// A config line could not be interpreted as a valid directive.
InvalidConfigDirective(String),
/// A config option that requires a value was provided without one.
MissingConfigValue(String),
/// A named option received an invalid value.
InvalidValue {
/// Canonical option name that failed validation.
option: String,
/// Raw value that failed validation.
value: String,
/// Human-readable validation failure detail.
reason: String,
},
/// A compat-only alias or deprecated switch was encountered.
DeprecatedOption {
/// Deprecated option spelling.
option: String,
/// Replacement spelling when one exists.
replacement: Option<String>,
},
}
impl std::fmt::Display for CompatError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnknownOption(name) => write!(f, "unknown option: {name}"),
Self::UnknownProtocol(name) => write!(f, "unknown protocol: {name}"),
Self::InvalidConfigDirective(line) => write!(f, "invalid config directive: {line}"),
Self::MissingConfigValue(name) => write!(f, "missing value for option: {name}"),
Self::InvalidValue {
option,
value,
reason,
} => write!(f, "invalid value for {option}: {value} ({reason})"),
Self::DeprecatedOption {
option,
replacement,
} => {
if let Some(replacement) = replacement {
write!(f, "deprecated option: {option} (use {replacement})")
} else {
write!(f, "deprecated option: {option}")
}
}
}
}
}
impl std::error::Error for CompatError {}
/// Returns the standard version banner for the compat surface.
#[must_use]
pub fn version_line() -> String {
format!("{PRODUCT_NAME} {VERSION} (compat baseline {BASELINE_COMMIT})")
}
/// Returns whether a protocol belongs to the required compatibility baseline.
#[must_use]
pub fn is_required_protocol(protocol: &str) -> bool {
REQUIRED_PROTOCOLS.contains(&protocol)
}
/// Maps a config or CLI option spelling to its canonical option name.
#[must_use]
pub fn normalize_option_name(name: &str) -> Option<&'static str> {
option_spec(name).map(|spec| spec.name)
}
/// Maps any known option spelling to its canonical RPC field name.
#[must_use]
pub fn normalize_rpc_option_name(name: &str) -> Option<&'static str> {
rpc_option_name(name)
}
/// Rewrites directive names in-place to their canonical registry spellings.
pub fn normalize_config_document(document: &mut ConfigDocument) {
for directive in &mut document.directives {
if let Some(canonical) = normalize_option_name(&directive.name) {
directive.name = canonical.to_owned();
}
}
}
@@ -0,0 +1,26 @@
//! Canonical option registry for the compat surface.
/// Shared option data model used by the compat registry and query helpers.
mod model;
/// Lookup and filtering helpers for canonical, scoped, and RPC option spellings.
mod query;
/// Static aria2-compatible option specifications exposed by the compat layer.
mod registry;
/// Internal option names reserved for compat-layer metadata.
mod reserved;
pub use self::model::{
OptionFamily, OptionKind, OptionMetadata, OptionParser, OptionScope, OptionSource, OptionSpec,
OptionStatus, OptionTag,
};
pub use self::query::{
env_var_for_option, global_option_specs, is_live_option_status, is_required_pro_option,
live_option_specs, option_spec, per_download_option_specs, reserved_option_names,
rpc_option_name,
};
pub use self::registry::OPTION_SPECS;
pub use self::reserved::{RESERVED_OPTION_NAMES, ReservedOptionName};
#[cfg(test)]
/// Regression coverage for compat option registry behavior.
mod tests;
@@ -0,0 +1,316 @@
//! Canonical option registry for the compat surface.
use std::fmt;
/// High-level value kind for an option.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OptionKind {
/// Boolean on/off value.
Bool,
/// Signed or unsigned integral value.
Integer,
/// Byte-size value such as `1M`.
Size,
/// Duration value such as seconds.
Duration,
/// Free-form text value.
Text,
/// Floating-point numeric value.
Float,
/// Filesystem path value.
Path,
/// Closed set of named values.
Enum,
/// Comma-separated list-like value.
List,
}
impl fmt::Display for OptionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Bool => f.write_str("bool"),
Self::Integer => f.write_str("integer"),
Self::Size => f.write_str("size"),
Self::Duration => f.write_str("duration"),
Self::Text => f.write_str("text"),
Self::Float => f.write_str("float"),
Self::Path => f.write_str("path"),
Self::Enum => f.write_str("enum"),
Self::List => f.write_str("list"),
}
}
}
/// Provenance for an option specification.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OptionSource {
/// Native upstream aria2 option.
Original,
/// Option introduced by `aria2-rust-pro`.
Pro,
/// Long-form alias kept for compatibility.
CompatibilityAlias,
/// RPC-facing alias kept for compatibility.
RpcAlias,
/// Experimental surface that may still change.
Experimental,
}
/// Implementation status for an option surface.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OptionStatus {
/// Option is planned but not yet implemented.
Planned,
/// Option is implemented but not fully verified.
Implemented,
/// Option is implemented and verified.
Verified,
/// Option remains available but is deprecated.
Deprecated,
/// Option was intentionally removed from the live surface.
Removed,
}
/// Placement scope for an option.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OptionScope {
/// Option is only valid globally.
Global,
/// Option is only valid per download.
PerDownload,
/// Option is valid in both scopes.
Both,
}
/// Functional family used for grouping and help tagging.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OptionFamily {
/// Core download behavior.
Core,
/// HTTP-specific behavior.
Http,
/// FTP-specific behavior.
Ftp,
/// SFTP-specific behavior.
Sftp,
/// RPC server behavior.
Rpc,
/// `BitTorrent` behavior.
Bt,
/// Metalink behavior.
Metalink,
/// Session import or save behavior.
Session,
/// Input-file behavior.
Input,
/// Checksum-related behavior.
Checksum,
/// Proxy-related behavior.
Proxy,
/// TLS and certificate behavior.
Security,
/// Performance and throughput behavior.
Performance,
}
/// Fine-grained compatibility tags attached to option metadata.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OptionTag {
/// Required to cover the targeted compatibility baseline.
RequiredCompat,
/// High-risk option that benefits from extra care.
HighRisk,
/// Option spelling is deprecated.
Deprecated,
/// Option acts as a compatibility alias.
Alias,
/// Option participates in the RPC surface.
Rpc,
/// Option participates in the `BitTorrent` surface.
Bt,
/// Option participates in the Metalink surface.
Metalink,
/// Option belongs in session files.
SessionFile,
/// Option belongs in input files.
InputFile,
/// Option is only valid globally.
GlobalOnly,
/// Option is only valid per download.
PerDownloadOnly,
}
/// Parser shape used for user-facing validation hints.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OptionParser {
/// Boolean parser.
Boolean,
/// Integer parser.
Integer,
/// Size parser.
Size,
/// Duration parser.
Duration,
/// Free-form text parser.
Text,
/// Comma-separated list parser.
Csv,
/// Enum parser.
Enum,
/// URI-list parser.
UriList,
/// Filesystem path parser.
Path,
/// Repeated header parser.
Headers,
/// `key=value` parser.
KeyValue,
}
/// Supplemental metadata attached to an option specification.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct OptionMetadata {
/// Scope where the option is valid.
pub scope: OptionScope,
/// Functional family for grouping and help tagging.
pub family: OptionFamily,
/// Parser shape used for validation and help text.
pub parser: OptionParser,
/// Extra compatibility tags attached to the option.
pub tags: &'static [OptionTag],
/// Human-readable validator summary.
pub validator: &'static str,
/// Short source description for the option origin.
pub source_text: &'static str,
/// Brief compat-oriented description for help and ledger output.
pub compatibility_note: &'static str,
}
/// Canonical registry entry for a compat option.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct OptionSpec {
/// Canonical option name.
pub name: &'static str,
/// High-level option value kind.
pub kind: OptionKind,
/// Default value shown by help and metadata.
pub default_value: &'static str,
/// Provenance for the option surface.
pub source: OptionSource,
/// Current implementation status.
pub status: OptionStatus,
/// CLI aliases accepted for the option.
pub aliases: &'static [&'static str],
/// RPC names accepted for the option.
pub rpc_names: &'static [&'static str],
/// Supplemental metadata for the option.
pub metadata: OptionMetadata,
}
impl OptionSpec {
/// Returns whether the option carries a given compatibility tag.
#[must_use]
pub fn has_tag(&self, tag: OptionTag) -> bool {
self.metadata.tags.contains(&tag)
}
/// Returns all accepted CLI spellings for the option.
#[must_use]
pub fn cli_spellings(&self) -> Vec<String> {
let mut spellings = vec![format!("--{}", self.name)];
for alias in self.aliases {
if alias.len() == 1 {
spellings.push(format!("-{alias}"));
} else {
spellings.push(format!("--{alias}"));
}
}
spellings
}
/// Returns config-file spellings for the option, excluding short aliases.
#[must_use]
pub fn config_spellings(&self) -> Vec<&'static str> {
let mut spellings = vec![self.name];
for alias in self.aliases {
if alias.len() > 1 && !spellings.contains(alias) {
spellings.push(alias);
}
}
spellings
}
/// Returns all accepted lookup spellings across CLI aliases and RPC names.
#[must_use]
pub fn lookup_spellings(&self) -> Vec<&'static str> {
let mut spellings = vec![self.name];
for alias in self.aliases {
if !spellings.contains(alias) {
spellings.push(alias);
}
}
for rpc_name in self.rpc_names {
if !spellings.contains(rpc_name) {
spellings.push(rpc_name);
}
}
spellings
}
/// Returns the human-readable value hint used by help rendering.
#[must_use]
pub fn value_hint(&self) -> &'static str {
if self.metadata.validator.contains('|') {
return self.metadata.validator;
}
match self.metadata.parser {
OptionParser::Boolean => "true|false",
OptionParser::Integer => {
if self.name.ends_with("-port") {
"PORT"
} else {
"NUM"
}
}
OptionParser::Size => "SIZE",
OptionParser::Duration => "SEC",
OptionParser::Text => match self.metadata.validator {
"command string" => "COMMAND",
"proxy url" => "URI",
"filename-safe" => "FILE",
_ => "VALUE",
},
OptionParser::Csv => match self.name {
"bt-tracker" => "URI,...",
"no-proxy" => "HOST,...",
"select-file" => "INDEX,...",
_ => "VALUE,...",
},
OptionParser::Enum => self.metadata.validator,
OptionParser::UriList => "URI,...",
OptionParser::Path => "PATH",
OptionParser::Headers => "HEADER",
OptionParser::KeyValue => "KEY=VALUE",
}
}
/// Returns the help synopsis rendered for the option.
#[must_use]
pub fn help_synopsis(&self) -> String {
let mut synopsis = format!("--{}", self.name);
let value_hint = self.value_hint();
if self.kind == OptionKind::Bool {
synopsis.push_str("[=");
synopsis.push_str(value_hint);
synopsis.push(']');
} else {
synopsis.push('=');
synopsis.push_str(value_hint);
}
let aliases = self.cli_spellings();
if let Some((_, extra_aliases)) = aliases.split_first()
&& !extra_aliases.is_empty()
{
synopsis.push_str(", ");
synopsis.push_str(&extra_aliases.join(", "));
}
synopsis
}
}
@@ -0,0 +1,77 @@
use super::registry::OPTION_SPECS;
use super::reserved::{RESERVED_OPTION_NAMES, ReservedOptionName};
use super::{OptionScope, OptionSource, OptionSpec, OptionStatus};
/// Returns the canonical option specification for a known spelling.
#[must_use]
pub fn option_spec(name: &str) -> Option<&'static OptionSpec> {
OPTION_SPECS
.iter()
.find(|s| s.name == name)
.or_else(|| OPTION_SPECS.iter().find(|s| s.aliases.contains(&name)))
}
/// Returns whether an option is required by the `aria2-rust-pro` surface.
#[must_use]
pub fn is_required_pro_option(option: &str) -> bool {
OPTION_SPECS.iter().any(|s| {
s.name == option
&& (s.source == OptionSource::Pro || s.source == OptionSource::CompatibilityAlias)
})
}
/// Returns whether a status should be exposed in live option listings.
#[must_use]
pub const fn is_live_option_status(status: OptionStatus) -> bool {
matches!(
status,
OptionStatus::Implemented | OptionStatus::Verified | OptionStatus::Deprecated
)
}
/// Filters the registry while preserving canonical-name uniqueness.
fn unique_option_specs(predicate: impl Fn(&OptionSpec) -> bool) -> Vec<&'static OptionSpec> {
let mut seen = std::collections::BTreeSet::new();
OPTION_SPECS
.iter()
.filter(|spec| predicate(spec) && seen.insert(spec.name))
.collect()
}
/// Returns all live option specs without duplicate canonical names.
#[must_use]
pub fn live_option_specs() -> Vec<&'static OptionSpec> {
unique_option_specs(|spec| is_live_option_status(spec.status))
}
/// Returns all options available in the global scope.
#[must_use]
pub fn global_option_specs() -> Vec<&'static OptionSpec> {
unique_option_specs(|spec| {
matches!(spec.metadata.scope, OptionScope::Global | OptionScope::Both)
})
}
/// Returns all options available in the per-download scope.
#[must_use]
pub fn per_download_option_specs() -> Vec<&'static OptionSpec> {
unique_option_specs(|spec| {
matches!(
spec.metadata.scope,
OptionScope::PerDownload | OptionScope::Both
)
})
}
/// Returns the reserved option-name table.
#[must_use]
pub const fn reserved_option_names() -> &'static [ReservedOptionName] {
RESERVED_OPTION_NAMES
}
/// Returns the canonical RPC option name for a known spelling.
#[must_use]
pub fn rpc_option_name(name: &str) -> Option<&'static str> {
option_spec(name).and_then(|s| s.rpc_names.first().copied())
}
/// Returns the environment-variable name associated with an option.
#[must_use]
pub fn env_var_for_option(name: &str) -> Option<String> {
option_spec(name).map(|s| format!("ARIA2_{}", s.name.replace('-', "_").to_ascii_uppercase()))
}
@@ -0,0 +1,53 @@
use std::sync::LazyLock;
use super::{
OptionFamily, OptionKind, OptionMetadata, OptionParser, OptionScope, OptionSource, OptionSpec,
OptionStatus, OptionTag,
};
/// Shared tag slice for per-download-only options.
const TAG_PER: &[OptionTag] = &[OptionTag::PerDownloadOnly];
/// Shared tag slice for RPC options.
const TAG_RPC: &[OptionTag] = &[OptionTag::Rpc];
/// Shared tag slice for `BitTorrent` options.
const TAG_BT: &[OptionTag] = &[OptionTag::Bt];
/// Shared tag slice for Metalink options.
const TAG_METALINK: &[OptionTag] = &[OptionTag::Metalink];
/// Shared tag slice for compatibility aliases.
const TAG_ALIAS: &[OptionTag] = &[OptionTag::Alias];
/// Shared tag slice for global-only options.
const TAG_GLOBAL: &[OptionTag] = &[OptionTag::GlobalOnly];
/// Option entries that extend the baseline registry with compatibility extras.
mod compatibility_extension_entries;
/// Foundational core, RPC, and BT registry entries used across the compat layer.
mod foundational_entries;
/// Hook, proxy, TLS, and RPC-adjacent registry entries.
mod hooks_and_rpc_entries;
/// Transfer-tuning and performance-oriented registry entries.
mod transfer_tuning_entries;
use self::{
compatibility_extension_entries::COMPATIBILITY_EXTENSION_ENTRIES,
foundational_entries::FOUNDATIONAL_ENTRIES, hooks_and_rpc_entries::HOOKS_AND_RPC_ENTRIES,
transfer_tuning_entries::TRANSFER_TUNING_ENTRIES,
};
/// Builds the flattened compat registry once from the semantic entry groups.
fn build_option_specs() -> Box<[OptionSpec]> {
let total_len = FOUNDATIONAL_ENTRIES
.len()
.checked_add(HOOKS_AND_RPC_ENTRIES.len())
.and_then(|value| value.checked_add(TRANSFER_TUNING_ENTRIES.len()))
.and_then(|value| value.checked_add(COMPATIBILITY_EXTENSION_ENTRIES.len()))
.expect("compat option registry entry count should fit in usize");
let mut flattened = Vec::with_capacity(total_len);
flattened.extend_from_slice(FOUNDATIONAL_ENTRIES);
flattened.extend_from_slice(HOOKS_AND_RPC_ENTRIES);
flattened.extend_from_slice(TRANSFER_TUNING_ENTRIES);
flattened.extend_from_slice(COMPATIBILITY_EXTENSION_ENTRIES);
flattened.into_boxed_slice()
}
/// Canonical compat option registry.
pub static OPTION_SPECS: LazyLock<Box<[OptionSpec]>> = LazyLock::new(build_option_specs);
@@ -0,0 +1,368 @@
use super::{
OptionFamily, OptionKind, OptionMetadata, OptionParser, OptionScope, OptionSource, OptionSpec,
OptionStatus, OptionTag, TAG_ALIAS, TAG_GLOBAL, TAG_PER,
};
/// Compatibility-extension entries layered onto the canonical compat registry.
pub(super) const COMPATIBILITY_EXTENSION_ENTRIES: &[OptionSpec] = &[
OptionSpec {
name: "pause",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["pause"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Core,
parser: OptionParser::Boolean,
tags: TAG_PER,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "start in paused state after registration",
},
},
OptionSpec {
name: "dry-run",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["dry-run"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Core,
parser: OptionParser::Boolean,
tags: TAG_PER,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "validate target reachability without committing download data",
},
},
OptionSpec {
name: "on-download-pause",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["on-download-pause"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Core,
parser: OptionParser::Text,
tags: TAG_GLOBAL,
validator: "command string",
source_text: "aria2 option",
compatibility_note: "pause hook command",
},
},
OptionSpec {
name: "checksum",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["checksum"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Checksum,
parser: OptionParser::KeyValue,
tags: TAG_PER,
validator: "TYPE=DIGEST",
source_text: "aria2 option",
compatibility_note: "expected file digest supplied at add time",
},
},
OptionSpec {
name: "select-file",
kind: OptionKind::List,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["select-file"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Bt,
parser: OptionParser::Csv,
tags: &[OptionTag::Bt, OptionTag::PerDownloadOnly],
validator: "torrent file indexes",
source_text: "aria2 option",
compatibility_note: "choose torrent file indexes or ranges to download",
},
},
OptionSpec {
name: "bt-remove-unselected-file",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["bt-remove-unselected-file"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Bt,
parser: OptionParser::Boolean,
tags: &[OptionTag::Bt, OptionTag::PerDownloadOnly],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "delete skipped torrent files when selection is active",
},
},
OptionSpec {
name: "metalink-base-uri",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["metalink-base-uri"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Metalink,
parser: OptionParser::Text,
tags: &[OptionTag::Metalink, OptionTag::PerDownloadOnly],
validator: "any",
source_text: "aria2 option",
compatibility_note: "base URI used to resolve relative Metalink resources",
},
},
OptionSpec {
name: "remote-time",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &["R"],
rpc_names: &["remote-time"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Boolean,
tags: &[],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "persist remote timestamp on the output file",
},
},
OptionSpec {
name: "rpc-user",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-user"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Text,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "any",
source_text: "aria2 option",
compatibility_note: "legacy basic-auth rpc username",
},
},
OptionSpec {
name: "rpc-passwd",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-passwd"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Text,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "any",
source_text: "aria2 option",
compatibility_note: "legacy basic-auth rpc password",
},
},
OptionSpec {
name: "rpc-max-request-size",
kind: OptionKind::Size,
default_value: "2M",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-max-request-size"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Size,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "maximum accepted rpc request payload size",
},
},
OptionSpec {
name: "rpc-allow-origin-all",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-allow-origin-all"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Boolean,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "allow any origin for browser rpc access",
},
},
OptionSpec {
name: "rpc-certificate",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-certificate"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Path,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "path",
source_text: "aria2 option",
compatibility_note: "tls certificate for secure rpc mode",
},
},
OptionSpec {
name: "rpc-private-key",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-private-key"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Path,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "path",
source_text: "aria2 option",
compatibility_note: "tls private key for secure rpc mode",
},
},
OptionSpec {
name: "rpc-secure",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-secure"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Boolean,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "serve rpc over tls",
},
},
OptionSpec {
name: "rpc-save-upload-metadata",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-save-upload-metadata"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Boolean,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "persist uploaded torrent or metalink metadata",
},
},
OptionSpec {
name: "input-file",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &["i"],
rpc_names: &["input-file"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Input,
parser: OptionParser::Path,
tags: &[OptionTag::InputFile, OptionTag::GlobalOnly],
validator: "existing path",
source_text: "aria2 option",
compatibility_note: "load uri list from file",
},
},
OptionSpec {
name: "save-session",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["save-session"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Session,
parser: OptionParser::Path,
tags: &[OptionTag::SessionFile, OptionTag::GlobalOnly],
validator: "writable path",
source_text: "aria2 option",
compatibility_note: "save active tasks on exit",
},
},
OptionSpec {
name: "save-session-interval",
kind: OptionKind::Duration,
default_value: "0",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["save-session-interval"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Session,
parser: OptionParser::Duration,
tags: &[OptionTag::SessionFile, OptionTag::GlobalOnly],
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "periodic session flush interval",
},
},
OptionSpec {
name: "no-want-digest-header",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Pro,
status: OptionStatus::Implemented,
aliases: &["http-want-digest"],
rpc_names: &["no-want-digest-header", "http-want-digest"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Boolean,
tags: TAG_ALIAS,
validator: "bool",
source_text: "aria2-rust-pro",
compatibility_note: "compat switch for digest header behavior",
},
},
];
@@ -0,0 +1,422 @@
use super::{
OptionFamily, OptionKind, OptionMetadata, OptionParser, OptionScope, OptionSource, OptionSpec,
OptionStatus, OptionTag, TAG_BT, TAG_GLOBAL, TAG_PER, TAG_RPC,
};
/// Foundational option entries that anchor the compat registry surface.
pub(super) const FOUNDATIONAL_ENTRIES: &[OptionSpec] = &[
OptionSpec {
name: "dir",
kind: OptionKind::Path,
default_value: ".",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &[],
rpc_names: &["dir"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Core,
parser: OptionParser::Path,
tags: TAG_PER,
validator: "non-empty path",
source_text: "aria2 option",
compatibility_note: "download target directory",
},
},
OptionSpec {
name: "out",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &[],
rpc_names: &["out"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Core,
parser: OptionParser::Text,
tags: TAG_PER,
validator: "filename-safe",
source_text: "aria2 option",
compatibility_note: "output file name override",
},
},
OptionSpec {
name: "split",
kind: OptionKind::Integer,
default_value: "5",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &[],
rpc_names: &["split"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Performance,
parser: OptionParser::Integer,
tags: TAG_PER,
validator: ">=1",
source_text: "aria2 option",
compatibility_note: "piece split count",
},
},
OptionSpec {
name: "max-concurrent-downloads",
kind: OptionKind::Integer,
default_value: "5",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &["j"],
rpc_names: &["max-concurrent-downloads"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Performance,
parser: OptionParser::Integer,
tags: TAG_GLOBAL,
validator: ">=1",
source_text: "aria2 option",
compatibility_note: "maximum number of active downloads",
},
},
OptionSpec {
name: "continue",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &["c"],
rpc_names: &["continue"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Core,
parser: OptionParser::Boolean,
tags: TAG_PER,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "resume partial download",
},
},
OptionSpec {
name: "pause",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["pause"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Core,
parser: OptionParser::Boolean,
tags: TAG_PER,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "add download in paused state",
},
},
OptionSpec {
name: "allow-overwrite",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["allow-overwrite"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Core,
parser: OptionParser::Boolean,
tags: TAG_PER,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "allow overwriting existing destination files",
},
},
OptionSpec {
name: "checksum",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["checksum"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Checksum,
parser: OptionParser::KeyValue,
tags: TAG_PER,
validator: "algorithm=value",
source_text: "aria2 option",
compatibility_note: "expected checksum for content verification",
},
},
OptionSpec {
name: "parameterized-uri",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &["P"],
rpc_names: &["parameterized-uri"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Input,
parser: OptionParser::Boolean,
tags: &[OptionTag::InputFile, OptionTag::PerDownloadOnly],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "treat input URIs as parameterized templates",
},
},
OptionSpec {
name: "remote-time",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &["R"],
rpc_names: &["remote-time"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Http,
parser: OptionParser::Boolean,
tags: TAG_PER,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "preserve remote Last-Modified timestamp",
},
},
OptionSpec {
name: "referer",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["referer"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Http,
parser: OptionParser::Text,
tags: TAG_PER,
validator: "URI",
source_text: "aria2 option",
compatibility_note: "HTTP referer header override",
},
},
OptionSpec {
name: "enable-rpc",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &[],
rpc_names: &["enable-rpc"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Boolean,
tags: TAG_RPC,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "enable rpc server",
},
},
OptionSpec {
name: "rpc-listen-port",
kind: OptionKind::Integer,
default_value: "6800",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &[],
rpc_names: &["rpc-listen-port"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Integer,
tags: TAG_RPC,
validator: "1..65535",
source_text: "aria2 option",
compatibility_note: "rpc tcp port",
},
},
OptionSpec {
name: "rpc-listen-all",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-listen-all"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Boolean,
tags: TAG_RPC,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "bind rpc server to all interfaces",
},
},
OptionSpec {
name: "rpc-allow-origin-all",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-allow-origin-all"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Boolean,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "allow any Origin header on RPC responses",
},
},
OptionSpec {
name: "rpc-secure",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-secure"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Boolean,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "enable TLS on the RPC server",
},
},
OptionSpec {
name: "rpc-secret",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-secret", "token"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Text,
tags: TAG_RPC,
validator: "any",
source_text: "aria2 option",
compatibility_note: "rpc auth token",
},
},
OptionSpec {
name: "rpc-save-upload-metadata",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["rpc-save-upload-metadata"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Rpc,
parser: OptionParser::Boolean,
tags: &[OptionTag::Rpc, OptionTag::GlobalOnly],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "persist uploaded torrent or metalink metadata through RPC",
},
},
OptionSpec {
name: "listen-port",
kind: OptionKind::Integer,
default_value: "6881",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["listen-port"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Bt,
parser: OptionParser::Integer,
tags: TAG_BT,
validator: "1..65535",
source_text: "aria2 option",
compatibility_note: "bt tcp/udp listen port",
},
},
OptionSpec {
name: "dht-listen-port",
kind: OptionKind::Integer,
default_value: "6881",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["dht-listen-port"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Bt,
parser: OptionParser::Integer,
tags: TAG_BT,
validator: "1..65535",
source_text: "aria2 option",
compatibility_note: "dht udp listen port",
},
},
OptionSpec {
name: "select-file",
kind: OptionKind::List,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["select-file"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Bt,
parser: OptionParser::Csv,
tags: &[OptionTag::Bt, OptionTag::PerDownloadOnly],
validator: "comma-separated file indexes",
source_text: "aria2 option",
compatibility_note: "select BT or Metalink files to download",
},
},
OptionSpec {
name: "bt-tracker",
kind: OptionKind::List,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["bt-tracker"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Bt,
parser: OptionParser::Csv,
tags: TAG_BT,
validator: "comma-separated tracker list",
source_text: "aria2 option",
compatibility_note: "bt tracker announce list",
},
},
OptionSpec {
name: "ftp-user",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["ftp-user"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Ftp,
parser: OptionParser::Text,
tags: &[OptionTag::GlobalOnly],
validator: "VALUE",
source_text: "aria2 option",
compatibility_note: "default FTP username",
},
},
];
@@ -0,0 +1,512 @@
use super::{
OptionFamily, OptionKind, OptionMetadata, OptionParser, OptionScope, OptionSource, OptionSpec,
OptionStatus, OptionTag, TAG_BT, TAG_METALINK,
};
/// Hook, proxy, TLS, and RPC-adjacent compat registry entries.
pub(super) const HOOKS_AND_RPC_ENTRIES: &[OptionSpec] = &[
OptionSpec {
name: "on-download-complete",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["on-download-complete"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Core,
parser: OptionParser::Text,
tags: &[OptionTag::GlobalOnly],
validator: "command string",
source_text: "aria2 option",
compatibility_note: "completion hook command",
},
},
OptionSpec {
name: "on-download-stop",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["on-download-stop"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Core,
parser: OptionParser::Text,
tags: &[OptionTag::GlobalOnly],
validator: "command string",
source_text: "aria2 option",
compatibility_note: "stop hook command",
},
},
OptionSpec {
name: "save-cookies",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["save-cookies"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Http,
parser: OptionParser::Path,
tags: &[OptionTag::GlobalOnly],
validator: "writable path",
source_text: "aria2 option",
compatibility_note: "persist the cookie jar to disk",
},
},
OptionSpec {
name: "disable-ipv6",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["disable-ipv6"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Core,
parser: OptionParser::Boolean,
tags: &[],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "disable ipv6 sockets and resolution",
},
},
OptionSpec {
name: "user-agent",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &["U"],
rpc_names: &["user-agent"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "request user agent header",
},
},
OptionSpec {
name: "header",
kind: OptionKind::List,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["header"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Headers,
tags: &[],
validator: "header lines",
source_text: "aria2 option",
compatibility_note: "custom request headers",
},
},
OptionSpec {
name: "all-proxy",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["all-proxy"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "proxy url",
source_text: "aria2 option",
compatibility_note: "generic proxy endpoint",
},
},
OptionSpec {
name: "http-proxy",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["http-proxy"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "proxy url",
source_text: "aria2 option",
compatibility_note: "http proxy endpoint",
},
},
OptionSpec {
name: "https-proxy",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["https-proxy"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "proxy url",
source_text: "aria2 option",
compatibility_note: "https proxy endpoint",
},
},
OptionSpec {
name: "no-proxy",
kind: OptionKind::List,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["no-proxy"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Csv,
tags: &[],
validator: "csv host list",
source_text: "aria2 option",
compatibility_note: "proxy bypass host list",
},
},
OptionSpec {
name: "ftp-proxy",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["ftp-proxy"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "proxy url",
source_text: "aria2 option",
compatibility_note: "ftp proxy endpoint",
},
},
OptionSpec {
name: "http-proxy-user",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["http-proxy-user"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "username override for http proxy endpoint",
},
},
OptionSpec {
name: "http-proxy-passwd",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["http-proxy-passwd"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "password override for http proxy endpoint",
},
},
OptionSpec {
name: "https-proxy-user",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["https-proxy-user"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "username override for https proxy endpoint",
},
},
OptionSpec {
name: "https-proxy-passwd",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["https-proxy-passwd"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "password override for https proxy endpoint",
},
},
OptionSpec {
name: "ftp-proxy-user",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["ftp-proxy-user"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "username override for ftp proxy endpoint",
},
},
OptionSpec {
name: "ftp-proxy-passwd",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["ftp-proxy-passwd"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "password override for ftp proxy endpoint",
},
},
OptionSpec {
name: "all-proxy-user",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["all-proxy-user"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "username override for generic proxy endpoint",
},
},
OptionSpec {
name: "all-proxy-passwd",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["all-proxy-passwd"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Proxy,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "password override for generic proxy endpoint",
},
},
OptionSpec {
name: "check-certificate",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["check-certificate"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Security,
parser: OptionParser::Boolean,
tags: &[],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "verify peer and host certificates",
},
},
OptionSpec {
name: "ca-certificate",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["ca-certificate"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Security,
parser: OptionParser::Path,
tags: &[],
validator: "path",
source_text: "aria2 option",
compatibility_note: "ca certificate file",
},
},
OptionSpec {
name: "certificate",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["certificate"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Security,
parser: OptionParser::Path,
tags: &[],
validator: "path",
source_text: "aria2 option",
compatibility_note: "client certificate file",
},
},
OptionSpec {
name: "private-key",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["private-key"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Security,
parser: OptionParser::Path,
tags: &[],
validator: "path",
source_text: "aria2 option",
compatibility_note: "client private key file",
},
},
OptionSpec {
name: "retry-wait",
kind: OptionKind::Duration,
default_value: "0",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["retry-wait"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Duration,
tags: &[],
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "retry delay in seconds",
},
},
OptionSpec {
name: "max-tries",
kind: OptionKind::Integer,
default_value: "5",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["max-tries"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Integer,
tags: &[],
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "maximum retry attempts",
},
},
OptionSpec {
name: "bt-save-metadata",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &[],
rpc_names: &["bt-save-metadata"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Bt,
parser: OptionParser::Boolean,
tags: TAG_BT,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "save metadata file",
},
},
OptionSpec {
name: "follow-torrent",
kind: OptionKind::Text,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &[],
rpc_names: &["follow-torrent"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Bt,
parser: OptionParser::Enum,
tags: TAG_BT,
validator: "true|false|mem",
source_text: "aria2 option",
compatibility_note: "torrent follow behavior",
},
},
OptionSpec {
name: "metalink-enable-unique-protocol",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Verified,
aliases: &[],
rpc_names: &["metalink-enable-unique-protocol"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Metalink,
parser: OptionParser::Boolean,
tags: TAG_METALINK,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "metalink dedupe by protocol",
},
},
];
@@ -0,0 +1,566 @@
use super::{
OptionFamily, OptionKind, OptionMetadata, OptionParser, OptionScope, OptionSource, OptionSpec,
OptionStatus, OptionTag, TAG_GLOBAL, TAG_PER, TAG_RPC,
};
/// Transfer-tuning and performance-oriented compat registry entries.
pub(super) const TRANSFER_TUNING_ENTRIES: &[OptionSpec] = &[
OptionSpec {
name: "max-overall-download-limit",
kind: OptionKind::Size,
default_value: "0",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["max-overall-download-limit"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Performance,
parser: OptionParser::Size,
tags: TAG_PER,
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "global aggregate download-speed cap",
},
},
OptionSpec {
name: "max-download-limit",
kind: OptionKind::Size,
default_value: "0",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["max-download-limit"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Performance,
parser: OptionParser::Size,
tags: TAG_PER,
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "per-download download-speed cap",
},
},
OptionSpec {
name: "max-overall-upload-limit",
kind: OptionKind::Size,
default_value: "0",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["max-overall-upload-limit"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Performance,
parser: OptionParser::Size,
tags: TAG_PER,
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "global aggregate upload-speed cap",
},
},
OptionSpec {
name: "max-upload-limit",
kind: OptionKind::Size,
default_value: "0",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["max-upload-limit"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Performance,
parser: OptionParser::Size,
tags: TAG_PER,
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "per-download upload-speed cap",
},
},
OptionSpec {
name: "disk-cache",
kind: OptionKind::Size,
default_value: "16M",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["disk-cache"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Performance,
parser: OptionParser::Size,
tags: TAG_PER,
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "configured disk cache budget",
},
},
OptionSpec {
name: "max-connection-per-server",
kind: OptionKind::Integer,
default_value: "1",
source: OptionSource::Pro,
status: OptionStatus::Implemented,
aliases: &["x"],
rpc_names: &["max-connection-per-server"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Performance,
parser: OptionParser::Integer,
tags: TAG_PER,
validator: ">=1",
source_text: "aria2-rust-pro",
compatibility_note: "legacy speed tuning",
},
},
OptionSpec {
name: "min-split-size",
kind: OptionKind::Size,
default_value: "20M",
source: OptionSource::Pro,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["min-split-size"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Performance,
parser: OptionParser::Size,
tags: TAG_PER,
validator: ">=1024",
source_text: "aria2-rust-pro",
compatibility_note: "pro lower split-size floor target",
},
},
OptionSpec {
name: "piece-length",
kind: OptionKind::Size,
default_value: "1M",
source: OptionSource::Pro,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["piece-length"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Performance,
parser: OptionParser::Size,
tags: TAG_PER,
validator: ">=1024",
source_text: "aria2-rust-pro",
compatibility_note: "pro lower piece-length floor target",
},
},
OptionSpec {
name: "retry-on-400",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Pro,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["retry-on-400"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Http,
parser: OptionParser::Boolean,
tags: TAG_RPC,
validator: "bool",
source_text: "aria2-rust-pro",
compatibility_note: "retry HTTP 400 when explicitly enabled",
},
},
OptionSpec {
name: "retry-on-403",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Pro,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["retry-on-403"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Http,
parser: OptionParser::Boolean,
tags: TAG_RPC,
validator: "bool",
source_text: "aria2-rust-pro",
compatibility_note: "retry HTTP 403 when explicitly enabled",
},
},
OptionSpec {
name: "retry-on-406",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Pro,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["retry-on-406"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Http,
parser: OptionParser::Boolean,
tags: TAG_RPC,
validator: "bool",
source_text: "aria2-rust-pro",
compatibility_note: "retry HTTP 406 when explicitly enabled",
},
},
OptionSpec {
name: "retry-on-unknown",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Pro,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["retry-on-unknown"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Http,
parser: OptionParser::Boolean,
tags: TAG_RPC,
validator: "bool",
source_text: "aria2-rust-pro",
compatibility_note: "retry unknown HTTP failure when explicitly enabled",
},
},
OptionSpec {
name: "referer",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["referer"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "http referer header override",
},
},
OptionSpec {
name: "lowest-speed-limit",
kind: OptionKind::Size,
default_value: "0",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["lowest-speed-limit"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Performance,
parser: OptionParser::Size,
tags: &[],
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "abort slow connections below this transfer rate",
},
},
OptionSpec {
name: "allow-overwrite",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["allow-overwrite"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Core,
parser: OptionParser::Boolean,
tags: TAG_PER,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "overwrite existing target file instead of refusing",
},
},
OptionSpec {
name: "auto-file-renaming",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["auto-file-renaming"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Core,
parser: OptionParser::Boolean,
tags: TAG_PER,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "rename colliding output file automatically",
},
},
OptionSpec {
name: "parameterized-uri",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &["P"],
rpc_names: &["parameterized-uri"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Input,
parser: OptionParser::Boolean,
tags: &[OptionTag::InputFile, OptionTag::PerDownloadOnly],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "expand numbered or ranged URI templates",
},
},
OptionSpec {
name: "realtime-chunk-checksum",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["realtime-chunk-checksum"],
metadata: OptionMetadata {
scope: OptionScope::PerDownload,
family: OptionFamily::Checksum,
parser: OptionParser::Boolean,
tags: TAG_PER,
validator: "bool",
source_text: "aria2 option",
compatibility_note: "verify chunk checksums while downloading when available",
},
},
OptionSpec {
name: "load-cookies",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["load-cookies"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Path,
tags: &[],
validator: "existing path",
source_text: "aria2 option",
compatibility_note: "load Mozilla-format cookies from disk",
},
},
OptionSpec {
name: "save-cookies",
kind: OptionKind::Path,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["save-cookies"],
metadata: OptionMetadata {
scope: OptionScope::Global,
family: OptionFamily::Http,
parser: OptionParser::Path,
tags: TAG_GLOBAL,
validator: "writable path",
source_text: "aria2 option",
compatibility_note: "save Mozilla-format cookies on exit",
},
},
OptionSpec {
name: "ftp-user",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["ftp-user"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Ftp,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "ftp username applied to matching transfers",
},
},
OptionSpec {
name: "ftp-passwd",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["ftp-passwd"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Ftp,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "ftp password applied to matching transfers",
},
},
OptionSpec {
name: "ftp-type",
kind: OptionKind::Enum,
default_value: "binary",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["ftp-type"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Ftp,
parser: OptionParser::Enum,
tags: &[],
validator: "binary|ascii",
source_text: "aria2 option",
compatibility_note: "ftp transfer type preference",
},
},
OptionSpec {
name: "ftp-pasv",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &["p"],
rpc_names: &["ftp-pasv"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Ftp,
parser: OptionParser::Boolean,
tags: &[],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "ftp passive mode toggle",
},
},
OptionSpec {
name: "ftp-reuse-connection",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["ftp-reuse-connection"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Ftp,
parser: OptionParser::Boolean,
tags: &[],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "ftp connection reuse preference",
},
},
OptionSpec {
name: "http-user",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["http-user"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "http auth username applied to matching transfers",
},
},
OptionSpec {
name: "http-passwd",
kind: OptionKind::Text,
default_value: "",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["http-passwd"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Text,
tags: &[],
validator: "any",
source_text: "aria2 option",
compatibility_note: "http auth password applied to matching transfers",
},
},
OptionSpec {
name: "use-head",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["use-head"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Boolean,
tags: &[],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "probe with HEAD before the first GET when supported",
},
},
OptionSpec {
name: "always-resume",
kind: OptionKind::Bool,
default_value: "true",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["always-resume"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Session,
parser: OptionParser::Boolean,
tags: &[],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "refuse to restart from scratch when resume is possible",
},
},
OptionSpec {
name: "max-resume-failure-tries",
kind: OptionKind::Integer,
default_value: "0",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["max-resume-failure-tries"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Session,
parser: OptionParser::Integer,
tags: &[],
validator: ">=0",
source_text: "aria2 option",
compatibility_note: "allow limited resume mismatches before restarting",
},
},
OptionSpec {
name: "conditional-get",
kind: OptionKind::Bool,
default_value: "false",
source: OptionSource::Original,
status: OptionStatus::Implemented,
aliases: &[],
rpc_names: &["conditional-get"],
metadata: OptionMetadata {
scope: OptionScope::Both,
family: OptionFamily::Http,
parser: OptionParser::Boolean,
tags: &[],
validator: "bool",
source_text: "aria2 option",
compatibility_note: "skip download when local file is already current",
},
},
];
@@ -0,0 +1,24 @@
/// Reserved option name that cannot be used by external inputs.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ReservedOptionName {
/// Reserved option spelling.
pub name: &'static str,
/// Explanation for the reservation.
pub reason: &'static str,
}
/// Reserved option spellings used internally by the compat layer.
pub const RESERVED_OPTION_NAMES: &[ReservedOptionName] = &[
ReservedOptionName {
name: "_profile",
reason: "internal profile selector",
},
ReservedOptionName {
name: "_compat-mode",
reason: "internal compatibility switch",
},
ReservedOptionName {
name: "_source",
reason: "config source marker",
},
];
@@ -0,0 +1,176 @@
use super::{
OptionFamily, OptionScope, OptionStatus, OptionTag, global_option_specs, live_option_specs,
option_spec, per_download_option_specs,
};
#[test]
fn cli_spellings_keep_short_and_long_alias_forms() {
let continue_spec = option_spec("continue").expect("continue should exist");
assert_eq!(
continue_spec.cli_spellings(),
vec!["--continue".to_owned(), "-c".to_owned()]
);
let digest_spec =
option_spec("no-want-digest-header").expect("compat digest option should exist");
assert_eq!(
digest_spec.cli_spellings(),
vec![
"--no-want-digest-header".to_owned(),
"--http-want-digest".to_owned()
]
);
}
#[test]
fn config_spellings_exclude_short_cli_aliases_but_keep_long_compat_aliases() {
let continue_spec = option_spec("continue").expect("continue should exist");
assert_eq!(continue_spec.config_spellings(), vec!["continue"]);
let digest_spec =
option_spec("no-want-digest-header").expect("compat digest option should exist");
assert_eq!(
digest_spec.config_spellings(),
vec!["no-want-digest-header", "http-want-digest"]
);
}
#[test]
fn lookup_spellings_merge_canonical_alias_and_rpc_names_without_duplicates() {
let rpc_secret = option_spec("rpc-secret").expect("rpc-secret should exist");
assert_eq!(rpc_secret.lookup_spellings(), vec!["rpc-secret", "token"]);
}
#[test]
fn value_hint_and_help_synopsis_are_help_ready() {
let continue_spec = option_spec("continue").expect("continue should exist");
assert_eq!(continue_spec.value_hint(), "true|false");
assert_eq!(continue_spec.help_synopsis(), "--continue[=true|false], -c");
let port_spec = option_spec("rpc-listen-port").expect("rpc-listen-port should exist");
assert_eq!(port_spec.value_hint(), "PORT");
assert_eq!(port_spec.help_synopsis(), "--rpc-listen-port=PORT");
let follow_torrent = option_spec("follow-torrent").expect("follow-torrent should exist");
assert_eq!(follow_torrent.value_hint(), "true|false|mem");
let ftp_type = option_spec("ftp-type").expect("ftp-type should exist");
assert_eq!(ftp_type.value_hint(), "binary|ascii");
let ftp_pasv = option_spec("ftp-pasv").expect("ftp-pasv should exist");
assert_eq!(ftp_pasv.help_synopsis(), "--ftp-pasv[=true|false], -p");
}
#[test]
fn live_option_specs_cover_only_non_planned_surface() {
let live_specs = live_option_specs();
assert!(live_specs.iter().all(|spec| {
spec.status != OptionStatus::Planned && spec.status != OptionStatus::Removed
}));
assert!(live_specs.iter().any(|spec| spec.name == "bt-tracker"));
assert!(
live_specs
.iter()
.any(|spec| spec.name == "on-download-complete")
);
}
#[test]
fn extended_registry_surface_exposes_aliases_families_tags_and_value_hints() {
let parameterized = option_spec("parameterized-uri")
.expect("parameterized-uri compatibility option should exist");
assert_eq!(option_spec("P"), Some(parameterized));
assert_eq!(
parameterized.cli_spellings(),
vec!["--parameterized-uri".to_owned(), "-P".to_owned()]
);
assert_eq!(parameterized.metadata.family, OptionFamily::Input);
assert_eq!(parameterized.metadata.scope, OptionScope::PerDownload);
assert!(parameterized.has_tag(OptionTag::InputFile));
let remote_time = option_spec("R").expect("remote-time short alias should resolve");
assert_eq!(remote_time.name, "remote-time");
assert_eq!(remote_time.metadata.family, OptionFamily::Http);
let checksum = option_spec("checksum").expect("checksum option should exist");
assert_eq!(checksum.metadata.family, OptionFamily::Checksum);
assert_eq!(checksum.value_hint(), "KEY=VALUE");
assert!(checksum.has_tag(OptionTag::PerDownloadOnly));
let select_file = option_spec("select-file").expect("select-file should exist");
assert_eq!(select_file.value_hint(), "INDEX,...");
assert_eq!(select_file.metadata.family, OptionFamily::Bt);
assert!(select_file.has_tag(OptionTag::Bt));
let rpc_origin =
option_spec("rpc-allow-origin-all").expect("rpc-allow-origin-all should exist");
assert_eq!(rpc_origin.metadata.family, OptionFamily::Rpc);
assert_eq!(rpc_origin.metadata.scope, OptionScope::Global);
assert!(rpc_origin.has_tag(OptionTag::Rpc));
let ftp_proxy = option_spec("ftp-proxy").expect("ftp-proxy should exist");
assert_eq!(ftp_proxy.metadata.family, OptionFamily::Proxy);
assert_eq!(ftp_proxy.metadata.scope, OptionScope::Both);
let all_proxy_user = option_spec("all-proxy-user").expect("all-proxy-user should exist");
assert_eq!(all_proxy_user.metadata.family, OptionFamily::Proxy);
assert_eq!(all_proxy_user.value_hint(), "VALUE");
}
#[test]
fn extended_registry_surface_flows_into_global_and_per_download_views() {
let global_names = global_option_specs()
.into_iter()
.map(|spec| spec.name)
.collect::<Vec<_>>();
let per_names = per_download_option_specs()
.into_iter()
.map(|spec| spec.name)
.collect::<Vec<_>>();
assert!(global_names.contains(&"rpc-secure"));
assert!(global_names.contains(&"save-cookies"));
assert!(global_names.contains(&"rpc-save-upload-metadata"));
assert!(global_names.contains(&"ftp-user"));
assert!(global_names.contains(&"ftp-proxy-user"));
assert!(global_names.contains(&"ftp-pasv"));
assert!(per_names.contains(&"select-file"));
assert!(per_names.contains(&"pause"));
assert!(per_names.contains(&"checksum"));
assert!(per_names.contains(&"allow-overwrite"));
assert!(per_names.contains(&"ftp-proxy"));
assert!(per_names.contains(&"ftp-reuse-connection"));
}
#[test]
fn option_registry_views_do_not_emit_duplicate_canonical_names() {
let live_names = live_option_specs()
.into_iter()
.map(|spec| spec.name)
.collect::<Vec<_>>();
let global_names = global_option_specs()
.into_iter()
.map(|spec| spec.name)
.collect::<Vec<_>>();
let per_names = per_download_option_specs()
.into_iter()
.map(|spec| spec.name)
.collect::<Vec<_>>();
for (label, names) in [
("live", live_names),
("global", global_names),
("per-download", per_names),
] {
let unique = names
.iter()
.copied()
.collect::<std::collections::BTreeSet<_>>();
assert_eq!(
unique.len(),
names.len(),
"{label} option projection should not contain duplicate canonical names: {names:?}"
);
}
}