aboutsummaryrefslogtreecommitdiffstats
path: root/src/cache/font.rs
blob: a238a87d509e60fc378fb05ad61d7c50660e86a1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 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<Arc<str>>,
  pub include_font: Option<Arc<str>>,
  pub google_font: Option<Arc<str>>,
//  pub small_font: Option<()>
}

pub type FontFuture = CacheFuture<Arc<str>>;
pub type FontGetter = CacheGetter<Arc<str>>;
pub type FontCache  = Cache<Arc<str>>;

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<Client> = crate::http::lazy();

static FONT_CACHE: LazyLock<FontCache> =  LazyLock::new(|| {
  Arc::new(RwLock::new(AsyncCache::new(Duration::from_secs(86400), font_getter as FontGetter)))
});

pub async fn get_fontinfo(font: &String) -> Result<Arc<str>, (StatusCode, &'static str)> {
  FONT_CACHE.write().await.get_owned(font).await
}

pub fn touch() {
  LazyLock::force(&FONT_CACHE);
}