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:
parent
910422199b
commit
a80b86b50d
2 changed files with 42 additions and 13 deletions
17
src/link.rs
17
src/link.rs
|
|
@ -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}"));
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue