From fb5b1349364b9b9f1a88a6117eafcd990ca05ddf Mon Sep 17 00:00:00 2001 From: vekovius Date: Wed, 5 Aug 2026 16:21:40 -0500 Subject: [PATCH] Clean expired IDs before marked-entry trimming --- bitchat/Utils/MessageDeduplicator.swift | 4 +++- bitchatTests/MessageDeduplicatorTests.swift | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/bitchat/Utils/MessageDeduplicator.swift b/bitchat/Utils/MessageDeduplicator.swift index 27909ad4..d2fc489d 100644 --- a/bitchat/Utils/MessageDeduplicator.swift +++ b/bitchat/Utils/MessageDeduplicator.swift @@ -57,8 +57,10 @@ final class MessageDeduplicator { lock.lock() defer { lock.unlock() } + let now = Date() + cleanupOldEntries(before: now.addingTimeInterval(-maxAge)) + if lookup[id] == nil { - let now = Date() entries.append(Entry(id: id, timestamp: now)) lookup[id] = now trimIfNeeded() diff --git a/bitchatTests/MessageDeduplicatorTests.swift b/bitchatTests/MessageDeduplicatorTests.swift index 6016d7a9..6db1117d 100644 --- a/bitchatTests/MessageDeduplicatorTests.swift +++ b/bitchatTests/MessageDeduplicatorTests.swift @@ -25,4 +25,20 @@ struct MessageDeduplicatorTests { #expect(deduplicator.contains("d")) #expect(deduplicator.contains("e")) } + + @Test func markProcessed_cleansExpiredEntriesBeforeCountTrim() async { + let deduplicator = MessageDeduplicator(maxAge: 0.1, maxCount: 4) + + deduplicator.markProcessed("expired") + try? await Task.sleep(nanoseconds: 200_000_000) + + for id in ["b", "c", "d", "e"] { + deduplicator.markProcessed(id) + } + + #expect(deduplicator.contains("b")) + #expect(deduplicator.contains("c")) + #expect(deduplicator.contains("d")) + #expect(deduplicator.contains("e")) + } }