Merge 97f94e7593e241207c0c318295c7df3aa893f439 into 9b84b361225facd8e623f25d76f889d3dc54a879

This commit is contained in:
Sam 2026-08-14 18:16:39 +00:00 committed by GitHub
commit c78ca0e3fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 67 additions and 4 deletions

View File

@ -16,6 +16,7 @@ final class MessageDeduplicator {
private let lock = NSLock()
private let maxAge: TimeInterval
private let maxCount: Int
private let dateProvider: () -> Date
/// Initialize with default config from TransportConfig
convenience init() {
@ -26,9 +27,14 @@ final class MessageDeduplicator {
}
/// Initialize with custom config for content deduplication
init(maxAge: TimeInterval, maxCount: Int) {
init(
maxAge: TimeInterval,
maxCount: Int,
dateProvider: @escaping () -> Date = Date.init
) {
self.maxAge = maxAge
self.maxCount = maxCount
self.dateProvider = dateProvider
}
/// Check if message is duplicate and add if not.
@ -38,7 +44,7 @@ final class MessageDeduplicator {
lock.lock()
defer { lock.unlock() }
let now = Date()
let now = dateProvider()
cleanupOldEntries(before: now.addingTimeInterval(-maxAge))
if lookup[id] != nil {
@ -57,10 +63,13 @@ final class MessageDeduplicator {
lock.lock()
defer { lock.unlock() }
let now = dateProvider()
cleanupOldEntries(before: now.addingTimeInterval(-maxAge))
if lookup[id] == nil {
let now = Date()
entries.append(Entry(id: id, timestamp: now))
lookup[id] = now
trimIfNeeded()
}
}
@ -106,7 +115,7 @@ final class MessageDeduplicator {
lock.lock()
defer { lock.unlock() }
cleanupOldEntries(before: Date().addingTimeInterval(-maxAge))
cleanupOldEntries(before: dateProvider().addingTimeInterval(-maxAge))
// Shrink capacity if significantly oversized
if entries.capacity > maxCount * 2 && entries.count < maxCount {

View File

@ -0,0 +1,54 @@
//
// MessageDeduplicatorTests.swift
// bitchatTests
//
// Tests for MessageDeduplicator.
// This is free and unencumbered software released into the public domain.
//
import Foundation
import Testing
@testable import bitchat
@Suite("Message Deduplicator")
struct MessageDeduplicatorTests {
@Test func markProcessed_enforcesMaximumCount() {
let now = Date(timeIntervalSince1970: 1_000)
let deduplicator = MessageDeduplicator(
maxAge: 300,
maxCount: 4,
dateProvider: { now }
)
for id in ["a", "b", "c", "d", "e"] {
deduplicator.markProcessed(id)
}
#expect(!deduplicator.contains("a"))
#expect(!deduplicator.contains("b"))
#expect(deduplicator.contains("c"))
#expect(deduplicator.contains("d"))
#expect(deduplicator.contains("e"))
}
@Test func markProcessed_cleansExpiredEntriesBeforeCountTrim() {
var now = Date(timeIntervalSince1970: 1_000)
let deduplicator = MessageDeduplicator(
maxAge: 300,
maxCount: 4,
dateProvider: { now }
)
deduplicator.markProcessed("expired")
now.addTimeInterval(301)
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"))
}
}