127 lines
4.3 KiB
Rust
127 lines
4.3 KiB
Rust
#![doc(hidden)]
|
|
#![expect(
|
|
clippy::needless_pass_by_value,
|
|
clippy::redundant_pub_crate,
|
|
reason = "this private daemon-launch module keeps ownership explicit across listener bootstrap helpers"
|
|
)]
|
|
|
|
use std::{
|
|
net::{IpAddr, Ipv4Addr, TcpListener},
|
|
sync::{Arc, Mutex},
|
|
};
|
|
|
|
use aria2_rust_pro_core::RuntimeConfig;
|
|
use aria2_rust_pro_rpc::{
|
|
InProcessRpcDispatcher, JsonRpcRequest, RpcMeta, RpcMethod, RpcServerConfig, RpcValue,
|
|
serve_rpc_listener,
|
|
};
|
|
|
|
use super::{
|
|
CliError, ParsedArguments, TransferInputEntry, derive_rpc_listen_host, derive_rpc_secret,
|
|
derive_runtime_config, expand_transfer_entries, load_config_report, merged_profile,
|
|
rpc_option_object,
|
|
};
|
|
use crate::Invocation;
|
|
|
|
#[derive(Debug)]
|
|
struct RpcDaemonLaunch {
|
|
runtime: RuntimeConfig,
|
|
listen_ip: IpAddr,
|
|
secret: Option<String>,
|
|
input_entries: Vec<TransferInputEntry>,
|
|
}
|
|
|
|
/// Runs the RPC daemon surface implied by a parsed CLI invocation.
|
|
pub(super) fn run_rpc_daemon(parsed: ParsedArguments) -> Result<(), CliError> {
|
|
let (config_path, inputs) = match &parsed.invocation {
|
|
Invocation::Run { config_path, uris } => (config_path.clone(), uris.clone()),
|
|
Invocation::Version | Invocation::Help { .. } => {
|
|
return Err(CliError::Io(
|
|
"rpc daemon launch requires a run invocation".to_owned(),
|
|
));
|
|
}
|
|
};
|
|
let launch = build_rpc_daemon_launch(&parsed, config_path, inputs)?;
|
|
let listener = bind_rpc_listener(launch.listen_ip, launch.runtime.rpc_port)?;
|
|
let mut dispatcher = InProcessRpcDispatcher::with_runtime(launch.runtime);
|
|
seed_dispatcher_with_inputs(&mut dispatcher, launch.input_entries);
|
|
let server_config = build_rpc_server_config(&listener, launch.secret)?;
|
|
|
|
println!(
|
|
"rpc daemon listening on {}:{}",
|
|
launch.listen_ip,
|
|
server_config.listen_addr.port()
|
|
);
|
|
|
|
serve_rpc_listener(listener, server_config, Arc::new(Mutex::new(dispatcher)))
|
|
.map_err(|error| CliError::Io(format!("rpc daemon serve failed: {error}")))
|
|
}
|
|
|
|
fn build_rpc_daemon_launch(
|
|
parsed: &ParsedArguments,
|
|
config_path: Option<std::path::PathBuf>,
|
|
inputs: Vec<String>,
|
|
) -> Result<RpcDaemonLaunch, CliError> {
|
|
let config_report = config_path
|
|
.as_ref()
|
|
.map(|path| load_config_report(path, true))
|
|
.transpose()?;
|
|
let file_profile = config_report.as_ref().map(|report| &report.profile);
|
|
let effective_profile = merged_profile(file_profile, parsed.cli_profile.as_ref());
|
|
let profile = effective_profile.as_ref();
|
|
let runtime = derive_runtime_config(profile, &parsed.profile);
|
|
let listen_host = derive_rpc_listen_host(profile, &parsed.profile);
|
|
let secret = derive_rpc_secret(profile, &parsed.profile);
|
|
let listen_ip = listen_host
|
|
.parse::<IpAddr>()
|
|
.unwrap_or(IpAddr::V4(Ipv4Addr::LOCALHOST));
|
|
let input_entries =
|
|
expand_transfer_entries(&inputs, profile, Some(&parsed.cli_transfer_sources))?;
|
|
|
|
Ok(RpcDaemonLaunch {
|
|
runtime,
|
|
listen_ip,
|
|
secret,
|
|
input_entries,
|
|
})
|
|
}
|
|
|
|
fn bind_rpc_listener(listen_ip: IpAddr, listen_port: u16) -> Result<TcpListener, CliError> {
|
|
TcpListener::bind((listen_ip, listen_port))
|
|
.map_err(|error| CliError::Io(format!("rpc daemon bind failed: {error}")))
|
|
}
|
|
|
|
fn build_rpc_server_config(
|
|
listener: &TcpListener,
|
|
secret: Option<String>,
|
|
) -> Result<RpcServerConfig, CliError> {
|
|
Ok(RpcServerConfig {
|
|
listen_addr: listener
|
|
.local_addr()
|
|
.map_err(|error| CliError::Io(format!("rpc daemon local addr failed: {error}")))?,
|
|
secret_token: secret,
|
|
..RpcServerConfig::default()
|
|
})
|
|
}
|
|
|
|
fn seed_dispatcher_with_inputs(
|
|
dispatcher: &mut InProcessRpcDispatcher,
|
|
input_entries: Vec<TransferInputEntry>,
|
|
) {
|
|
for entry in input_entries {
|
|
let mut params = vec![RpcValue::Array(
|
|
entry.uris.into_iter().map(RpcValue::String).collect(),
|
|
)];
|
|
if let Some(options) = rpc_option_object(entry.profile.as_ref()) {
|
|
params.push(options);
|
|
}
|
|
let _ = dispatcher.dispatch_json(JsonRpcRequest {
|
|
jsonrpc: Some("2.0".to_owned()),
|
|
id: None,
|
|
method: RpcMethod::Aria2AddUri.as_str().to_owned(),
|
|
params,
|
|
meta: RpcMeta::default(),
|
|
});
|
|
}
|
|
}
|