use super::{ AtomicU64, BtRuntimeCoordinatorAction, BtRuntimeCoordinatorStepReport, BtRuntimeCoordinatorStepStatus, Digest, Ordering, RpcError, Sha1, SystemTime, UNIX_EPOCH, }; /// Converts a successful or failed coordinator action result into a stable report row. pub(in crate::dispatcher) fn push_bt_runtime_coordinator_result( steps: &mut Vec, action: BtRuntimeCoordinatorAction, result: Result<(), RpcError>, ) { match result { Ok(()) => steps.push(BtRuntimeCoordinatorStepReport { action, status: BtRuntimeCoordinatorStepStatus::Executed, detail: None, }), Err(error) => steps.push(BtRuntimeCoordinatorStepReport { action, status: BtRuntimeCoordinatorStepStatus::Failed, detail: Some(error.message), }), } } /// Builds a skipped coordinator action report row with a concise reason. pub(in crate::dispatcher) fn skipped_bt_runtime_coordinator_step( action: BtRuntimeCoordinatorAction, detail: &str, ) -> BtRuntimeCoordinatorStepReport { BtRuntimeCoordinatorStepReport { action, status: BtRuntimeCoordinatorStepStatus::Skipped, detail: Some(detail.to_owned()), } } /// Monotonic nonce mixed into generated session IDs. static NEXT_SESSION_ID_NONCE: AtomicU64 = AtomicU64::new(1); /// Generates a stable hex session identifier for RPC clients. pub(in crate::dispatcher) fn generate_session_id() -> String { let now_nanos = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("system time should be after unix epoch") .as_nanos(); let nonce = NEXT_SESSION_ID_NONCE.fetch_add(1, Ordering::Relaxed); let mut sha1 = Sha1::new(); sha1.update(now_nanos.to_le_bytes()); sha1.update(std::process::id().to_le_bytes()); sha1.update(nonce.to_le_bytes()); let digest = sha1.finalize(); digest.iter().map(|byte| format!("{byte:02x}")).collect() } /// Returns the upstream-style enabled feature list reported by `getVersion`. pub(in crate::dispatcher) fn rpc_enabled_features() -> &'static [&'static str] { &[ "Async DNS", "BitTorrent", "GZip", "HTTPS", "Message Digest", "Metalink", "XML-RPC", "SFTP", ] } /// Encodes bytes as an uppercase hexadecimal string. pub(in crate::dispatcher) fn hex_string(bytes: &[u8]) -> String { let mut out = String::with_capacity(bytes.len() * 2); for byte in bytes { out.push_str(&format!("{byte:02X}")); } out } /// Formats the share ratio text expected by aria2 RPC payloads. pub(in crate::dispatcher) fn rpc_share_ratio_text(share_ratio_milli: Option) -> String { share_ratio_milli .map(|milli| format!("{:.3}", milli as f64 / 1000.0)) .unwrap_or_else(|| "0.000".to_owned()) } /// Formats the share time text expected by aria2 RPC payloads. pub(in crate::dispatcher) fn rpc_share_time_text( snapshot: &aria2_rust_pro_core::ProgressSnapshot, ) -> String { snapshot.share_time_secs.unwrap_or(0).to_string() }