use std::{path::PathBuf, time::Duration};
use anyhow::Result;
use clap::Parser;
use config::Config;
use storage::{FsController, cleanup_routine};
use tokio::signal::unix::{SignalKind, signal};
use tokio_util::sync::CancellationToken;
use tracing::{Level, info};
use utils::{byte_size_str, large_secs_str};
mod config;
mod server;
mod storage;
mod utils;
#[derive(Parser, Debug)]
#[command(version, about)]
struct Args {
#[arg(long)]
data_dir: Option<PathBuf>,
#[arg(long)]
ip_addr: Option<String>,
#[arg(long)]
domain: Option<String>,
#[arg(long)]
presign_api_key: Option<String>,
#[arg(short, long)]
config: Option<PathBuf>,
#[arg(short, long, default_value = "false")]
verbose: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Args::parse();
let level = if args.verbose {
Level::DEBUG
} else {
Level::INFO
};
tracing_subscriber::fmt().with_max_level(level).init();
let config = Config::init(args)?;
info!("📦 Data-Directory: {}", config.data_dir.display());
info!("🔒 Domain: {}", config.domain);
info!("🌐 Listening on {}", config.ip_addr);
info!(
"🌐 Presign-API request size limit: {}",
byte_size_str(config.max_presign_rq_size)
);
info!(
"🌐 Data-API request size limit: {}",
byte_size_str(config.max_data_rq_size)
);
info!("🌐 Request-Timeout: {}s", config.rq_timeout_secs);
let fs_controller = FsController::init(&config.data_dir)?;
let shutdown_token = CancellationToken::new();
let fs = fs_controller.clone();
let ttl_orphan_secs = config.ttl_orphan_secs;
let cleanup_task = tokio::spawn(async move {
info!(
"🪣 Started cleanup task - orphan timeout {}",
large_secs_str(ttl_orphan_secs)
);
loop {
info!("🧹 Performing cleanup routine...");
cleanup_routine(fs.clone(), ttl_orphan_secs).await;
tokio::time::sleep(Duration::from_secs(2 * ttl_orphan_secs)).await;
}
});
tokio::spawn(signal_handler(shutdown_token.clone()));
server::start(config, fs_controller, shutdown_token).await?;
cleanup_task.abort();
Ok(())
}
async fn signal_handler(shutdown_token: CancellationToken) {
let mut sigterm =
signal(SignalKind::terminate()).expect("failed to register interrupt handler for SIGTERM");
let mut sigint =
signal(SignalKind::interrupt()).expect("failed to register interrupt handler for SIGINT");
tokio::select! {
_ = sigterm.recv() => {
info!("🪦 Termination signal received (SIGTERM), gracefully shutting down.");
}
_ = sigint.recv() => {
info!("⛔ Interrupt received (SIGINT), gracefully shutting down.");
}
}
shutdown_token.cancel();
}