chore: initial sanitized public snapshot
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
#![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(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user