vnj/bin/main.rs
2024-11-17 18:43:15 +03:00

79 lines
2.1 KiB
Rust

use std::{
fs,
future::IntoFuture,
path::{Path, PathBuf},
};
use clap::Parser;
use eyre::Context;
use tokio::{net::TcpListener, runtime as rt};
use tracing_subscriber::FmtSubscriber;
use vnj::{app::App, cfg, db::Db, notifies, state::State};
#[derive(Debug, Parser)]
pub struct Args {
/// Path to the TOML config.
#[clap(long, short)]
pub config: PathBuf,
}
async fn run(cfg: cfg::Root) -> eyre::Result<()> {
let listener = TcpListener::bind(cfg.http.listen)
.await
.wrap_err("failed to bind HTTP port")?;
let db = Db::from_root(&cfg.app.journal)?;
let notifies = notifies::make();
let app = App::new(db, notifies.clone())?;
let state = State::new(app, cfg)?;
let daemon = tokio::spawn(vnj::daemon::run(state.clone(), notifies.clone()));
let router = vnj::http::make(state.clone()).with_state(state);
tracing::info!("listening on {}", listener.local_addr()?);
let server = tokio::spawn(axum::serve(listener, router).into_future());
tokio::try_join!(daemon, server)
.wrap_err("error while running")?
.0?;
Ok(())
}
fn read_config(path: &Path) -> eyre::Result<cfg::Root> {
let contents = fs::read_to_string(path).wrap_err("failed to read")?;
let cfg: cfg::Root = toml::from_str(&contents).wrap_err("failed to parse TOML")?;
Ok(cfg)
}
fn setup_logger(level: cfg::LogLevel) -> eyre::Result<()> {
let level: Option<tracing::Level> = level.into();
let subscriber = FmtSubscriber::builder();
let subscriber = if let Some(level) = level {
subscriber.with_max_level(level)
} else {
subscriber.with_max_level(tracing::level_filters::LevelFilter::OFF)
};
let subscriber = subscriber.finish();
tracing::subscriber::set_global_default(subscriber)?;
Ok(())
}
fn main() -> eyre::Result<()> {
let rt = rt::Builder::new_current_thread()
.enable_all()
.thread_name("vnj")
.build()
.wrap_err("failed to create tokio runtime")?;
let args = Args::parse();
let cfg = read_config(&args.config).wrap_err("failed to load the config")?;
setup_logger(cfg.app.log_level)?;
rt.block_on(run(cfg))
}