use crate::cache::enums::cache_error::CacheError;
use crate::cache::structs::cache_connector_redis::CacheConnectorRedis;
use crate::cache::traits::cache_backend::CacheBackend;
use crate::tracker::structs::info_hash::InfoHash;
use async_trait::async_trait;
use log::debug;
use redis::AsyncCommands;
#[async_trait]
impl CacheBackend for CacheConnectorRedis {
async fn ping(&self) -> Result<(), CacheError> {
let mut conn = self.connection.clone();
redis::cmd("PING")
.query_async::<String>(&mut conn)
.await
.map_err(CacheError::RedisError)?;
Ok(())
}
async fn set_torrent_peers(
&self,
info_hash: &InfoHash,
seeds: u64,
peers: u64,
ttl: Option<u64>,
) -> Result<(), CacheError> {
let mut conn = self.connection.clone();
let key = self.torrent_key(info_hash);
conn.hset_multiple::<_, _, _, ()>(&key, &[("s", seeds), ("p", peers)])
.await
.map_err(CacheError::RedisError)?;
if let Some(ttl_secs) = ttl
&& ttl_secs > 0 {
conn.expire::<_, ()>(&key, ttl_secs as i64)
.await
.map_err(CacheError::RedisError)?;
}
debug!("[Redis] Set torrent {info_hash} seeds={seeds} peers={peers}");
Ok(())
}
async fn get_torrent_peers(
&self,
info_hash: &InfoHash,
) -> Result<Option<(u64, u64)>, CacheError> {
let mut conn = self.connection.clone();
let key = self.torrent_key(info_hash);
let (seeds, peers): (Option<u64>, Option<u64>) = redis::cmd("HMGET")
.arg(&key)
.arg("s")
.arg("p")
.query_async(&mut conn)
.await
.map_err(CacheError::RedisError)?;
match (seeds, peers) {
(Some(s), Some(p)) => Ok(Some((s, p))),
_ => Ok(None),
}
}
async fn delete_torrent(&self, info_hash: &InfoHash) -> Result<(), CacheError> {
let mut conn = self.connection.clone();
let key = self.torrent_key(info_hash);
conn.del::<_, ()>(&key)
.await
.map_err(CacheError::RedisError)?;
debug!("[Redis] Deleted torrent {info_hash}");
Ok(())
}
async fn set_torrent_peers_batch(
&self,
data: &[(InfoHash, u64, u64)],
ttl: Option<u64>,
) -> Result<(), CacheError> {
if data.is_empty() {
return Ok(());
}
let mut conn = self.connection.clone();
let mut pipe = redis::pipe();
for (info_hash, seeds, peers) in data {
let key = self.torrent_key(info_hash);
pipe.hset_multiple(&key, &[("s", *seeds), ("p", *peers)]);
if let Some(ttl_secs) = ttl
&& ttl_secs > 0 {
pipe.expire(&key, ttl_secs as i64);
}
}
pipe.query_async::<()>(&mut conn)
.await
.map_err(CacheError::RedisError)?;
debug!("[Redis] Batch set {} torrents", data.len());
Ok(())
}
}