#![feature(lazy_cell)] use std::collections::BTreeMap; use std::fs::File; use std::sync::Arc; use lfm_embed::{CONFIG, ResponseCtx}; use lfm_embed::cache::font::FontQuery; use log::LevelFilter; use dotenv::var; 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(); let user = warp::path!("user" / String) .and(warp::query::()) .then(|s, q: UserQuery| async move { log::debug!(target: "lfm_embed::server::user", "Handling request for user `{s}` with {q:?}"); let (ctx, dur) = lfm_embed::cache::user::get_userinfo(&s).await; let ResponseCtx(data, status) = ResponseCtx::create(ctx, q.font, q.rest).await; let (theme, res) = lfm_embed::theming::render_theme(q.theme.as_deref(), &data); log::debug!(target: "lfm_embed::server::user", "Using theme {theme}"); match res { Err(status) => Box::new(warp::reply::with_status(warp::reply::html("

Internal Server Error.

"), status)) as Box, Ok(contents) => Box::new(warp::reply::with_header( warp::reply::with_header( warp::reply::with_status( warp::reply::html( contents ), status ), "Refresh", dur.as_secs() ), "X-Selected-Theme", theme )) as Box } }); warp::serve(user) .bind(([127,0,0,1], CONFIG.port())).await; }