From 63a0ec3901a863fb07d18f4b814a98a813644382 Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Mon, 20 Jul 2026 14:18:36 +0200 Subject: chore: Commit --- crates/daemon/src/main.rs | 170 +++++----------------------------------------- 1 file changed, 18 insertions(+), 152 deletions(-) (limited to 'crates/daemon/src/main.rs') diff --git a/crates/daemon/src/main.rs b/crates/daemon/src/main.rs index 26a5cafd..174cf94b 100644 --- a/crates/daemon/src/main.rs +++ b/crates/daemon/src/main.rs @@ -1,22 +1,16 @@ -#[allow(unused_imports)] +#![expect(unused_crate_dependencies, reason = "Didn't remove them yet")] + use clap::Parser; use eyre::{Result, WrapErr, bail, eyre}; use fs4::fs_std::FileExt; use std::fs::{self, File, OpenOptions}; -use std::io::{ErrorKind, Write}; -#[cfg(unix)] -use std::os::unix::net::UnixStream as StdUnixStream; +use std::io::Write; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; use std::time::{Duration, Instant}; use tokio::time::sleep; use turtle_daemon::{ - DaemonEvent, - aclient::{ - database::ClientSqlite, history::History, record::sqlite_store::SqliteStore, - settings::Settings, - }, - client::{ControlClient, DaemonClientErrorKind, HistoryClient, classify_error}, + aclient::{database::ClientSqlite, record::sqlite_store::SqliteStore, settings::Settings}, + client::{DaemonClientErrorKind, HistoryClient, classify_error}, }; #[derive(Parser, Debug)] @@ -24,9 +18,6 @@ use turtle_daemon::{ pub(crate) enum Cmd { /// Start the daemon server Start { - #[arg(long, hide = true)] - daemonize: bool, - /// Also write daemon logs to the console (useful for debugging) #[arg(long)] show_logs: bool, @@ -39,21 +30,6 @@ pub(crate) enum Cmd { Stop, } -impl Cmd { - pub(crate) async fn run( - self, - settings: Settings, - store: SqliteStore, - history_db: ClientSqlite, - ) -> Result<()> { - match self { - Cmd::Start { .. } => run(settings, store, history_db).await, - Cmd::Status => status_cmd(&settings).await, - Cmd::Stop => stop_cmd(&settings).await, - } - } -} - #[tokio::main] async fn main() -> Result<()> { let settings = Settings::new().wrap_err("could not load client settings")?; @@ -63,13 +39,14 @@ async fn main() -> Result<()> { let db = ClientSqlite::new(db_path, settings.local_timeout).await?; let sqlite_store = SqliteStore::new(record_store_path, settings.local_timeout).await?; - Cmd::parse().run(settings, sqlite_store, db).await + match Cmd::parse() { + Cmd::Start { show_logs, .. } => start_cmd(settings, store, history_db, show_logs).await, + Cmd::Status => status_cmd(&settings).await, + Cmd::Stop => stop_cmd(&settings).await, + } } -const DAEMON_VERSION: &str = env!("CARGO_PKG_VERSION"); -const DAEMON_PROTOCOL_VERSION: u32 = 1; const STARTUP_POLL: Duration = Duration::from_millis(40); -const LOCK_POLL: Duration = Duration::from_millis(20); const LEGACY_DAEMON_RESTART_MESSAGE: &str = "legacy daemon detected; restart daemon manually"; struct PidfileGuard { @@ -109,18 +86,6 @@ enum Probe { Unreachable(eyre::Report), } -fn daemon_matches_expected(version: &str, protocol: u32) -> bool { - version == DAEMON_VERSION && protocol == DAEMON_PROTOCOL_VERSION -} - -fn daemon_mismatch_message(version: &str, protocol: u32) -> String { - if protocol == DAEMON_PROTOCOL_VERSION { - format!("daemon is out of date: expected {DAEMON_VERSION}, got {version}") - } else { - format!("daemon protocol mismatch: expected {DAEMON_PROTOCOL_VERSION}, got {protocol}") - } -} - fn is_legacy_daemon_error(err: &eyre::Report) -> bool { matches!(classify_error(err), DaemonClientErrorKind::Unimplemented) } @@ -141,6 +106,8 @@ fn open_lock_file(path: &Path) -> Result { } async fn wait_for_lock(path: &Path, timeout: Duration) -> Result { + const LOCK_POLL: Duration = Duration::from_millis(20); + let file = open_lock_file(path)?; let start = Instant::now(); @@ -168,32 +135,6 @@ async fn wait_for_pidfile_available(path: &Path, timeout: Duration) -> Result<() Ok(()) } -async fn connect_client(settings: &Settings) -> Result { - HistoryClient::new( - #[cfg(unix)] - settings.daemon.socket_path.clone(), - ) - .await -} - -async fn probe(settings: &Settings) -> Probe { - let mut client = match connect_client(settings).await { - Ok(client) => client, - Err(err) => return Probe::Unreachable(err), - }; - - match client.status().await { - Ok(status) => { - if daemon_matches_expected(&status.version, status.protocol) { - Probe::Ready(client) - } else { - Probe::NeedsRestart(daemon_mismatch_message(&status.version, status.protocol)) - } - } - Err(err) => Probe::Unreachable(err), - } -} - async fn request_shutdown(settings: &Settings) { if let Ok(mut client) = connect_client(settings).await { drop(client.shutdown().await); @@ -204,85 +145,6 @@ fn startup_timeout(settings: &Settings) -> Duration { Duration::from_secs_f64(settings.local_timeout.max(0.5) + 2.0) } -pub(crate) async fn start_history(settings: &Settings, history: History) -> Result { - match async { - connect_client(settings) - .await? - .start_history(history.clone()) - .await - } - .await - { - Ok(resp) => { - if daemon_matches_expected(&resp.version, resp.protocol) { - return Ok(resp.id); - } - - Err(eyre!( - "{}. Restart the daemon manually", - daemon_mismatch_message(&resp.version, resp.protocol) - )) - } - Err(err) => Err(err), - } -} - -pub(crate) async fn end_history( - settings: &Settings, - id: String, - duration: u64, - exit: i64, -) -> Result<()> { - match async { - connect_client(settings) - .await? - .end_history(id.clone(), duration, exit) - .await - } - .await - { - Ok(resp) => { - if daemon_matches_expected(&resp.version, resp.protocol) { - return Ok(()); - } - - Err(eyre!( - "{}. Restart the daemon manually", - daemon_mismatch_message(&resp.version, resp.protocol) - )) - } - Err(err) => Err(err), - } -} - -/// Emit a daemon event. -pub(crate) async fn emit_event(settings: &Settings, event: DaemonEvent) { - // Try to connect and send - match ControlClient::from_settings(settings).await { - Ok(mut client) => { - if let Err(e) = client.send_event(event).await { - tracing::debug!(?e, "failed to send event to daemon"); - } - } - Err(e) => { - tracing::debug!(?e, "daemon not available, skipping event emission"); - } - } -} - -pub(crate) async fn tail_client(settings: &Settings) -> Result { - match probe(settings).await { - Probe::Ready(client) => Ok(client), - Probe::NeedsRestart(reason) => { - bail!("{reason}. Restart the daemon manually"); - } - Probe::Unreachable(err) if is_legacy_daemon_error(&err) => { - Err(err.wrap_err(LEGACY_DAEMON_RESTART_MESSAGE)) - } - Probe::Unreachable(err) => Err(err), - } -} - async fn status_cmd(settings: &Settings) -> Result<()> { match probe(settings).await { Probe::Ready(mut client) => { @@ -292,7 +154,6 @@ async fn status_cmd(settings: &Settings) -> Result<()> { println!(" Version: {}", status.version); println!(" Protocol: {}", status.protocol); println!(" Healthy: {}", status.healthy); - #[cfg(unix)] println!(" Socket: {}", settings.daemon.socket_path); } Probe::NeedsRestart(reason) => { @@ -331,7 +192,12 @@ async fn stop_cmd(settings: &Settings) -> Result<()> { } } -async fn run(settings: Settings, store: SqliteStore, history_db: ClientSqlite) -> Result<()> { +async fn start_cmd( + settings: Settings, + store: SqliteStore, + history_db: ClientSqlite, + show_logs: bool, +) -> Result<()> { let pidfile_path = PathBuf::from(&settings.daemon.pidfile_path); let _pidfile_guard = PidfileGuard::acquire(&pidfile_path)?; -- cgit v1.3.1