Skip to content
Clone
d3ac05f
139 lines 3.7 KB Rust
use std::sync::Arc;
use cache::redis::RedisCache;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Clone)]
pub struct ProjectCache {
kv: Arc<RedisCache>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CachedProjectDetail {
pub id: Uuid,
pub space_id: Uuid,
pub name: String,
pub state: i32,
}
impl ProjectCache {
pub fn new(kv: Arc<RedisCache>) -> Self {
Self { kv }
}
fn project_key(id: Uuid) -> String {
format!("project:{}", id)
}
fn member_role_key(project_id: Uuid, user_id: Uuid) -> String {
format!("pm_role:{}:{}", project_id, user_id)
}
fn favorites_key(user_id: Uuid) -> String {
format!("fav:{}", user_id)
}
pub async fn get_project(
&self,
project_id: Uuid,
) -> Result<Option<CachedProjectDetail>, crate::error::ProjectError> {
let raw = self
.kv
.get_bytes(&Self::project_key(project_id))
.await
.map_err(|e| crate::error::ProjectError::Cache(e.to_string()))?;
match raw {
Some(b) => match serde_json::from_slice::<CachedProjectDetail>(&b) {
Ok(v) => Ok(Some(v)),
Err(_) => Ok(None),
},
None => Ok(None),
}
}
pub async fn put_project(
&self,
detail: &CachedProjectDetail,
ttl_secs: u64,
) -> Result<(), crate::error::ProjectError> {
let bytes = serde_json::to_vec(detail)?;
self.kv
.set_bytes(&Self::project_key(detail.id), bytes, ttl_secs)
.await
.map_err(|e| crate::error::ProjectError::Cache(e.to_string()))?;
Ok(())
}
pub async fn invalidate_project(
&self,
project_id: Uuid,
) -> Result<(), crate::error::ProjectError> {
self.kv
.delete(&Self::project_key(project_id))
.await
.map_err(|e| crate::error::ProjectError::Cache(e.to_string()))?;
Ok(())
}
pub async fn get_member_role(
&self,
project_id: Uuid,
user_id: Uuid,
) -> Result<Option<i32>, crate::error::ProjectError> {
let raw = self
.kv
.get_bytes(&Self::member_role_key(project_id, user_id))
.await
.map_err(|e| crate::error::ProjectError::Cache(e.to_string()))?;
let Some(b) = raw else {
return Ok(None);
};
if b.len() != 4 {
return Ok(None);
}
let arr: [u8; 4] = [b[0], b[1], b[2], b[3]];
Ok(Some(i32::from_le_bytes(arr)))
}
pub async fn put_member_role(
&self,
project_id: Uuid,
user_id: Uuid,
role: i32,
ttl_secs: u64,
) -> Result<(), crate::error::ProjectError> {
self.kv
.set_bytes(
&Self::member_role_key(project_id, user_id),
role.to_le_bytes().to_vec(),
ttl_secs,
)
.await
.map_err(|e| crate::error::ProjectError::Cache(e.to_string()))?;
Ok(())
}
pub async fn invalidate_member_role(
&self,
project_id: Uuid,
user_id: Uuid,
) -> Result<(), crate::error::ProjectError> {
self.kv
.delete(&Self::member_role_key(project_id, user_id))
.await
.map_err(|e| crate::error::ProjectError::Cache(e.to_string()))?;
Ok(())
}
pub async fn invalidate_favorites(
&self,
user_id: Uuid,
) -> Result<(), crate::error::ProjectError> {
self.kv
.delete(&Self::favorites_key(user_id))
.await
.map_err(|e| crate::error::ProjectError::Cache(e.to_string()))?;
Ok(())
}
}