use std::{ collections::{BinaryHeap, HashMap}, sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, }; use tokio::sync::RwLock; use crate::game::{Game, GameId}; pub fn start_gc( game_expiry: Arc>>, games: Arc>>, ) { let games = games.clone(); let game_expiry = game_expiry.clone(); tokio::spawn(async move { tokio::time::sleep(Duration::from_secs(3600)).await; if let Ok(now) = SystemTime::now() .duration_since(UNIX_EPOCH) .map(|y| y.as_secs()) { let mut game_expiry = game_expiry.write().await; while let Some(gc) = game_expiry.peek() { if gc.expires_at > now { break; } else if let Some(gc) = game_expiry.pop() { let mut games = games.write().await; games.remove(&gc.id); } } } }); } #[derive(PartialEq, Eq)] pub struct GarbageCollectorItem { id: GameId, expires_at: u64, } impl GarbageCollectorItem { pub fn new_in(id: GameId, time: u64) -> Self { Self { id, expires_at: SystemTime::now() .checked_add(Duration::from_secs(time)) .and_then(|x| x.duration_since(UNIX_EPOCH).map(|y| y.as_secs()).ok()) .unwrap_or_default(), } } } impl PartialOrd for GarbageCollectorItem { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for GarbageCollectorItem { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.expires_at.cmp(&other.expires_at).reverse() } }