use uuid::Uuid; use crate::cache::redis::AppRedis; use crate::error::{AppError, AppResult}; use crate::service::im::util::{TYPING_PREFIX, TYPING_TTL_SECS}; use ::redis::Cmd; pub fn set_typing( redis: &AppRedis, channel_id: Uuid, thread_id: Option, user_id: Uuid, ) -> AppResult<()> { let key = typing_key(channel_id, thread_id, user_id); let mut conn = redis.get_connection()?; Cmd::new() .arg("SETEX") .arg(&key) .arg(TYPING_TTL_SECS as u64) .arg("1") .query::<()>(&mut *conn.inner_mut())?; Ok(()) } pub fn clear_typing( redis: &AppRedis, channel_id: Uuid, thread_id: Option, user_id: Uuid, ) -> AppResult<()> { let key = typing_key(channel_id, thread_id, user_id); let mut conn = redis.get_connection()?; Cmd::new() .arg("DEL") .arg(&key) .query::<()>(&mut *conn.inner_mut())?; Ok(()) } pub fn get_typing_users( redis: &AppRedis, channel_id: Uuid, thread_id: Option, ) -> AppResult> { let pattern = match thread_id { Some(tid) => format!("{TYPING_PREFIX}{channel_id}:{tid}:*"), None => format!("{TYPING_PREFIX}{channel_id}:*"), }; let mut conn = redis.get_connection()?; let keys: Vec = Cmd::new() .arg("KEYS") .arg(&pattern) .query(&mut *conn.inner_mut()) .map_err(AppError::Redis)?; let mut ids = Vec::with_capacity(keys.len()); for key in &keys { if let Some(part) = key.rsplit(':').next() && let Ok(uid) = part.parse::() { ids.push(uid); } } Ok(ids) } fn typing_key(channel_id: Uuid, thread_id: Option, user_id: Uuid) -> String { match thread_id { Some(tid) => format!("{TYPING_PREFIX}{channel_id}:{tid}:{user_id}"), None => format!("{TYPING_PREFIX}{channel_id}:{user_id}"), } }