chore (backend-rs): cache generated icons

This commit is contained in:
naskya 2024-07-29 23:48:55 +09:00
parent 07c5bfa600
commit 2c35a3885c
No known key found for this signature in database
GPG key ID: 712D413B3A9FED5C
4 changed files with 24 additions and 6 deletions

View file

@ -495,7 +495,7 @@ export declare function genId(): string
/** Generate an ID using a specific datetime */ /** Generate an ID using a specific datetime */
export declare function genIdAt(date: Date): string export declare function genIdAt(date: Date): string
export declare function genIdenticon(id: string): Buffer export declare function genIdenticon(id: string): Promise<Buffer>
export declare function getFullApAccount(username: string, host?: string | undefined | null): string export declare function getFullApAccount(username: string, host?: string | undefined | null): string

View file

@ -10,6 +10,7 @@ pub enum Category {
Block, Block,
Follow, Follow,
CatLang, CatLang,
RandomIcon,
#[cfg(test)] #[cfg(test)]
Test, Test,
} }
@ -35,6 +36,7 @@ fn categorize(category: Category, key: &str) -> String {
Category::Block => "blocking", Category::Block => "blocking",
Category::Follow => "following", Category::Follow => "following",
Category::CatLang => "catlang", Category::CatLang => "catlang",
Category::RandomIcon => "randomIcon",
#[cfg(test)] #[cfg(test)]
Category::Test => "usedOnlyForTesting", Category::Test => "usedOnlyForTesting",
}; };

View file

@ -1,13 +1,29 @@
use identicon_rs::{error::IdenticonError, Identicon}; use identicon_rs::{error::IdenticonError, Identicon};
use crate::database::cache;
pub fn generate(id: &str) -> Result<Vec<u8>, IdenticonError> { #[macros::errors]
Identicon::new(id).set_border(35).export_png_data() pub enum Error {
#[doc = "failed to generate identicon"]
#[error(transparent)]
Identicon(#[from] IdenticonError),
#[error("Redis cache operation has failed")]
Cache(#[from] cache::Error),
}
pub async fn generate(id: &str) -> Result<Vec<u8>, Error> {
if let Some(icon) = cache::get_one::<Vec<u8>>(cache::Category::RandomIcon, id).await? {
Ok(icon)
} else {
let icon = Identicon::new(id).set_border(35).export_png_data()?;
cache::set_one(cache::Category::RandomIcon, id, &icon, 10 * 60).await?;
Ok(icon)
}
} }
#[cfg(feature = "napi")] #[cfg(feature = "napi")]
#[napi_derive::napi(js_name = "genIdenticon")] #[napi_derive::napi(js_name = "genIdenticon")]
pub fn generate_js(id: String) -> napi::Result<napi::bindgen_prelude::Buffer> { pub async fn generate_js(id: String) -> napi::Result<napi::bindgen_prelude::Buffer> {
match generate(&id) { match generate(&id).await {
Ok(icon) => Ok(icon.into()), Ok(icon) => Ok(icon.into()),
Err(err) => Err(napi::Error::from_reason(format!( Err(err) => Err(napi::Error::from_reason(format!(
"\n{}\n", "\n{}\n",

View file

@ -118,7 +118,7 @@ router.get("/avatar/@:acct", async (ctx) => {
router.get("/identicon/:x", async (ctx) => { router.get("/identicon/:x", async (ctx) => {
const instanceMeta = await fetchMeta(); const instanceMeta = await fetchMeta();
if (instanceMeta.enableIdenticonGeneration) { if (instanceMeta.enableIdenticonGeneration) {
const identicon = genIdenticon(ctx.params.x); const identicon = await genIdenticon(ctx.params.x);
const [temp, cleanup] = await createTemp(); const [temp, cleanup] = await createTemp();
fs.createWriteStream(temp).write(identicon); fs.createWriteStream(temp).write(identicon);
ctx.set("Content-Type", "image/png"); ctx.set("Content-Type", "image/png");