use std::sync::{Arc, Mutex};
use log::{info, error};
use crate::error::DaemonError;
use crate::config::DaemonConfig;
use crate::binary::BinaryManager;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DaemonState {
Offline,
Booting,
Loading,
Running,
Restarting,
Closing,
Errored,
}
pub struct Daemon {
state: Arc<Mutex<DaemonState>>,
binary_manager: Option<BinaryManager>,
}
impl Daemon {
pub fn new() -> Self {
Daemon {
state: Arc::new(Mutex::new(DaemonState::Offline)),
binary_manager: None,
}
}
pub fn get_state(&self) -> DaemonState {
*self.state.lock().unwrap()
}
pub fn start(&self, on_start: impl FnOnce() -> Result<(), DaemonError>) -> Result<(), DaemonError> {
let mut state = self.state.lock().unwrap();
if *state == DaemonState::Running {
return Err(DaemonError::AlreadyRunning);
}
*state = DaemonState::Booting;
info!("Daemon is booting...");
match on_start() {
Ok(_) => {
*state = DaemonState::Running;
info!("Daemon is running.");
Ok(())
}
Err(e) => {
*state = DaemonState::Errored;
error!("Failed to start daemon: {}", e);
Err(e)
}
}
}
pub fn stop(&self, on_stop: impl FnOnce() -> Result<(), DaemonError>) -> Result<(), DaemonError> {
let mut state = self.state.lock().unwrap();
if *state != DaemonState::Running {
return Err(DaemonError::NotRunning);
}
*state = DaemonState::Closing;
info!("Daemon is closing...");
match on_stop() {
Ok(_) => {
*state = DaemonState::Offline;
info!("Daemon stopped successfully.");
Ok(())
}
Err(e) => {
*state = DaemonState::Errored;
error!("Failed to stop daemon: {}", e);
Err(e)
}
}
}
pub fn restart(&self, on_restart: impl Fn() -> Result<(), DaemonError> + Clone) -> Result<(), DaemonError> {
self.stop(on_restart.clone())?;
self.start(on_restart)
}
pub fn load_config(&mut self, config: &DaemonConfig) -> Result<(), DaemonError> {
log::set_max_level(match config.log_level.as_str() {
"debug" => log::LevelFilter::Debug,
"info" => log::LevelFilter::Info,
"warn" => log::LevelFilter::Warn,
"error" => log::LevelFilter::Error,
_ => log::LevelFilter::Info,
});
let binary_manager = BinaryManager::new(config.binary_paths.clone());
binary_manager.load_all()?;
self.binary_manager = Some(binary_manager);
Ok(())
}
#[cfg(feature = "async")]
pub async fn start_async<F, Fut>(&self, on_start: F) -> Result<(), DaemonError>
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = Result<(), DaemonError>>,
{
let mut state = self.state.lock().unwrap();
if *state == DaemonState::Running {
return Err(DaemonError::AlreadyRunning);
}
*state = DaemonState::Booting;
info!("Daemon is booting...");
match on_start().await {
Ok(_) => {
*state = DaemonState::Running;
info!("Daemon is running.");
Ok(())
}
Err(e) => {
*state = DaemonState::Errored;
error!("Failed to start daemon: {}", e);
Err(e)
}
}
}
#[cfg(feature = "async")]
pub async fn stop_async<F, Fut>(&self, on_stop: F) -> Result<(), DaemonError>
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = Result<(), DaemonError>>,
{
let mut state = self.state.lock().unwrap();
if *state != DaemonState::Running {
return Err(DaemonError::NotRunning);
}
*state = DaemonState::Closing;
info!("Daemon is closing...");
match on_stop().await {
Ok(_) => {
*state = DaemonState::Offline;
info!("Daemon stopped successfully.");
Ok(())
}
Err(e) => {
*state = DaemonState::Errored;
error!("Failed to stop daemon: {}", e);
Err(e)
}
}
}
}