From: Ian Jackson Date: Sun, 23 Aug 2020 02:07:37 +0000 (+0100) Subject: expire old clients function X-Git-Tag: otter-0.2.0~1082 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=939970182fbf08311d001b24e4cbc6d216cba741;p=otter.git expire old clients function --- diff --git a/src/global.rs b/src/global.rs index 6f6dc1c9..54bf4f60 100644 --- a/src/global.rs +++ b/src/global.rs @@ -9,6 +9,8 @@ use std::sync::PoisonError; visible_slotmap_key!{ ClientId('C') } +const MAX_CLIENT_INACTIVITY : Duration = Duration::from_secs(200); + // ---------- public data structure ---------- #[derive(Debug,Serialize,Deserialize)] @@ -795,6 +797,69 @@ pub fn record_token ( token } +// ---------- client expiiry ---------- + +pub fn client_expire_old_clients() { + fn lock_even_poisoned(gref: &InstanceRef) -> MutexGuard { + match gref.0.lock() { + Ok(g) => g, + Err(poison) => poison.into_inner(), + } + } + + let mut expire = vec![]; + let max_age = Instant::now() - MAX_CLIENT_INACTIVITY; + + trait ClientIterator { + type Ret; + fn iter<'g>(&mut self, gref: &'g InstanceRef, max_age: Instant) + -> (MutexGuard<'g, InstanceContainer>, Option) { + let c = lock_even_poisoned(gref); + let ret = 'ret: loop { + for (client, cl) in &c.g.clients { + if cl.lastseen > max_age { continue } + let ret = self.old(client); + if ret.is_some() { break 'ret ret } + } + break 'ret None; + }; + (c,ret) + } + fn old(&mut self, client: ClientId) -> Option; + } + + for gref in GLOBAL.games.read().unwrap().values() { + struct Any; + impl ClientIterator for Any { + type Ret = (); + fn old(&mut self, _client: ClientId) -> Option<()> { + return Some(()) + } + } + if let (_, Some(())) = Any.iter(&gref, max_age) { + expire.push(gref.clone()); + } + } + for gref in expire.drain(..) { + struct Now(HashSet); + enum Impossible { } + impl ClientIterator for Now { + type Ret = Impossible; + fn old(&mut self, client: ClientId) + -> Option { + self.0.insert(client); + None + } + } + + let mut now = Now(Default::default()); + let (mut c, _) = now.iter(&gref, max_age); + c.g.clients.retain(|c,_| !now.0.contains(&c)); + let mut gref = InstanceGuard { c, gref: gref.clone() }; + gref.tokens_deregister_for_id::(|c| now.0.contains(&c)); + } +} + // ========== server config ========== const DEFAULT_SAVE_DIRECTORY : &str = "save";