diff --git a/packages/backend-rs/src/cache/redis.rs b/packages/backend-rs/src/cache/redis.rs index 5403fbd603..83cbd616d0 100644 --- a/packages/backend-rs/src/cache/redis.rs +++ b/packages/backend-rs/src/cache/redis.rs @@ -1,6 +1,7 @@ //! Utilities for using Redis cache use crate::database::{redis_conn, redis_key, RedisConnError}; +use chrono::Duration; use redis::{AsyncCommands, RedisError}; use serde::{Deserialize, Serialize}; @@ -23,6 +24,8 @@ pub enum Error { RedisConn(#[from] RedisConnError), #[error("failed to encode data for Redis")] Encode(#[from] rmp_serde::encode::Error), + #[error("invalid cache TTL")] + TTL, } #[inline] @@ -56,18 +59,19 @@ fn wildcard(category: Category) -> String { /// /// * `key` : key (prefixed automatically) /// * `value` : (de)serializable value -/// * `expire_seconds` : TTL +/// * `ttl` : cache lifetime /// /// # Example /// /// ``` /// # use backend_rs::cache; +/// use chrono::Duration; /// # async fn f() -> Result<(), Box> { /// let key = "apple"; /// let data = "I want to cache this string".to_owned(); /// /// // caches the data for 10 seconds -/// cache::set(key, &data, 10).await?; +/// cache::set(key, &data, Duration::seconds(10)).await?; /// /// // get the cache /// let cached_data = cache::get::(key).await?; @@ -80,14 +84,14 @@ fn wildcard(category: Category) -> String { pub async fn set Deserialize<'a> + Serialize>( key: &str, value: &V, - expire_seconds: u64, + ttl: Duration, ) -> Result<(), Error> { redis_conn() .await? .set_ex( prefix_key(key), rmp_serde::encode::to_vec(&value)?, - expire_seconds, + ttl.num_seconds().try_into().map_err(|_| Error::TTL)?, ) .await?; Ok(()) @@ -176,14 +180,14 @@ pub async fn delete(key: &str) -> Result<(), Error> { /// * `category` : one of [Category] /// * `key` : key (prefixed automatically) /// * `value` : (de)serializable value -/// * `expire_seconds` : TTL +/// * `ttl` : cache lifetime pub async fn set_one Deserialize<'a> + Serialize>( category: Category, key: &str, value: &V, - expire_seconds: u64, + ttl: Duration, ) -> Result<(), Error> { - set(&categorize(category, key), value, expire_seconds).await + set(&categorize(category, key), value, ttl).await } /// Gets a Redis cache under a `category`. @@ -233,6 +237,7 @@ pub async fn delete_all(category: Category) -> Result<(), Error> { mod unit_test { use super::{delete_all, get, get_one, set, set_one, Category::Test}; use crate::cache::delete_one; + use chrono::Duration; use pretty_assertions::assert_eq; #[tokio::test] @@ -256,9 +261,9 @@ mod unit_test { kind: "prime number".to_owned(), }; - set(key_1, &value_1, 1).await.unwrap(); - set(key_2, &value_2, 1).await.unwrap(); - set(key_3, &value_3, 1).await.unwrap(); + set(key_1, &value_1, Duration::seconds(1)).await.unwrap(); + set(key_2, &value_2, Duration::seconds(1)).await.unwrap(); + set(key_3, &value_3, Duration::seconds(1)).await.unwrap(); let cached_value_1: Vec = get(key_1).await.unwrap().unwrap(); let cached_value_2: String = get(key_2).await.unwrap().unwrap(); @@ -291,9 +296,15 @@ mod unit_test { let value_2 = 998244353u32; let value_3 = 'あ'; - set_one(Test, key_1, &value_1, 5 * 60).await.unwrap(); - set_one(Test, key_2, &value_2, 5 * 60).await.unwrap(); - set_one(Test, key_3, &value_3, 5 * 60).await.unwrap(); + set_one(Test, key_1, &value_1, Duration::minutes(5)) + .await + .unwrap(); + set_one(Test, key_2, &value_2, Duration::minutes(5)) + .await + .unwrap(); + set_one(Test, key_3, &value_3, Duration::minutes(5)) + .await + .unwrap(); assert_eq!( get_one::(Test, key_1).await.unwrap().unwrap(), diff --git a/packages/backend-rs/src/misc/get_image_size.rs b/packages/backend-rs/src/misc/get_image_size.rs index 19c98fa496..89498e46ed 100644 --- a/packages/backend-rs/src/misc/get_image_size.rs +++ b/packages/backend-rs/src/misc/get_image_size.rs @@ -1,4 +1,5 @@ use crate::{cache, util::http_client}; +use chrono::Duration; use futures_util::AsyncReadExt; use image::{ImageError, ImageFormat, ImageReader}; use isahc::AsyncReadResponseExt; @@ -63,7 +64,7 @@ pub async fn get_image_size_from_url(url: &str) -> Result { .is_some(); if !attempted { - cache::set_one(cache::Category::FetchUrl, url, &true, 10 * 60).await?; + cache::set_one(cache::Category::FetchUrl, url, &true, Duration::minutes(10)).await?; } } diff --git a/packages/backend-rs/src/misc/latest_version.rs b/packages/backend-rs/src/misc/latest_version.rs index 871e54cccb..487c3f95fe 100644 --- a/packages/backend-rs/src/misc/latest_version.rs +++ b/packages/backend-rs/src/misc/latest_version.rs @@ -1,6 +1,7 @@ //! Fetch latest Firefish version from the Firefish repository use crate::{cache, util::http_client}; +use chrono::Duration; use futures_util::AsyncReadExt; use isahc::AsyncReadResponseExt; use serde::Deserialize; @@ -65,7 +66,7 @@ pub async fn latest_version() -> Result { cache::Category::FetchUrl, UPSTREAM_PACKAGE_JSON_URL, &fetched_version, - 3 * 60 * 60, + Duration::hours(3), ) .await?; Ok(fetched_version) diff --git a/packages/backend-rs/src/misc/random_icon.rs b/packages/backend-rs/src/misc/random_icon.rs index aa6c09a836..c5463ebc18 100644 --- a/packages/backend-rs/src/misc/random_icon.rs +++ b/packages/backend-rs/src/misc/random_icon.rs @@ -1,4 +1,5 @@ use crate::cache; +use chrono::Duration; use identicon_rs::{error::IdenticonError, Identicon}; #[macros::errors] @@ -18,7 +19,13 @@ pub async fn generate(id: &str) -> Result, Error> { .set_border(16) .set_scale(96)? .export_png_data()?; - cache::set_one(cache::Category::RandomIcon, id, &icon, 10 * 60).await?; + cache::set_one( + cache::Category::RandomIcon, + id, + &icon, + Duration::minutes(10), + ) + .await?; Ok(icon) } } diff --git a/packages/backend-rs/src/misc/should_nyaify.rs b/packages/backend-rs/src/misc/should_nyaify.rs index 9f609c69a3..66e54f5996 100644 --- a/packages/backend-rs/src/misc/should_nyaify.rs +++ b/packages/backend-rs/src/misc/should_nyaify.rs @@ -1,6 +1,7 @@ //! Determine whether to enable the cat language conversion use crate::{cache, database::db_conn, model::entity::user}; +use chrono::Duration; use sea_orm::{DbErr, EntityTrait, QuerySelect, SelectColumns}; #[macros::errors] @@ -35,7 +36,7 @@ pub async fn should_nyaify(reader_user_id: &str) -> Result { cache::Category::CatLang, reader_user_id, &fetched_value, - 10 * 60, + Duration::minutes(10), ) .await?; diff --git a/packages/backend-rs/src/service/antenna/check_hit.rs b/packages/backend-rs/src/service/antenna/check_hit.rs index 4fd2c06c28..87ed46ee70 100644 --- a/packages/backend-rs/src/service/antenna/check_hit.rs +++ b/packages/backend-rs/src/service/antenna/check_hit.rs @@ -5,6 +5,7 @@ use crate::{ federation::acct::Acct, model::entity::{antenna, blocking, following, note, sea_orm_active_enums::*}, }; +use chrono::Duration; use sea_orm::{prelude::*, QuerySelect}; #[macros::errors] @@ -109,7 +110,13 @@ pub(super) async fn check_hit_antenna( .into_tuple::() .all(db) .await?; - cache::set_one(cache::Category::Block, ¬e.user_id, &blocks, 10 * 60).await?; + cache::set_one( + cache::Category::Block, + ¬e.user_id, + &blocks, + Duration::minutes(10), + ) + .await?; blocks }; @@ -138,7 +145,7 @@ pub(super) async fn check_hit_antenna( cache::Category::Follow, &antenna.user_id, &following, - 10 * 60, + Duration::minutes(10), ) .await?; following