2023-11-01 21:12:18 +01:00
|
|
|
use std::{
|
|
|
|
collections::{BinaryHeap, HashMap},
|
|
|
|
sync::Arc,
|
|
|
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
|
|
|
};
|
|
|
|
|
|
|
|
use tokio::sync::RwLock;
|
|
|
|
|
2023-11-06 18:38:00 +01:00
|
|
|
use crate::game::{Game, GameId};
|
2023-11-01 21:12:18 +01:00
|
|
|
|
|
|
|
pub fn start_gc(
|
|
|
|
game_expiry: Arc<RwLock<BinaryHeap<GarbageCollectorItem>>>,
|
2023-11-06 18:38:00 +01:00
|
|
|
games: Arc<RwLock<HashMap<GameId, Game>>>,
|
2023-11-01 21:12:18 +01:00
|
|
|
) {
|
|
|
|
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 {
|
2023-11-06 18:38:00 +01:00
|
|
|
id: GameId,
|
2023-11-01 21:12:18 +01:00
|
|
|
expires_at: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GarbageCollectorItem {
|
2023-11-06 18:38:00 +01:00
|
|
|
pub fn new_in(id: GameId, time: u64) -> Self {
|
2023-11-01 21:12:18 +01:00
|
|
|
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<std::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ord for GarbageCollectorItem {
|
|
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
|
|
self.expires_at.cmp(&other.expires_at).reverse()
|
|
|
|
}
|
|
|
|
}
|