gitdataai/libs/transport/dedup.rs

72 lines
1.8 KiB
Rust

use redis::AsyncCommands;
use std::time::Duration;
use uuid::Uuid;
#[derive(Clone)]
pub struct DeduplicationManager {
cache: db::cache::AppCache,
window: Duration,
}
impl DeduplicationManager {
pub fn new(cache: db::cache::AppCache) -> Self {
Self {
cache,
window: Duration::from_secs(300),
}
}
pub async fn check_and_mark(
&self,
message_id: Uuid,
room_id: Uuid,
) -> Result<bool, crate::error::AppTransportError> {
let key = format!("dedup:{}:{}", room_id, message_id);
let mut conn = self
.cache
.conn()
.await
.map_err(|_| crate::error::AppTransportError::Internal)?;
// Use atomic SET NX EX to prevent race conditions.
// Returns true if the key was set (not a duplicate), false if it already exists.
let result: Option<String> = redis::cmd("SET")
.arg(&key)
.arg("1")
.arg("NX")
.arg("EX")
.arg(self.window.as_secs())
.query_async(&mut conn)
.await
.map_err(|_| crate::error::AppTransportError::Internal)?;
Ok(result.is_some())
}
pub async fn is_duplicate(
&self,
message_id: Uuid,
room_id: Uuid,
) -> Result<bool, crate::error::AppTransportError> {
let key = format!("dedup:{}:{}", room_id, message_id);
let mut conn = self
.cache
.conn()
.await
.map_err(|_| crate::error::AppTransportError::Internal)?;
let exists: bool = conn
.exists(&key)
.await
.map_err(|_| crate::error::AppTransportError::Internal)?;
Ok(exists)
}
pub async fn cleanup_expired(&self) -> Result<(), crate::error::AppTransportError> {
Ok(())
}
}