use crate::stats::enums::stats_event::StatsEvent;
use crate::tracker::enums::updates_action::UpdatesAction;
use crate::tracker::structs::info_hash::InfoHash;
use crate::tracker::structs::torrent_tracker::TorrentTracker;
use chrono::{
TimeZone,
Utc
};
use log::{
error,
info
};
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
use std::sync::Arc;
use std::time::{
SystemTime,
UNIX_EPOCH
};
impl TorrentTracker {
pub async fn load_keys(&self, tracker: Arc<TorrentTracker>)
{
if let Ok(keys) = self.sqlx.load_keys(tracker).await {
info!("Loaded {keys} keys");
}
}
pub async fn save_keys(&self, tracker: Arc<TorrentTracker>, keys: BTreeMap<InfoHash, (i64, UpdatesAction)>) -> Result<(), ()>
{
if let Ok(keys_count) = self.sqlx.save_keys(tracker, keys).await {
info!("[SYNC KEYS] Synced {keys_count} keys");
Ok(())
} else {
error!("[SYNC KEYS] Unable to sync keys");
Err(())
}
}
pub fn add_key(&self, hash: InfoHash, timeout: i64) -> bool
{
let mut lock = self.keys.write();
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
let timeout_unix = timestamp.as_secs() as i64 + timeout;
match lock.entry(hash) {
Entry::Vacant(v) => {
self.update_stats(StatsEvent::Key, 1);
v.insert(timeout_unix);
true
}
Entry::Occupied(mut o) => {
o.insert(timeout_unix);
false
}
}
}
pub fn get_key(&self, hash: InfoHash) -> Option<(InfoHash, i64)>
{
let lock = self.keys.read_recursive();
lock.get(&hash).map(|&data| (hash, data))
}
pub fn get_keys(&self) -> BTreeMap<InfoHash, i64>
{
let lock = self.keys.read_recursive();
lock.clone()
}
pub fn remove_key(&self, hash: InfoHash) -> bool
{
let mut lock = self.keys.write();
if lock.remove(&hash).is_some() {
self.update_stats(StatsEvent::Key, -1);
true
} else {
false
}
}
pub fn check_key(&self, hash: InfoHash) -> bool
{
let lock = self.keys.read_recursive();
lock.get(&hash).is_some_and(|&key| {
let key_time = Utc.timestamp_opt(key, 0)
.single()
.map_or(UNIX_EPOCH, SystemTime::from);
key_time > SystemTime::now()
})
}
pub fn clear_keys(&self)
{
let mut lock = self.keys.write();
lock.clear();
self.set_stats(StatsEvent::Key, 0);
}
pub fn clean_keys(&self)
{
let now = SystemTime::now();
let mut keys_to_remove = Vec::new();
{
let lock = self.keys.read_recursive();
for (&hash, &key_time) in lock.iter() {
let time = Utc.timestamp_opt(key_time, 0)
.single()
.map_or(UNIX_EPOCH, SystemTime::from);
if time <= now {
keys_to_remove.push(hash);
}
}
}
for hash in keys_to_remove {
self.remove_key(hash);
}
}
}