From a80b86b50d50d75e2f1d9820526068eb2f7961a8 Mon Sep 17 00:00:00 2001 From: reverse Date: Wed, 19 Aug 2026 00:47:32 +0000 Subject: [PATCH] =?UTF-8?q?perf:=20S2S=20channel-message=20fanout=20shares?= =?UTF-8?q?=20the=20line=20by=20Arc=20across=20members=20(relay=5Fchannel?= =?UTF-8?q?=5Fmessage)=20instead=20of=20cloning=20a=20String=20per=20recip?= =?UTF-8?q?ient=20=E2=80=94=20mirrors=20the=20client=20PRIVMSG=20fanout;?= =?UTF-8?q?=20builds=20at=20most=20three=20variants=20(plain=20/=20server-?= =?UTF-8?q?time=20/=20echo-services-tagged)=20whatever=20the=20channel=20s?= =?UTF-8?q?ize,=20behaviour=20unchanged?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/link.rs | 17 ++++------------- src/server.rs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/link.rs b/src/link.rs index 1446698..1abdb9f 100644 --- a/src/link.rs +++ b/src/link.rs @@ -1453,20 +1453,11 @@ impl Server { if !self.channels.contains_key(&key) { return; } + // echo/services badges a service source for message-tags clients; the + // line is built once and shared by Arc across all members (not cloned + // per recipient). let base = format!(":{prefix} {cmd} {target} :{text}"); - // echo/services: tag messages from a network service so capable - // clients can badge them. Per-recipient (needs the message-tags cap). - let is_service = src_is_service; - let tagged = format!("@echo/services {base}"); - let members: Vec = self.channels[&key].members.keys().copied().collect(); - for m in members { - if self.users.get(&m).map(|u| u.flags.deaf).unwrap_or(false) { - continue; - } - let want_tag = is_service - && self.users.get(&m).map(|u| u.caps.message_tags).unwrap_or(false); - self.send(m, if want_tag { tagged.clone() } else { base.clone() }); - } + self.relay_channel_message(&key, &base, src_is_service); // forward to the other links that have members in this channel for l in self.channel_link_targets(&key, Some(via)) { self.link_out(l, format!(":{src} {cmd} {target} :{text}")); diff --git a/src/server.rs b/src/server.rs index e220738..1f82967 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1018,6 +1018,44 @@ impl Server { } } + /// Fan an already-composed S2S channel message (`:prefix PRIVMSG #c :text`) out + /// to local members, sharing the line by `Arc` instead of cloning a String per + /// recipient. When `service`, message-tags clients get the `echo/services` badge; + /// server-time and +D deaf filtering are applied per recipient. At most three + /// distinct lines are built (plain / time-tagged / service-tagged) whatever the + /// channel size. + pub fn relay_channel_message(&self, key: &str, base: &str, service: bool) { + let Some(ch) = self.channels.get(key) else { + return; + }; + let sourced = base.starts_with(':'); // only `:prefix …` lines carry server-time + let plain: std::sync::Arc = std::sync::Arc::from(base); + let tagged: Option> = + service.then(|| std::sync::Arc::from(format!("@echo/services {base}").as_str())); + let mut plain_time: Option> = None; + for &m in ch.members.keys() { + let Some(u) = self.users.get(&m) else { + continue; + }; + if u.flags.deaf { + continue; + } + // a service-badged line already carries a tag block, so — as before — it + // isn't additionally server-time tagged. + let buf = if service && u.caps.message_tags { + LineBuf::Shared(tagged.clone().unwrap()) + } else if sourced && u.caps.server_time { + let t = plain_time.get_or_insert_with(|| { + std::sync::Arc::from(format!("@time={} {base}", iso_time(now())).as_str()) + }); + LineBuf::Shared(t.clone()) + } else { + LineBuf::Shared(plain.clone()) + }; + self.emit_to(m, buf); + } + } + /// Send a message body (`:prefix CMD …`) from `src` to `uid`, composing its /// IRCv3 tag prefix from *that recipient's* caps: `time=` (server-time), /// `account=` (account-tag, from the sender's login) plus the client-only tags