Perf/optimizations (#563)

* Perf: reduce hot‑path overhead (logger autoclosure, zero‑copy BinaryProtocol.decode, prealloc encoders)

* Compression: revert to zlib per request (compatibility)

* Nostr: parse inbound messages off-main, then update state on main; BLE: debounce peer snapshot publishing to reduce churn

* Fix: Swift 6 concurrency - avoid capturing self in detached tasks; deliver parsed Nostr messages via MainActor singleton

* Fix: move ParsedInbound + parseInboundMessage to file scope (non-isolated) to satisfy Swift 6; update detached tasks to call free function

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
jack
2025-09-06 12:47:32 +02:00
committed by GitHub
co-authored by jack
parent 5273f13512
commit 0ce68bc762
7 changed files with 297 additions and 262 deletions
+21 -7
View File
@@ -9,6 +9,7 @@ final class MessageDeduplicator {
}
private var entries: [Entry] = []
private var head: Int = 0
private var lookup = Set<String>()
private let lock = NSLock()
private let maxAge: TimeInterval = TransportConfig.messageDedupMaxAgeSeconds // 5 minutes
@@ -28,10 +29,18 @@ final class MessageDeduplicator {
entries.append(Entry(messageID: messageID, timestamp: Date()))
lookup.insert(messageID)
if entries.count > maxCount {
let toRemove = entries.prefix(100)
toRemove.forEach { lookup.remove($0.messageID) }
entries.removeFirst(100)
// Soft-cap and advance head by a chunk to avoid O(n) shifting
if (entries.count - head) > maxCount {
let removeCount = min(100, entries.count - head)
for i in head..<(head + removeCount) {
lookup.remove(entries[i].messageID)
}
head += removeCount
// Periodically compact to reclaim memory
if head > entries.count / 2 {
entries.removeFirst(head)
head = 0
}
}
return false
@@ -61,6 +70,7 @@ final class MessageDeduplicator {
defer { lock.unlock() }
entries.removeAll()
head = 0
lookup.removeAll()
}
@@ -78,9 +88,13 @@ final class MessageDeduplicator {
private func cleanupOldEntries() {
let cutoff = Date().addingTimeInterval(-maxAge)
while let first = entries.first, first.timestamp < cutoff {
lookup.remove(first.messageID)
entries.removeFirst()
while head < entries.count, entries[head].timestamp < cutoff {
lookup.remove(entries[head].messageID)
head += 1
}
if head > 0 && head > entries.count / 2 {
entries.removeFirst(head)
head = 0
}
}
}
+4 -4
View File
@@ -140,11 +140,11 @@ class SecureLogger {
}
/// Log general messages with automatic sensitive data filtering
static func log(_ message: String, category: OSLog = noise, level: LogLevel = .debug,
static func log(_ message: @autoclosure () -> String, category: OSLog = noise, level: LogLevel = .debug,
file: String = #file, line: Int = #line, function: String = #function) {
guard shouldLog(level) else { return }
let location = formatLocation(file: file, line: line, function: function)
let sanitized = sanitize("\(location) \(message)")
let sanitized = sanitize("\(location) \(message())")
#if DEBUG
os_log("%{public}@", log: category, type: level.osLogType, sanitized)
@@ -157,10 +157,10 @@ class SecureLogger {
}
/// Log errors with context
static func logError(_ error: Error, context: String, category: OSLog = noise,
static func logError(_ error: Error, context: @autoclosure () -> String, category: OSLog = noise,
file: String = #file, line: Int = #line, function: String = #function) {
let location = formatLocation(file: file, line: line, function: function)
let sanitized = sanitize(context)
let sanitized = sanitize(context())
let errorDesc = sanitize(error.localizedDescription)
#if DEBUG