#![feature(lazy_cell)] use dotenv::var; use log::LevelFilter; use std::collections::BTreeMap; use std::fs::File; use std::sync::Arc; use lfm_embed::{STATE, ResponseCtx}; use lfm_embed::font::FontQuery; use warp::Filter; #[derive(serde::Deserialize, Debug)] #[serde(rename = "kebab-case")] struct UserQuery { #[serde(default)] theme: Option>, #[serde(flatten)] #[serde(default)] font: Option, #[serde(flatten)] rest: BTreeMap } #[tokio::main] async fn main() { env_logger::Builder::new() .filter_level(LevelFilter::Warn) .parse_filters(&var("LFME_LOG_LEVEL").unwrap_or_default()) .target( var("LFME_LOG_FILE").ok() .map( |f| env_logger::Target::Pipe( Box::new(File::options() .append(true) .open(f) .expect("couldn't open LFME_LOG_FILE"))) ) .unwrap_or(env_logger::Target::Stderr) ).init(); std::sync::LazyLock::force(&STATE); let user = warp::path!("user" / String) .and(warp::query::()) .then(|s, q: UserQuery| async move { log::debug!(target: "lfm::server::user", "Handling request for user `{s}` with {q:?}"); let (ctx, dur) = STATE.get_userinfo(&s).await; let ResponseCtx(mut data, status) = ResponseCtx::create(ctx, q.font, q.rest).await; let theme = q.theme.filter(|a| STATE.handlebars().has_template(&a)).unwrap_or_else(|| STATE.default_theme()); log::debug!(target: "lfm::server::user", "Using theme {theme}"); warp::reply::with_header( warp::reply::with_header( warp::reply::with_status( warp::reply::html( STATE.handlebars().render(&theme, &data).unwrap() ), status ), "Refresh", dur.as_secs() ), "X-Selected-Theme", theme.as_ref() ) }); warp::serve(user) .bind(([127,0,0,1], STATE.port())).await; }