aboutsummaryrefslogblamecommitdiffstats
path: root/src/cache/font.rs
blob: 5be2196443dbf0368a5b367a2eb8dbb4a450ebe3 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                                         
                   
                        
                        

                        
                                  
 

                                                         






                                             
                                    

                              







                                                                    
                                                            



                     
                                                                                                                               







                                                                                                                                                            
                                                                                         






                                                                                                                                                     


                                                            
                                                                                               



                                                                                          
 
// 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
}