#![deny(warnings)]
mod cli;
mod cron_jobs;
mod error;
mod filesystem;
mod middlewares;
mod openapi;
mod paths;
mod restart;
mod routes;
mod routine_storage;
mod routines;
mod service;
mod storage;
mod sync;
mod utils;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
match cli::parse(std::env::args().skip(1)) {
cli::Command::Help => {
cli::print_help();
Ok(())
}
cli::Command::Version => {
cli::print_version();
Ok(())
}
cli::Command::Status { json } => std::process::exit(cli::status(json)?),
cli::Command::Cleanup { json } => std::process::exit(cli::cleanup(json)?),
cli::Command::Stop { json } => std::process::exit(cli::stop(json)?),
cli::Command::Background => cli::run_background(),
cli::Command::Restart => cli::restart(),
cli::Command::Install => service::install(),
cli::Command::Uninstall => service::uninstall(),
cli::Command::Foreground => run_server().await,
}
}
async fn run_server() -> anyhow::Result<()> {
routines::ensure_default_agents();
let store = storage::load_store();
routine_storage::migrate_prompt_files();
routine_storage::migrate_routine_dirs();
let routines = routine_storage::load_store();
routines::ensure_default_routines(&routines);
routine_storage::repersist_routines(&routines);
if let Err(err) = sync::routines::sync_routines_to_crontab(&routines) {
log::warn!("startup crontab sync failed: {err}");
}
let listener = tokio::net::TcpListener::bind(cli::bind_addr()).await?;
cli::write_pid_file()?;
let result =
routes::http::run_with_listener_until(store, routines, listener, termination_signal())
.await;
cli::clear_pid_file();
result
}
async fn termination_signal() {
#[cfg(unix)]
{
use tokio::signal::unix::{signal, SignalKind};
match signal(SignalKind::terminate()) {
Ok(mut term) => {
tokio::select! {
_ = tokio::signal::ctrl_c() => {}
_ = term.recv() => {}
}
}
Err(_) => {
let _ = tokio::signal::ctrl_c().await;
}
}
}
#[cfg(not(unix))]
{
let _ = tokio::signal::ctrl_c().await;
}
}