perf: S2S channel-message fanout shares the line by Arc across members (relay_channel_message) instead of cloning a String per recipient — mirrors the client PRIVMSG fanout; builds at most three variants (plain / server-time / echo-services-tagged) whatever the channel size, behaviour unchanged

This commit is contained in:
Jean Chevronnet 2026-08-19 00:47:32 +00:00
parent 910422199b
commit a80b86b50d
2 changed files with 42 additions and 13 deletions

View file

@ -1453,20 +1453,11 @@ impl Server {
if !self.channels.contains_key(&key) { if !self.channels.contains_key(&key) {
return; 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}"); let base = format!(":{prefix} {cmd} {target} :{text}");
// echo/services: tag messages from a network service so capable self.relay_channel_message(&key, &base, src_is_service);
// 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<Uid> = 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() });
}
// forward to the other links that have members in this channel // forward to the other links that have members in this channel
for l in self.channel_link_targets(&key, Some(via)) { for l in self.channel_link_targets(&key, Some(via)) {
self.link_out(l, format!(":{src} {cmd} {target} :{text}")); self.link_out(l, format!(":{src} {cmd} {target} :{text}"));

View file

@ -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<str> = std::sync::Arc::from(base);
let tagged: Option<std::sync::Arc<str>> =
service.then(|| std::sync::Arc::from(format!("@echo/services {base}").as_str()));
let mut plain_time: Option<std::sync::Arc<str>> = 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 /// Send a message body (`:prefix CMD …`) from `src` to `uid`, composing its
/// IRCv3 tag prefix from *that recipient's* caps: `time=` (server-time), /// IRCv3 tag prefix from *that recipient's* caps: `time=` (server-time),
/// `account=` (account-tag, from the sender's login) plus the client-only tags /// `account=` (account-tag, from the sender's login) plus the client-only tags