use std::{collections::HashMap, sync::OnceLock, time::Instant}; use log::warn; use rocket::{get, http::CookieJar, serde::json::json, State}; use serde::Serialize; use serenity::{client::Context, model::id::GuildId}; use tokio::sync::RwLock; use crate::web::{check_authorization, routes::JsonResult}; #[derive(Serialize, Clone)] struct EmojiInfo { fmt: String, name: String, } #[derive(Clone)] struct EmojiCache { emojis: Vec, timestamp: Instant, } const CACHE_LENGTH: u64 = 120; static EMOJI_CACHE: OnceLock>> = OnceLock::new(); #[get("/api/guild//emojis")] pub async fn get_guild_emojis( id: u64, cookies: &CookieJar<'_>, ctx: &State, ) -> JsonResult { offline!(Ok(json!(vec![] as Vec))); check_authorization(cookies, ctx.inner(), id).await?; let cache_value = { let cache = EMOJI_CACHE.get_or_init(|| RwLock::new(HashMap::new())); let read_lock = cache.read().await; read_lock.get(&GuildId::new(id)).cloned() }; if let Some(emojis) = cache_value .map(|v| { if Instant::now().duration_since(v.timestamp).as_secs() < CACHE_LENGTH { Some(v.emojis) } else { None } }) .flatten() { Ok(json!(emojis)) } else { let emojis_res = ctx.http.get_emojis(GuildId::new(id)).await; match emojis_res { Ok(emojis) => { let emojis = emojis .iter() .map(|emoji| EmojiInfo { fmt: format!("{}", emoji), name: emoji.name.to_string(), }) .collect::>(); { let cache = EMOJI_CACHE.get_or_init(|| RwLock::new(HashMap::new())); let mut write_lock = cache.write().await; write_lock.insert( GuildId::new(id), EmojiCache { emojis: emojis.clone(), timestamp: Instant::now() }, ); } Ok(json!(emojis)) } Err(e) => { warn!("Could not fetch emojis from {}: {:?}", id, e); json_err!("Could not get emojis") } } } }