mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-10-25 07:41:41 +00:00
Merge 97f94e7593e241207c0c318295c7df3aa893f439 into 9b84b361225facd8e623f25d76f889d3dc54a879
This commit is contained in:
commit
c78ca0e3fe
@ -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 {
|
||||
|
||||
54
bitchatTests/MessageDeduplicatorTests.swift
Normal file
54
bitchatTests/MessageDeduplicatorTests.swift
Normal 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"))
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user