chir.rs/src/main.rs

138 lines
4.7 KiB
Rust

//! Main entrypoint for the chir-rs web server
use core::str::FromStr;
use std::sync::Arc;
use chir_rs_config::ChirRs;
use eyre::{Context, Result};
// implicitly used
use sentry_eyre as _;
use tokio::signal;
use tracing::error;
use tracing_error::ErrorLayer;
use tracing_subscriber::{
fmt::format::JsonFields, layer::SubscriberExt as _, util::SubscriberInitExt as _, Layer,
};
/// Initializes logging for the application
fn init_logging(cfg: &ChirRs) -> Result<()> {
let log_filter = tracing_subscriber::EnvFilter::from_str(&cfg.logging.log_level)
.with_context(|| format!("Setting log filter to {}", cfg.logging.log_level))?;
match cfg.logging.log_style {
chir_rs_config::LogFormat::Full => {
let log_format = tracing_subscriber::fmt::format();
tracing_subscriber::registry()
.with(ErrorLayer::default())
.with(sentry_tracing::layer())
.with(
tracing_subscriber::fmt::layer()
.event_format(log_format)
.with_filter(log_filter),
)
.init();
}
chir_rs_config::LogFormat::Compact => {
let log_format = tracing_subscriber::fmt::format().compact();
tracing_subscriber::registry()
.with(ErrorLayer::default())
.with(sentry_tracing::layer())
.with(
tracing_subscriber::fmt::layer()
.event_format(log_format)
.with_filter(log_filter),
)
.init();
}
chir_rs_config::LogFormat::Pretty => {
let log_format = tracing_subscriber::fmt::format().pretty();
tracing_subscriber::registry()
.with(ErrorLayer::default())
.with(sentry_tracing::layer())
.with(
tracing_subscriber::fmt::layer()
.event_format(log_format)
.with_filter(log_filter),
)
.init();
}
chir_rs_config::LogFormat::Json => {
let log_format = tracing_subscriber::fmt::format().json();
tracing_subscriber::registry()
.with(ErrorLayer::default())
.with(sentry_tracing::layer())
.with(
tracing_subscriber::fmt::layer()
.event_format(log_format)
.fmt_fields(JsonFields::new())
.with_filter(log_filter),
)
.init();
}
}
Ok(())
}
fn main() -> Result<()> {
color_eyre::install().ok();
dotenvy::dotenv().ok();
// NO THREADS BEFORE THIS POINT
let cfg = ChirRs::read_from_env().context("Reading chir.rs configuration")?;
let _guard = sentry::init(sentry::ClientOptions {
dsn: cfg.logging.sentry_dsn.clone(),
release: sentry::release_name!(),
traces_sample_rate: 0.1,
attach_stacktrace: true,
debug: cfg!(debug_assertions),
..Default::default()
});
init_logging(&cfg)?;
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.context("Building thread pool for tokio")?
.block_on(async move {
let cfg = Arc::new(cfg);
let db = chir_rs_db::open_database(&cfg.database.path).await?;
let castore = chir_rs_castore::CaStore::new(&cfg).await?;
let cfg1 = Arc::clone(&cfg);
let cfg2 = Arc::clone(&cfg);
let db1 = db.clone();
let db2 = db.clone();
let castore1 = castore.clone();
let castore2 = castore.clone();
let jobs = [
tokio::spawn(chir_rs_db::session::expire_sessions_job(db.clone())),
tokio::spawn(async move {
if let Err(e) = chir_rs_http::main(cfg1, db1, castore1).await {
error!("Failing to start HTTP Server: {e:?}");
}
}),
tokio::spawn(async move {
if let Err(e) = chir_rs_gemini::main(cfg2, db2, castore2).await {
error!("Failing to start Gemini Server: {e:?}");
}
}),
];
signal::ctrl_c()
.await
.context("Trying to register ctrl+c handler")?;
for job in jobs {
job.abort();
if let Err(e) = job.await {
if e.is_panic() {
error!("Failed running job: {e:?}");
}
}
}
Ok::<_, eyre::Report>(())
})
.context("Running chir.rs")
}