#![allow(unstable_name_collisions)]
#![deny(clippy::wildcard_imports, missing_docs)]
use std::{
fmt, fs, io,
path::{Path, PathBuf},
process,
};
use anyhow::{Context, Result};
use aranya_daemon::{config::Config, Daemon};
use aranya_util::error::ReportExt as _;
use clap::Parser;
use tokio::runtime::Runtime;
use tracing::{error, info};
use tracing_subscriber::{prelude::*, EnvFilter};
fn main() -> Result<()> {
let flags = Args::parse();
let cfg = Config::load(&flags.config)?;
tracing_subscriber::registry()
.with(
tracing_subscriber::fmt::layer()
.with_writer(io::stderr)
.with_file(false)
.compact()
.with_filter(EnvFilter::from_env("ARANYA_DAEMON")),
)
.init();
info!("starting Aranya daemon");
let pid = PidFile::create(cfg.pid_path()).context("unable to create PID file")?;
info!(name = cfg.name, "wrote PID file to {pid}");
let rt = Runtime::new()?;
rt.block_on(async {
let daemon = Daemon::load(cfg).await.context("unable to load daemon")?;
info!("loaded Aranya daemon");
let handle = daemon.spawn().await.context("unable to start daemon")?;
handle.join().await?;
Ok(())
})
.inspect_err(|err| error!(error = ?err))
}
#[derive(Debug, Parser)]
#[clap(author, version, about, long_about = None)]
struct Args {
#[arg(long)]
config: PathBuf,
}
struct PidFile {
path: PathBuf,
}
impl PidFile {
fn create<P: AsRef<Path>>(path: P) -> io::Result<Self> {
fs::write(path.as_ref(), process::id().to_string())?;
Ok(Self {
path: path.as_ref().to_owned(),
})
}
}
impl Drop for PidFile {
fn drop(&mut self) {
if let Err(err) = fs::remove_file(&self.path) {
error!(error = %err.report(), "unable to remove PID file")
}
}
}
impl fmt::Display for PidFile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.path.display())
}
}