// SPDX-License-Identifier: AGPL-3.0-only use std::sync::Arc; use std::time::Duration; use std::sync::LazyLock; use tokio::sync::RwLock; use reqwest::{StatusCode, Client}; use super::{CacheFuture, CacheGetter, Cache, AsyncCache}; use crate::CONFIG; #[derive(serde::Deserialize, Debug, Default)] #[serde(default)] #[serde(rename = "kebab-case")] pub struct FontQuery { pub font: Option>, pub include_font: Option>, pub google_font: Option>, // pub small_font: Option<()> } pub type FontFuture = CacheFuture>; pub type FontGetter = CacheGetter>; pub type FontCache = Cache>; fn font_getter(fontname: &String) -> FontFuture { let fontname = urlencoding::encode(fontname.as_ref()).to_string(); Box::pin(async move { let Some(google_api_key) = CONFIG.google_api_key.clone() else { unreachable!(); }; let fontreq = HTTP.get(format!("https://www.googleapis.com/webfonts/v1/webfonts?key={}&family={fontname}", google_api_key)) .send().await .map_err(|e| {log::error!("Failed to get info for font `{fontname}`: {e}"); (StatusCode::SERVICE_UNAVAILABLE, "Couldn't connect to Google Fonts!")})?; if fontreq.status() == StatusCode::NOT_FOUND { return Err((StatusCode::NOT_FOUND, "Font does not exist!")); } if fontreq.status() == StatusCode::FORBIDDEN { log::error!("Invalid Google API key in config!"); return Err((StatusCode::SERVICE_UNAVAILABLE, "This instance is not configured to support Google Fonts properly, please use a different font.")); } let cssreq = HTTP.get(format!("https://fonts.googleapis.com/css2?family={fontname}")) .send().await .map_err(|e| {log::error!("Failed to get CSS for font `{fontname}`: {e}"); (StatusCode::SERVICE_UNAVAILABLE, "Couldn't download font CSS!")})?; Ok(cssreq.text().await.unwrap().into()) }) } static HTTP: LazyLock = crate::http::lazy(); static FONT_CACHE: LazyLock = LazyLock::new(|| { Arc::new(RwLock::new(AsyncCache::new(Duration::from_secs(86400), font_getter as FontGetter))) }); pub async fn get_fontinfo(font: &String) -> Result, (StatusCode, &'static str)> { FONT_CACHE.write().await.get_owned(font).await } pub fn touch() { LazyLock::force(&FONT_CACHE); }