use super::errors::AppError;
use figment::{
Figment,
providers::{Env, Format as _, Serialized, Toml},
};
use std::io::stdout;
use serde::{Serialize, de::DeserializeOwned};
use tracing::Level;
use tracing_appender::{self, non_blocking, non_blocking::WorkerGuard, rolling::daily};
use tracing_subscriber::{
EnvFilter,
fmt::{layer, writer::MakeWriterExt as _},
layer::SubscriberExt as _,
registry,
util::SubscriberInitExt as _,
};
#[cfg(feature = "tera")]
use ::{
include_dir::Dir,
std::sync::Arc,
tera::Tera,
};
#[expect(clippy::result_large_err, reason = "Size doesn't matter here as it's only for config")]
pub fn load_config<T>() -> Result<T, AppError>
where
T: Default + DeserializeOwned + Serialize,
{
Ok(Figment::from(Serialized::defaults(T::default()))
.merge(Toml::file("Config.toml"))
.merge(Env::raw())
.extract()?)
}
pub fn setup_logging<S: AsRef<str>>(logdir: S) -> WorkerGuard {
let (non_blocking_appender, guard) = non_blocking(
daily(logdir.as_ref(), "general.log")
);
registry()
.with(
EnvFilter::try_from_default_env()
.unwrap_or_else(|_| format!(
"info,{}=debug,terracotta=debug,tower_http=debug",
env!("CARGO_PKG_NAME"),
).into()),
)
.with(
layer()
.with_writer(stdout.with_max_level(Level::DEBUG))
)
.with(
layer()
.with_writer(non_blocking_appender.with_max_level(Level::INFO))
)
.init()
;
guard
}
#[cfg(feature = "tera")]
#[expect(clippy::result_large_err, reason = "Size doesn't matter here as it's only for config")]
pub fn setup_tera(template_dir: &Arc<Dir<'static>>) -> Result<Tera, AppError> {
let templates = template_dir
.find("**/*.tera.html")?
.map(|file| {
Ok((
file
.path()
.file_name()
.and_then(|f| f.to_str())
.and_then(|f| f.strip_suffix(".tera.html"))
.ok_or_else(|| AppError::InvalidTemplatePath(file.path().to_path_buf()))?
.to_owned()
,
template_dir
.get_file(file.path())
.ok_or_else(|| AppError::TemplateFileNotFound(file.path().to_path_buf()))?
.contents_utf8()
.ok_or_else(|| AppError::InvalidTemplateEncoding(file.path().to_path_buf()))?
,
))
}).collect::<Result<Vec<_>, AppError>>()?
;
let mut tera = Tera::default();
tera.add_raw_templates(templates)?;
tera.autoescape_on(vec![".tera.html", ".html"]);
Ok(tera)
}