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
+1 -1
View File
@@ -14,7 +14,7 @@ final class GeoRelayDirectory {
private let cacheFileName = "georelays_cache.csv"
private let lastFetchKey = "georelay.lastFetchAt"
private let remoteURL = URL(string: "https://raw.githubusercontent.com/permissionlesstech/georelays/refs/heads/main/nostr_relays.csv")!
private let fetchInterval: TimeInterval = 60 * 60 * 24 // 24h
private let fetchInterval: TimeInterval = TransportConfig.geoRelayFetchIntervalSeconds // 24h
private init() {
// Load cached or bundled data synchronously
+9 -9
View File
@@ -48,10 +48,10 @@ class NostrRelayManager: ObservableObject {
private let messageQueueLock = NSLock()
// Exponential backoff configuration
private let initialBackoffInterval: TimeInterval = 1.0 // Start with 1 second
private let maxBackoffInterval: TimeInterval = 300.0 // Max 5 minutes
private let backoffMultiplier: Double = 2.0 // Double each time
private let maxReconnectAttempts = 10 // Stop after 10 attempts
private let initialBackoffInterval: TimeInterval = TransportConfig.nostrRelayInitialBackoffSeconds
private let maxBackoffInterval: TimeInterval = TransportConfig.nostrRelayMaxBackoffSeconds
private let backoffMultiplier: Double = TransportConfig.nostrRelayBackoffMultiplier
private let maxReconnectAttempts = TransportConfig.nostrRelayMaxReconnectAttempts
// Reconnection timer
private var reconnectionTimer: Timer?
@@ -289,7 +289,7 @@ class NostrRelayManager: ObservableObject {
// Only log non-gift-wrap events to reduce noise
if event.kind != 1059 {
SecureLogger.log("📥 Received Nostr event (kind: \(event.kind)) from relay: \(relayUrl)",
SecureLogger.log("📥 Event kind=\(event.kind) id=\(event.id.prefix(16)) relay=\(relayUrl)",
category: SecureLogger.session, level: .debug)
}
@@ -321,11 +321,11 @@ class NostrRelayManager: ObservableObject {
let reason = array.count >= 4 ? (array[3] as? String ?? "no reason given") : "no reason given"
if success {
_ = Self.pendingGiftWrapIDs.remove(eventId)
SecureLogger.log("Event accepted id=\(eventId.prefix(16))... by relay: \(relayUrl)",
SecureLogger.log("Accepted id=\(eventId.prefix(16)) relay=\(relayUrl)",
category: SecureLogger.session, level: .debug)
} else {
let isGiftWrap = Self.pendingGiftWrapIDs.remove(eventId) != nil
SecureLogger.log("📮 Event \(eventId.prefix(16))... rejected by relay: \(reason)",
SecureLogger.log("📮 Rejected id=\(eventId.prefix(16))… reason=\(reason)",
category: SecureLogger.session, level: isGiftWrap ? .warning : .error)
}
}
@@ -353,7 +353,7 @@ class NostrRelayManager: ObservableObject {
let data = try encoder.encode(req)
let message = String(data: data, encoding: .utf8) ?? ""
SecureLogger.log("📤 Sending Nostr event (kind: \(event.kind)) to relay: \(relayUrl)",
SecureLogger.log("📤 Send kind=\(event.kind) id=\(event.id.prefix(16)) relay=\(relayUrl)",
category: SecureLogger.session, level: .debug)
connection.send(.string(message)) { [weak self] error in
@@ -568,7 +568,7 @@ struct NostrFilter: Encodable {
filter.kinds = [1059] // Gift wrap kind
filter.since = since?.timeIntervalSince1970.toInt()
filter.tagFilters = ["p": [pubkey]]
filter.limit = 100 // Add a reasonable limit
filter.limit = TransportConfig.nostrRelayDefaultFetchLimit // reasonable limit
return filter
}