chore: initial sanitized public snapshot
This commit is contained in:
@@ -0,0 +1,337 @@
|
||||
//! Canonical RPC method catalog and lookup helpers.
|
||||
#![expect(
|
||||
clippy::redundant_pub_crate,
|
||||
reason = "method-catalog helpers stay crate-internal while retaining explicit visibilities"
|
||||
)]
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::model::RpcValue;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
/// RPC methods supported or reserved by the aria2-compatible surface.
|
||||
pub enum RpcMethod {
|
||||
/// Adds one or more download URIs.
|
||||
Aria2AddUri,
|
||||
/// Adds a torrent payload.
|
||||
Aria2AddTorrent,
|
||||
/// Adds a metalink payload.
|
||||
Aria2AddMetalink,
|
||||
/// Removes a download.
|
||||
Aria2Remove,
|
||||
/// Force-removes a download.
|
||||
Aria2ForceRemove,
|
||||
/// Pauses a download.
|
||||
Aria2Pause,
|
||||
/// Pauses all active downloads.
|
||||
Aria2PauseAll,
|
||||
/// Force-pauses a download.
|
||||
Aria2ForcePause,
|
||||
/// Force-pauses all active downloads.
|
||||
Aria2ForcePauseAll,
|
||||
/// Resumes a paused download.
|
||||
Aria2Unpause,
|
||||
/// Resumes all paused downloads.
|
||||
Aria2UnpauseAll,
|
||||
/// Returns status for a single download.
|
||||
Aria2TellStatus,
|
||||
/// Returns active downloads.
|
||||
Aria2TellActive,
|
||||
/// Returns waiting downloads.
|
||||
Aria2TellWaiting,
|
||||
/// Returns stopped downloads.
|
||||
Aria2TellStopped,
|
||||
/// Returns URIs for a download.
|
||||
Aria2GetUris,
|
||||
/// Returns files for a download.
|
||||
Aria2GetFiles,
|
||||
/// Returns peers for a `BitTorrent` download.
|
||||
Aria2GetPeers,
|
||||
/// Returns servers for a download.
|
||||
Aria2GetServers,
|
||||
/// Changes queue position for a download.
|
||||
Aria2ChangePosition,
|
||||
/// Changes URIs attached to a download.
|
||||
Aria2ChangeUri,
|
||||
/// Purges completed download results.
|
||||
Aria2PurgeDownloadResult,
|
||||
/// Removes one completed download result.
|
||||
Aria2RemoveDownloadResult,
|
||||
/// Returns aggregate global statistics.
|
||||
Aria2TellGlobalStat,
|
||||
/// Returns per-download options.
|
||||
Aria2GetOption,
|
||||
/// Changes per-download options.
|
||||
Aria2ChangeOption,
|
||||
/// Returns global options.
|
||||
Aria2GetGlobalOption,
|
||||
/// Changes global options.
|
||||
Aria2ChangeGlobalOption,
|
||||
/// Returns version and enabled feature metadata.
|
||||
Aria2GetVersion,
|
||||
/// Returns session metadata.
|
||||
Aria2GetSessionInfo,
|
||||
/// Persists the current session.
|
||||
Aria2SaveSession,
|
||||
/// Requests graceful shutdown.
|
||||
Aria2Shutdown,
|
||||
/// Requests forced shutdown.
|
||||
Aria2ForceShutdown,
|
||||
/// Executes a batch of nested method calls.
|
||||
SystemMulticall,
|
||||
/// Returns the method catalog.
|
||||
SystemListMethods,
|
||||
/// Returns the notification catalog.
|
||||
SystemListNotifications,
|
||||
}
|
||||
|
||||
impl RpcMethod {
|
||||
/// Returns the canonical method name exposed on the wire.
|
||||
#[must_use]
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Aria2AddUri => "aria2.addUri",
|
||||
Self::Aria2AddTorrent => "aria2.addTorrent",
|
||||
Self::Aria2AddMetalink => "aria2.addMetalink",
|
||||
Self::Aria2Remove => "aria2.remove",
|
||||
Self::Aria2ForceRemove => "aria2.forceRemove",
|
||||
Self::Aria2Pause => "aria2.pause",
|
||||
Self::Aria2PauseAll => "aria2.pauseAll",
|
||||
Self::Aria2ForcePause => "aria2.forcePause",
|
||||
Self::Aria2ForcePauseAll => "aria2.forcePauseAll",
|
||||
Self::Aria2Unpause => "aria2.unpause",
|
||||
Self::Aria2UnpauseAll => "aria2.unpauseAll",
|
||||
Self::Aria2TellStatus => "aria2.tellStatus",
|
||||
Self::Aria2TellActive => "aria2.tellActive",
|
||||
Self::Aria2TellWaiting => "aria2.tellWaiting",
|
||||
Self::Aria2TellStopped => "aria2.tellStopped",
|
||||
Self::Aria2GetUris => "aria2.getUris",
|
||||
Self::Aria2GetFiles => "aria2.getFiles",
|
||||
Self::Aria2GetPeers => "aria2.getPeers",
|
||||
Self::Aria2GetServers => "aria2.getServers",
|
||||
Self::Aria2ChangePosition => "aria2.changePosition",
|
||||
Self::Aria2ChangeUri => "aria2.changeUri",
|
||||
Self::Aria2PurgeDownloadResult => "aria2.purgeDownloadResult",
|
||||
Self::Aria2RemoveDownloadResult => "aria2.removeDownloadResult",
|
||||
Self::Aria2TellGlobalStat => "aria2.getGlobalStat",
|
||||
Self::Aria2GetOption => "aria2.getOption",
|
||||
Self::Aria2ChangeOption => "aria2.changeOption",
|
||||
Self::Aria2GetGlobalOption => "aria2.getGlobalOption",
|
||||
Self::Aria2ChangeGlobalOption => "aria2.changeGlobalOption",
|
||||
Self::Aria2GetVersion => "aria2.getVersion",
|
||||
Self::Aria2GetSessionInfo => "aria2.getSessionInfo",
|
||||
Self::Aria2SaveSession => "aria2.saveSession",
|
||||
Self::Aria2Shutdown => "aria2.shutdown",
|
||||
Self::Aria2ForceShutdown => "aria2.forceShutdown",
|
||||
Self::SystemMulticall => "system.multicall",
|
||||
Self::SystemListMethods => "system.listMethods",
|
||||
Self::SystemListNotifications => "system.listNotifications",
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns accepted legacy aliases for compatibility handling.
|
||||
#[must_use]
|
||||
pub const fn legacy_aliases(self) -> &'static [&'static str] {
|
||||
match self {
|
||||
Self::Aria2TellGlobalStat => &["aria2.tellGlobalStat"],
|
||||
Self::SystemMulticall => &["aria2.multicall"],
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Canonical method ledger in the order exposed to compatibility consumers.
|
||||
pub const RPC_METHOD_LEDGER: &[RpcMethod] = &[
|
||||
RpcMethod::Aria2AddUri,
|
||||
RpcMethod::Aria2AddTorrent,
|
||||
RpcMethod::Aria2GetPeers,
|
||||
RpcMethod::Aria2AddMetalink,
|
||||
RpcMethod::Aria2Remove,
|
||||
RpcMethod::Aria2Pause,
|
||||
RpcMethod::Aria2ForcePause,
|
||||
RpcMethod::Aria2PauseAll,
|
||||
RpcMethod::Aria2ForcePauseAll,
|
||||
RpcMethod::Aria2Unpause,
|
||||
RpcMethod::Aria2UnpauseAll,
|
||||
RpcMethod::Aria2ForceRemove,
|
||||
RpcMethod::Aria2ChangePosition,
|
||||
RpcMethod::Aria2TellStatus,
|
||||
RpcMethod::Aria2GetUris,
|
||||
RpcMethod::Aria2GetFiles,
|
||||
RpcMethod::Aria2GetServers,
|
||||
RpcMethod::Aria2TellActive,
|
||||
RpcMethod::Aria2TellWaiting,
|
||||
RpcMethod::Aria2TellStopped,
|
||||
RpcMethod::Aria2GetOption,
|
||||
RpcMethod::Aria2ChangeUri,
|
||||
RpcMethod::Aria2ChangeOption,
|
||||
RpcMethod::Aria2GetGlobalOption,
|
||||
RpcMethod::Aria2ChangeGlobalOption,
|
||||
RpcMethod::Aria2PurgeDownloadResult,
|
||||
RpcMethod::Aria2RemoveDownloadResult,
|
||||
RpcMethod::Aria2GetVersion,
|
||||
RpcMethod::Aria2GetSessionInfo,
|
||||
RpcMethod::Aria2Shutdown,
|
||||
RpcMethod::Aria2ForceShutdown,
|
||||
RpcMethod::Aria2TellGlobalStat,
|
||||
RpcMethod::Aria2SaveSession,
|
||||
RpcMethod::SystemMulticall,
|
||||
RpcMethod::SystemListMethods,
|
||||
RpcMethod::SystemListNotifications,
|
||||
];
|
||||
|
||||
/// Required upstream-compatible method names that should resolve distinctly.
|
||||
pub const REQUIRED_RPC_METHODS: &[&str] = &[
|
||||
"aria2.addUri",
|
||||
"aria2.addTorrent",
|
||||
"aria2.getPeers",
|
||||
"aria2.addMetalink",
|
||||
"aria2.remove",
|
||||
"aria2.pause",
|
||||
"aria2.forcePause",
|
||||
"aria2.pauseAll",
|
||||
"aria2.forcePauseAll",
|
||||
"aria2.unpause",
|
||||
"aria2.unpauseAll",
|
||||
"aria2.forceRemove",
|
||||
"aria2.changePosition",
|
||||
"aria2.tellStatus",
|
||||
"aria2.getUris",
|
||||
"aria2.getFiles",
|
||||
"aria2.getServers",
|
||||
"aria2.tellActive",
|
||||
"aria2.tellWaiting",
|
||||
"aria2.tellStopped",
|
||||
"aria2.getOption",
|
||||
"aria2.changeUri",
|
||||
"aria2.changeOption",
|
||||
"aria2.getGlobalOption",
|
||||
"aria2.changeGlobalOption",
|
||||
"aria2.purgeDownloadResult",
|
||||
"aria2.removeDownloadResult",
|
||||
"aria2.getVersion",
|
||||
"aria2.getSessionInfo",
|
||||
"aria2.shutdown",
|
||||
"aria2.forceShutdown",
|
||||
"aria2.getGlobalStat",
|
||||
"aria2.saveSession",
|
||||
"system.multicall",
|
||||
"system.listMethods",
|
||||
"system.listNotifications",
|
||||
];
|
||||
|
||||
/// Canonical WebSocket notification names in upstream-compatible order.
|
||||
const RPC_NOTIFICATION_NAMES: &[&str] = &[
|
||||
"aria2.onDownloadStart",
|
||||
"aria2.onDownloadPause",
|
||||
"aria2.onDownloadStop",
|
||||
"aria2.onDownloadComplete",
|
||||
"aria2.onDownloadError",
|
||||
"aria2.onBtDownloadComplete",
|
||||
];
|
||||
|
||||
/// Returns whether a method name is part of the required compatibility set.
|
||||
#[must_use]
|
||||
pub fn is_required_rpc_method(method: &str) -> bool {
|
||||
REQUIRED_RPC_METHODS.contains(&method)
|
||||
}
|
||||
|
||||
/// Resolves a method name or legacy alias into the canonical method variant.
|
||||
#[must_use]
|
||||
pub(super) fn rpc_method(name: &str) -> Option<RpcMethod> {
|
||||
RPC_METHOD_LEDGER
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|method| method.as_str() == name || method.legacy_aliases().contains(&name))
|
||||
}
|
||||
|
||||
/// Returns the canonical RPC method names in ledger order.
|
||||
#[must_use]
|
||||
pub fn rpc_method_names() -> Vec<&'static str> {
|
||||
RPC_METHOD_LEDGER
|
||||
.iter()
|
||||
.copied()
|
||||
.map(RpcMethod::as_str)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns the canonical WebSocket notification method names.
|
||||
#[must_use]
|
||||
pub(super) fn rpc_notification_names() -> Vec<&'static str> {
|
||||
RPC_NOTIFICATION_NAMES.to_vec()
|
||||
}
|
||||
|
||||
/// Builds an RPC value containing the canonical method name list.
|
||||
#[must_use]
|
||||
#[cfg(test)]
|
||||
fn method_name_value_list() -> RpcValue {
|
||||
RpcValue::Array(
|
||||
rpc_method_names()
|
||||
.into_iter()
|
||||
.map(|m| RpcValue::String(m.to_owned()))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Unit tests for the public RPC method and notification catalog.
|
||||
mod tests {
|
||||
use super::{
|
||||
RpcMethod, method_name_value_list, rpc_method, rpc_method_names, rpc_notification_names,
|
||||
};
|
||||
use crate::model::RpcValue;
|
||||
|
||||
#[test]
|
||||
/// Verifies that legacy aliases resolve internally without leaking into public catalogs.
|
||||
fn legacy_aliases_resolve_but_do_not_leak_into_public_method_names() {
|
||||
assert_eq!(
|
||||
rpc_method("aria2.tellGlobalStat"),
|
||||
Some(RpcMethod::Aria2TellGlobalStat)
|
||||
);
|
||||
assert_eq!(
|
||||
rpc_method("aria2.multicall"),
|
||||
Some(RpcMethod::SystemMulticall)
|
||||
);
|
||||
|
||||
let method_names = rpc_method_names();
|
||||
assert!(method_names.contains(&"aria2.getGlobalStat"));
|
||||
assert!(method_names.contains(&"system.multicall"));
|
||||
assert!(!method_names.contains(&"aria2.tellGlobalStat"));
|
||||
assert!(!method_names.contains(&"aria2.multicall"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Verifies that public notification names keep the upstream aria2 order.
|
||||
fn public_notification_names_keep_upstream_order() {
|
||||
assert_eq!(
|
||||
rpc_notification_names(),
|
||||
vec![
|
||||
"aria2.onDownloadStart",
|
||||
"aria2.onDownloadPause",
|
||||
"aria2.onDownloadStop",
|
||||
"aria2.onDownloadComplete",
|
||||
"aria2.onDownloadError",
|
||||
"aria2.onBtDownloadComplete",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Verifies that `system.listMethods` emits only public method names.
|
||||
fn method_name_value_list_uses_public_names_only() {
|
||||
match method_name_value_list() {
|
||||
RpcValue::Array(values) => {
|
||||
let names = values
|
||||
.into_iter()
|
||||
.map(|value| match value {
|
||||
RpcValue::String(name) => name,
|
||||
other => panic!("unexpected method value: {other:?}"),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
assert!(names.iter().any(|name| name == "aria2.getGlobalStat"));
|
||||
assert!(!names.iter().any(|name| name == "aria2.tellGlobalStat"));
|
||||
assert!(!names.iter().any(|name| name == "aria2.multicall"));
|
||||
}
|
||||
other => panic!("unexpected method list payload: {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user