teamy-mft 0.7.1

TeamDman's Master File Table CLI and library for NTFS.
use crate::machine::config::DEFAULT_SERVICE_NAME;
use crate::machine::ipc::load_machine_daemon_client_config;
use crate::machine::ipc::shutdown as shutdown_daemon;
use crate::machine::service::WindowsServiceState;
use crate::machine::service::query_service_state;
use crate::machine::service::stop_service_if_running;
use crate::machine::service::wait_for_stopped;
use arbitrary::Arbitrary;
use eyre::WrapErr;
use facet::Facet;
use figue::{self as args};
use tracing::info;
use tracing::warn;

#[derive(Facet, Arbitrary, PartialEq, Debug, Default)]
pub struct ServiceStopArgs {
    /// Skip daemon RPC shutdown and directly stop the Windows service, elevating if needed.
    #[facet(args::named, default)]
    pub force: bool,
}

impl ServiceStopArgs {
    /// # Errors
    ///
    /// Returns an error if the service cannot be stopped.
    pub fn invoke(self) -> eyre::Result<()> {
        let config = load_machine_daemon_client_config()?;
        let service_name = if config.service_name.is_empty() {
            DEFAULT_SERVICE_NAME
        } else {
            &config.service_name
        };
        let was_running = if self.force {
            crate::windows_utils::elevation::ensure_elevated()?;
            stop_service_if_running(service_name)?
        } else {
            match query_service_state(service_name)? {
                WindowsServiceState::Running | WindowsServiceState::StartPending => {
                    let (logs_tx, logs_rx) =
                        vox::channel::<crate::machine::daemon_log::DaemonLogWireEvent>();
                    let log_drain = crate::machine::daemon_log::spawn_stderr_log_drain(logs_rx);
                    match shutdown_daemon(&config, logs_tx) {
                        Ok(()) => {
                            drop(log_drain);
                            wait_for_stopped(service_name, std::time::Duration::from_secs(10))
                            .wrap_err_with(|| {
                                format!(
                                    "Timed out waiting for {service_name} to stop after daemon shutdown request"
                                )
                            })?;
                            true
                        }
                        Err(error) => {
                            drop(log_drain);
                            warn!(
                                service_name,
                                error = %error,
                                "Daemon shutdown failed; falling back to service stop"
                            );
                            stop_service_if_running(service_name)?
                        }
                    }
                }
                WindowsServiceState::Stopped
                | WindowsServiceState::Missing
                | WindowsServiceState::Unknown(_) => false,
            }
        };
        info!(
            service_name,
            was_running, "Machine daemon is now no longer running"
        );
        println!("Stopped {service_name}");
        Ok(())
    }
}