Centralize remaining magic numbers; finalize logging hygiene across UI/BLE/Nostr (#522)

* docs(plans): add refactor plan; chore(config): introduce TransportConfig and use in BLEService/ChatViewModel/PrivateChatManager; feat: add PeerDisplayNameResolver and apply in BLEService; chore: make TransportPeerSnapshot Equatable/Hashable; perf: simplify read-receipt persistence (no synchronize)

* project: add TransportConfig.swift and PeerDisplayNameResolver.swift to iOS/macOS targets (no xcodegen)

* chore: remove unnecessary UserDefaults.synchronize() calls (extension/app/VM)

* project: fix TransportConfig reference path; remove recovered reference; hook correct fileRef in iOS/macOS sources

* chore(BLE): move connect/duty/announce constants to TransportConfig and reference them

* chore(NostrTransport): factor recipient npub resolution into helper; reduce duplication

* chore(BLE): trim raw hex dump on central decode failure to length+prefix

* project: remove duplicate TransportConfig.swift entries from Sources build phases

* chore: centralize more constants in TransportConfig (BLE thresholds, Nostr read-ack, UI caps) and adopt in BLEService/ChatViewModel/NostrTransport

* chore: centralize location + geohash constants (filters, lookback, relay count) and adopt in LocationChannelManager/ChatViewModel

* chore: centralize compression, dedup, verification QR, relay backoff, georelay fetch constants; adopt across modules

* chore: centralize more BLE/Nostr delays; tighten NostrRelayManager logs to concise summaries; adopt config for location/geohash/relays

* refactor(config): centralize remaining magic numbers and finalize log hygiene

Add comprehensive TransportConfig constants for UI, Nostr, and BLE; adopt across ChatViewModel, ContentView, BLEService, ShareViewController, and BitchatApp to remove scattered literals. Standardize Nostr lookbacks/limits, UI delays/animations, and BLE announce/duty-cycle/candidate caps. Preserve behavior while making tuning explicit and safe.

Highlights:\n- UI: animations, scroll throttle, long-message thresholds, batch stagger, color hue tuning, rate-limit buckets, read-receipt debounce, startup delays, share accept/dismiss windows, migration cutoff.\n- Nostr: short display length (8), conv-key prefix length (16), DM lookback (24h), geohash sample lookback/limits; consistent use throughout ChatViewModel.\n- BLE: dynamic RSSI defaults, announce intervals/base+jitter, duty cycles (dense/sparse), fragment/ingress lifetimes, expected write timings/spacing, recent packet window (30s/100), peer inactivity timeout; unified candidate caps (100).\n- Share: use constant dismiss delay; App: use constant share accept window.\n\nRisk/impact: behavior-equivalent with centralized knobs; easier to tune without code edits.

* project: add TransportConfig.swift to Share Extension target to fix build

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
jack
2025-08-25 21:18:51 +02:00
committed by GitHub
co-authored by jack
parent 680a390b2d
commit a7d5b2d7d9
17 changed files with 442 additions and 265 deletions
+21 -38
View File
@@ -20,7 +20,7 @@ final class NostrTransport: Transport {
}
private var readQueue: [QueuedRead] = []
private var isSendingReadAcks = false
private let readAckInterval: TimeInterval = 0.35 // ~3 per second
private let readAckInterval: TimeInterval = TransportConfig.nostrReadAckInterval
var myPeerID: String { senderPeerID }
var myNickname: String { "" }
@@ -48,16 +48,7 @@ final class NostrTransport: Transport {
func sendPrivateMessage(_ content: String, to peerID: String, recipientNickname: String, messageID: String) {
Task { @MainActor in
// Resolve favorite by full noise key or by short peerID fallback
var recipientNostrPubkey: String?
if let noiseKey = Data(hexString: peerID),
let fav = FavoritesPersistenceService.shared.getFavoriteStatus(for: noiseKey) {
recipientNostrPubkey = fav.peerNostrPublicKey
}
if recipientNostrPubkey == nil, peerID.count == 16 {
recipientNostrPubkey = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: peerID)?.peerNostrPublicKey
}
guard let recipientNpub = recipientNostrPubkey else { return }
guard let recipientNpub = resolveRecipientNpub(for: peerID) else { return }
guard let senderIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() else { return }
SecureLogger.log("NostrTransport: preparing PM to \(recipientNpub.prefix(16))… for peerID \(peerID.prefix(8))… id=\(messageID.prefix(8))",
category: SecureLogger.session, level: .debug)
@@ -105,15 +96,7 @@ final class NostrTransport: Transport {
guard !readQueue.isEmpty else { isSendingReadAcks = false; return }
let item = readQueue.removeFirst()
Task { @MainActor in
var recipientNostrPubkey: String?
if let noiseKey = Data(hexString: item.peerID),
let fav = FavoritesPersistenceService.shared.getFavoriteStatus(for: noiseKey) {
recipientNostrPubkey = fav.peerNostrPublicKey
}
if recipientNostrPubkey == nil, item.peerID.count == 16 {
recipientNostrPubkey = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: item.peerID)?.peerNostrPublicKey
}
guard let recipientNpub = recipientNostrPubkey else { scheduleNextReadAck(); return }
guard let recipientNpub = resolveRecipientNpub(for: item.peerID) else { scheduleNextReadAck(); return }
guard let senderIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() else { scheduleNextReadAck(); return }
SecureLogger.log("NostrTransport: preparing READ ack for id=\(item.receipt.originalMessageID.prefix(8))… to \(recipientNpub.prefix(16))",
category: SecureLogger.session, level: .debug)
@@ -149,15 +132,7 @@ final class NostrTransport: Transport {
func sendFavoriteNotification(to peerID: String, isFavorite: Bool) {
Task { @MainActor in
var recipientNostrPubkey: String?
if let noiseKey = Data(hexString: peerID),
let fav = FavoritesPersistenceService.shared.getFavoriteStatus(for: noiseKey) {
recipientNostrPubkey = fav.peerNostrPublicKey
}
if recipientNostrPubkey == nil, peerID.count == 16 {
recipientNostrPubkey = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: peerID)?.peerNostrPublicKey
}
guard let recipientNpub = recipientNostrPubkey else { return }
guard let recipientNpub = resolveRecipientNpub(for: peerID) else { return }
guard let senderIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() else { return }
let content = isFavorite ? "[FAVORITED]:\(senderIdentity.npub)" : "[UNFAVORITED]:\(senderIdentity.npub)"
SecureLogger.log("NostrTransport: preparing FAVORITE(\(isFavorite)) to \(recipientNpub.prefix(16))",
@@ -183,18 +158,26 @@ final class NostrTransport: Transport {
}
}
// MARK: - Helpers
@MainActor
private func resolveRecipientNpub(for peerID: String) -> String? {
if let noiseKey = Data(hexString: peerID),
let fav = FavoritesPersistenceService.shared.getFavoriteStatus(for: noiseKey),
let npub = fav.peerNostrPublicKey {
return npub
}
if peerID.count == 16,
let fav = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: peerID),
let npub = fav.peerNostrPublicKey {
return npub
}
return nil
}
func sendBroadcastAnnounce() { /* no-op for Nostr */ }
func sendDeliveryAck(for messageID: String, to peerID: String) {
Task { @MainActor in
var recipientNostrPubkey: String?
if let noiseKey = Data(hexString: peerID),
let fav = FavoritesPersistenceService.shared.getFavoriteStatus(for: noiseKey) {
recipientNostrPubkey = fav.peerNostrPublicKey
}
if recipientNostrPubkey == nil, peerID.count == 16 {
recipientNostrPubkey = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: peerID)?.peerNostrPublicKey
}
guard let recipientNpub = recipientNostrPubkey else { return }
guard let recipientNpub = resolveRecipientNpub(for: peerID) else { return }
guard let senderIdentity = try? NostrIdentityBridge.getCurrentNostrIdentity() else { return }
SecureLogger.log("NostrTransport: preparing DELIVERED ack for id=\(messageID.prefix(8))… to \(recipientNpub.prefix(16))",
category: SecureLogger.session, level: .debug)