fix: bound IRC state, read recording metadata from the file tail, cap the audit log

- IRC: channel state is kept only for rooms the client itself joined, so
  JOIN/PART/KICK/NAMES for other rooms can't grow it; users per channel
  are capped at 10 000 and the view keeps at most 200 conversations,
  dropping the oldest idle query (SEC-20261012-014, F14).
- Recordings: the list reads the header line and the last 64 KiB for the
  duration instead of whole files of up to 250 MiB, falling back to a
  full scan only when the final event is longer than the window
  (SEC-20261012-020, F9).
- Audit log: keeps the newest 10 000 entries (F17).
This commit is contained in:
Andy Dixon
2026-10-12 09:12:25 +01:00
parent f09300fd95
commit 4d6595588b
4 changed files with 122 additions and 17 deletions
+12
View File
@@ -16,6 +16,9 @@ use std::sync::Arc;
const SERVER: &str = "server";
const MAX_LINES: usize = 2000;
/// Open conversations; past this the oldest idle query is dropped, so a flood of messages from
/// unique nicks can't grow the view without bound.
const MAX_TARGETS: usize = 200;
const SIDEBAR_W: f32 = 230.0;
struct Line {
@@ -172,6 +175,15 @@ impl IrcView {
let i = match self.targets.iter().position(|t| t.name == name) {
Some(i) => i,
None => {
if self.targets.len() >= MAX_TARGETS {
// ponytail: evicts the oldest-opened idle target, not least-recently-used.
let (active, joined) = (&self.active, &self.joined);
if let Some(i) = self.targets.iter().position(|t| t.name != SERVER && t.name != *active && !joined.iter().any(|r| r.name == t.name)) {
let gone = self.targets.remove(i);
self.unread.remove(&gone.name);
self.users.remove(&gone.name);
}
}
self.targets.push(Target { name: name.into(), lines: VecDeque::new() });
self.targets.len() - 1
}