From b5aa5412e13491bf64987b2922f7e52e4fcb2290 Mon Sep 17 00:00:00 2001 From: spqrz Date: Sat, 11 Apr 2026 22:38:57 +0100 Subject: [PATCH] IRC: split on word if possible, + flush --- channels/irc/src/main.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/channels/irc/src/main.rs b/channels/irc/src/main.rs index ee94e89..27aae5d 100644 --- a/channels/irc/src/main.rs +++ b/channels/irc/src/main.rs @@ -139,7 +139,12 @@ impl AsyncWriter for TlsWriter { line: &str, ) -> std::pin::Pin> + '_>> { let data = format!("{line}\r\n"); - Box::pin(async move { self.inner.write_all(data.as_bytes()).await }) + Box::pin(async move { + self.inner.write_all(data.as_bytes()).await?; + // Unconfirmed reports that some servers require + // multiple lines to be in separate packets + self.inner.flush().await + }) } } @@ -153,7 +158,12 @@ impl AsyncWriter for PlainWriter { line: &str, ) -> std::pin::Pin> + '_>> { let data = format!("{line}\r\n"); - Box::pin(async move { self.inner.write_all(data.as_bytes()).await }) + Box::pin(async move { + self.inner.write_all(data.as_bytes()).await?; + // Unconfirmed reports that some servers require + // multiple lines to be in separate packets + self.inner.flush().await + }) } } @@ -225,6 +235,8 @@ impl State { } async fn send_privmsg(&mut self, target: &str, msg: &str) -> io::Result<()> { + // Send PRIVMSG, which is used for both private and channel messages. + // Splits into multiple fragments if necessary. // IRC max line = 512 bytes including CRLF. The server prepends // our prefix when relaying: ":nick!~user@host PRIVMSG target :msg\r\n" // User is often ~nick (nick_len + 1). Host is up to 63 bytes. @@ -246,7 +258,11 @@ impl State { // Find last char boundary at or before max_msg let mut i = max_msg; while i > 0 && !remaining.is_char_boundary(i) { i -= 1; } - if i == 0 { max_msg } else { i } + // To avoid splitting mid-word, see if there was a space recently + let mut j = i; + while j > 0 && j > i-10 && remaining.as_bytes()[j] != b' ' { j -= 1; } + if remaining.as_bytes()[j] == b' ' { j } + else if i == 0 { max_msg } else { i } }; let (chunk, rest) = remaining.split_at(split_at); self.send_raw(&format!("PRIVMSG {target} :{chunk}")).await?;