From 755e835baf658c458ab9405274159801968b2859 Mon Sep 17 00:00:00 2001 From: reverse Date: Mon, 17 Aug 2026 22:49:29 +0000 Subject: [PATCH] =?UTF-8?q?snoop:=20only=20announce=20a=20client's=20exit?= =?UTF-8?q?=20if=20it=20registered=20=E2=80=94=20an=20unregistered=20liven?= =?UTF-8?q?ess/health=20probe=20was=20spamming=20the=20+q=20snomask=20(reg?= =?UTF-8?q?ression=20from=20firing=20on=5Fuser=5Fquit=20for=20all=20users)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/snoop.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/modules/snoop.rs b/src/modules/snoop.rs index c0ff345..01e60dd 100644 --- a/src/modules/snoop.rs +++ b/src/modules/snoop.rs @@ -27,10 +27,20 @@ impl Module for Snoop { } } fn on_user_quit(&mut self, srv: &mut Server, uid: Uid, reason: &str) { - let nick = srv.users.get(&uid).map(|u| u.nick.clone()); + // Only announce clients that actually registered. A health/liveness probe — or + // any client that drops mid-handshake — never fired a connect notice, so it must + // not fire an exit notice either, else it spams the +q snomask on every probe. + // (on_user_quit itself still fires for unregistered users so modules reclaim + // their per-uid state; only this operator-facing notice is gated.) + let Some(nick) = srv + .users + .get(&uid) + .filter(|u| u.registered) + .map(|u| u.nick.clone()) + else { + return; + }; eprintln!("[snoop] quit uid={uid} ({reason})"); - if let Some(nick) = nick { - srv.snotice_c('q', &format!("Client exiting: {nick} ({reason})")); - } + srv.snotice_c('q', &format!("Client exiting: {nick} ({reason})")); } }