mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 20:45:19 +00:00
Fix RSSI nil display issue (#316)
* Add comprehensive RSSI debugging logs - Log RSSI capture during discovery phase - Log RSSI reading after peripheral connection - Log didReadRSSI results including validation and retries - Log getPeerRSSI() calls and dictionary contents - Log RSSI transfer from temp IDs to real peer IDs - Add UI logging to trace nil RSSI values in ContentView - Track RSSI flow from Bluetooth discovery to UI display * Add detailed logging for RSSI transfer from temp ID to real peer ID - Log peripheral mapping updates during announce packet handling - Track connectedPeripherals state before and after mapping - Log RSSI transfer from peripheralRSSI to peerRSSI - Identify whether temp ID is found and properly transferred * Add peripheral lookup fallback for announce packets - Log whether peripheral is present when announce received - Add fallback to look up peripheral if not passed as parameter - This handles cases where announce is received via relay * Add comprehensive state logging to getPeerRSSI - Log connectedPeripherals mapping state - Log peripheralRSSI dictionary contents - Log UI-side RSSI lookup attempts with dictionary state - Track exactly what's in the RSSI lookup tables * Log peer list shown in UI * Ensure RSSI transfers even when no temp ID mapping exists * Add debugging for announce packets without peripheral reference * Fix build errors and add type annotations * Fix RSSI mapping for relayed announce packets - Add fallback logic to match unmapped peripherals with announced peers - Transfer RSSI from temp UUID to real peer ID when single unmapped peripheral exists - Implement periodic RSSI updates every 10 seconds for all connected peripherals - Improve RSSI debugging logs to track mapping state * Fix RSSI mapping condition for single unmapped peripheral - Remove peerNicknames.count == 0 condition that was preventing mapping - Map single unmapped peripheral to announcing peer regardless of nickname state - Remove temp RSSI entries when transferring to real peer ID - Improve logging to show successful RSSI transfers * Improve getPeerRSSI to skip temp IDs and check known peers - Skip temp IDs (non-16 character) when iterating connectedPeripherals - Add fallback to check peerNicknames for known peers without peripherals - Check both peerRSSI and peripheralRSSI for known peers - Improve RSSI lookup coverage for edge cases * Remove RSSI debug logging and fix build warnings - Remove all RSSI-related debug logging added during troubleshooting - Keep functional RSSI tracking code intact - Fix unused variable warnings in didReadRSSI and updateAllPeripheralRSSI - Clean up verbose logging while maintaining core functionality --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
@@ -91,6 +91,7 @@ class BluetoothMeshService: NSObject {
|
|||||||
private var activePeers: Set<String> = [] // Track all active peers
|
private var activePeers: Set<String> = [] // Track all active peers
|
||||||
private var peerRSSI: [String: NSNumber] = [:] // Track RSSI values for peers
|
private var peerRSSI: [String: NSNumber] = [:] // Track RSSI values for peers
|
||||||
private var peripheralRSSI: [String: NSNumber] = [:] // Track RSSI by peripheral ID during discovery
|
private var peripheralRSSI: [String: NSNumber] = [:] // Track RSSI by peripheral ID during discovery
|
||||||
|
private var rssiRetryCount: [String: Int] = [:] // Track RSSI retry attempts per peripheral
|
||||||
|
|
||||||
// Per-peer encryption queues to prevent nonce desynchronization
|
// Per-peer encryption queues to prevent nonce desynchronization
|
||||||
private var peerEncryptionQueues: [String: DispatchQueue] = [:]
|
private var peerEncryptionQueues: [String: DispatchQueue] = [:]
|
||||||
@@ -916,6 +917,11 @@ class BluetoothMeshService: NSObject {
|
|||||||
self?.checkPeerAvailability()
|
self?.checkPeerAvailability()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start RSSI update timer (every 10 seconds)
|
||||||
|
Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true) { [weak self] _ in
|
||||||
|
self?.updateAllPeripheralRSSI()
|
||||||
|
}
|
||||||
|
|
||||||
// Start write queue cleanup timer (every 30 seconds)
|
// Start write queue cleanup timer (every 30 seconds)
|
||||||
writeQueueTimer = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: true) { [weak self] _ in
|
writeQueueTimer = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: true) { [weak self] _ in
|
||||||
self?.cleanExpiredWriteQueues()
|
self?.cleanExpiredWriteQueues()
|
||||||
@@ -1548,9 +1554,53 @@ class BluetoothMeshService: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getPeerRSSI() -> [String: NSNumber] {
|
func getPeerRSSI() -> [String: NSNumber] {
|
||||||
// Return actual RSSI values only - no fake defaults
|
var rssiValues = peerRSSI
|
||||||
// UI should handle missing values gracefully
|
|
||||||
return peerRSSI
|
|
||||||
|
// Log connectedPeripherals state
|
||||||
|
SecureLogger.log("connectedPeripherals has \(connectedPeripherals.count) entries:", category: SecureLogger.session, level: .debug)
|
||||||
|
for (peerID, peripheral) in connectedPeripherals {
|
||||||
|
SecureLogger.log(" connectedPeripherals[\(peerID)] = \(peripheral.identifier.uuidString)", category: SecureLogger.session, level: .debug)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Also check peripheralRSSI for any connected peripherals
|
||||||
|
// This handles cases where RSSI is stored under temp IDs
|
||||||
|
for (peerID, peripheral) in connectedPeripherals {
|
||||||
|
// Skip temp IDs when iterating
|
||||||
|
if peerID.count != 16 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't have RSSI for this peer ID
|
||||||
|
if rssiValues[peerID] == nil {
|
||||||
|
|
||||||
|
// Check if we have RSSI stored by peripheral ID
|
||||||
|
let peripheralID = peripheral.identifier.uuidString
|
||||||
|
if let rssi = peripheralRSSI[peripheralID] {
|
||||||
|
rssiValues[peerID] = rssi
|
||||||
|
}
|
||||||
|
// Also check if RSSI is stored under the peer ID as a temp ID
|
||||||
|
else if let rssi = peripheralRSSI[peerID] {
|
||||||
|
rssiValues[peerID] = rssi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check for any known peers that might have RSSI in peerRSSI but not in connectedPeripherals
|
||||||
|
for (peerID, _) in peerNicknames {
|
||||||
|
if rssiValues[peerID] == nil && peerID.count == 16 {
|
||||||
|
// Check if we have RSSI stored directly
|
||||||
|
if let rssi = peerRSSI[peerID] {
|
||||||
|
rssiValues[peerID] = rssi
|
||||||
|
} else if let rssi = peripheralRSSI[peerID] {
|
||||||
|
rssiValues[peerID] = rssi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return rssiValues
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emergency disconnect for panic situations
|
// Emergency disconnect for panic situations
|
||||||
@@ -1582,6 +1632,7 @@ class BluetoothMeshService: NSObject {
|
|||||||
activePeers.removeAll()
|
activePeers.removeAll()
|
||||||
peerRSSI.removeAll()
|
peerRSSI.removeAll()
|
||||||
peripheralRSSI.removeAll()
|
peripheralRSSI.removeAll()
|
||||||
|
rssiRetryCount.removeAll()
|
||||||
announcedToPeers.removeAll()
|
announcedToPeers.removeAll()
|
||||||
announcedPeers.removeAll()
|
announcedPeers.removeAll()
|
||||||
// For emergency/panic, reset immediately
|
// For emergency/panic, reset immediately
|
||||||
@@ -2451,6 +2502,8 @@ class BluetoothMeshService: NSObject {
|
|||||||
if let nickname = String(data: packet.payload, encoding: .utf8) {
|
if let nickname = String(data: packet.payload, encoding: .utf8) {
|
||||||
let senderID = packet.senderID.hexEncodedString()
|
let senderID = packet.senderID.hexEncodedString()
|
||||||
|
|
||||||
|
SecureLogger.log("handleReceivedPacket: Received announce from \(senderID), peripheral is \(peripheral != nil ? "present" : "nil")", category: SecureLogger.session, level: .debug)
|
||||||
|
|
||||||
// Ignore if it's from ourselves (including previous peer IDs)
|
// Ignore if it's from ourselves (including previous peer IDs)
|
||||||
if isPeerIDOurs(senderID) {
|
if isPeerIDOurs(senderID) {
|
||||||
return
|
return
|
||||||
@@ -2523,17 +2576,75 @@ class BluetoothMeshService: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update peripheral mapping if we have it
|
// Update peripheral mapping if we have it
|
||||||
if let peripheral = peripheral {
|
// If peripheral is nil (e.g., from relay), try to find it
|
||||||
|
var peripheralToUpdate = peripheral
|
||||||
|
if peripheralToUpdate == nil {
|
||||||
|
// Look for any peripheral that might be this peer
|
||||||
|
// First check if we already have a mapping for this peer ID
|
||||||
|
peripheralToUpdate = self.connectedPeripherals[senderID]
|
||||||
|
|
||||||
|
if peripheralToUpdate == nil {
|
||||||
|
SecureLogger.log("handleReceivedPacket: No peripheral passed and no existing mapping for \(senderID)", category: SecureLogger.session, level: .debug)
|
||||||
|
|
||||||
|
// Try to find an unidentified peripheral that might be this peer
|
||||||
|
// This handles case where announce is relayed and we need to update RSSI mapping
|
||||||
|
var unmappedPeripherals: [(String, CBPeripheral)] = []
|
||||||
|
for (tempID, peripheral) in self.connectedPeripherals {
|
||||||
|
// Check if this is a temp ID (UUID format, not a peer ID)
|
||||||
|
if tempID.count == 36 && tempID.contains("-") { // UUID length with dashes
|
||||||
|
unmappedPeripherals.append((tempID, peripheral))
|
||||||
|
SecureLogger.log("handleReceivedPacket: Found unmapped peripheral with temp ID \(tempID)", category: SecureLogger.session, level: .debug)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have exactly one unmapped peripheral, it's likely this one
|
||||||
|
if unmappedPeripherals.count == 1 {
|
||||||
|
let (tempID, peripheral) = unmappedPeripherals[0]
|
||||||
|
SecureLogger.log("handleReceivedPacket: Single unmapped peripheral \(tempID), mapping to \(senderID)", category: SecureLogger.session, level: .info)
|
||||||
|
peripheralToUpdate = peripheral
|
||||||
|
|
||||||
|
// Remove temp mapping and add real mapping
|
||||||
|
self.connectedPeripherals.removeValue(forKey: tempID)
|
||||||
|
self.connectedPeripherals[senderID] = peripheral
|
||||||
|
|
||||||
|
// Transfer RSSI if available
|
||||||
|
if let rssi = self.peripheralRSSI[tempID] {
|
||||||
|
self.peripheralRSSI.removeValue(forKey: tempID)
|
||||||
|
self.peripheralRSSI[senderID] = rssi
|
||||||
|
self.peerRSSI[senderID] = rssi
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check the peripheral's UUID-based RSSI
|
||||||
|
let peripheralUUID = peripheral.identifier.uuidString
|
||||||
|
if peripheralUUID == tempID && peripheralRSSI[peripheralUUID] != nil {
|
||||||
|
// Already handled above
|
||||||
|
} else if let rssi = self.peripheralRSSI[peripheralUUID] {
|
||||||
|
self.peerRSSI[senderID] = rssi
|
||||||
|
}
|
||||||
|
} else if unmappedPeripherals.count > 1 {
|
||||||
|
SecureLogger.log("handleReceivedPacket: Multiple unmapped peripherals (\(unmappedPeripherals.count)), cannot determine which is \(senderID)", category: SecureLogger.session, level: .debug)
|
||||||
|
// TODO: Could use timing heuristics or other methods to match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let peripheral = peripheralToUpdate {
|
||||||
|
SecureLogger.log("handleReceivedPacket: Updating peripheral mapping for announce from \(senderID)", category: SecureLogger.session, level: .debug)
|
||||||
|
SecureLogger.log("handleReceivedPacket: Current connectedPeripherals: \(self.connectedPeripherals.keys.joined(separator: ", "))", category: SecureLogger.session, level: .debug)
|
||||||
|
|
||||||
// Find and remove any temp ID mapping for this peripheral
|
// Find and remove any temp ID mapping for this peripheral
|
||||||
var tempIDToRemove: String? = nil
|
var tempIDToRemove: String? = nil
|
||||||
for (id, per) in self.connectedPeripherals {
|
for (id, per) in self.connectedPeripherals {
|
||||||
if per == peripheral && id != senderID {
|
if per == peripheral && id != senderID {
|
||||||
|
SecureLogger.log("handleReceivedPacket: Found temp ID \(id) for peripheral that announced as \(senderID)", category: SecureLogger.session, level: .debug)
|
||||||
tempIDToRemove = id
|
tempIDToRemove = id
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let tempID = tempIDToRemove {
|
if let tempID = tempIDToRemove {
|
||||||
|
SecureLogger.log("handleReceivedPacket: Transferring from temp ID \(tempID) to real peer ID \(senderID)", category: SecureLogger.session, level: .debug)
|
||||||
|
|
||||||
// Remove temp mapping
|
// Remove temp mapping
|
||||||
self.connectedPeripherals.removeValue(forKey: tempID)
|
self.connectedPeripherals.removeValue(forKey: tempID)
|
||||||
// Add real peer ID mapping
|
// Add real peer ID mapping
|
||||||
@@ -2541,6 +2652,17 @@ class BluetoothMeshService: NSObject {
|
|||||||
// Update peripheral ID to peer ID mapping
|
// Update peripheral ID to peer ID mapping
|
||||||
self.peerIDByPeripheralID[peripheral.identifier.uuidString] = senderID
|
self.peerIDByPeripheralID[peripheral.identifier.uuidString] = senderID
|
||||||
|
|
||||||
|
// Transfer RSSI from temp ID to real peer ID
|
||||||
|
if let tempRSSI = self.peripheralRSSI[tempID] {
|
||||||
|
self.peerRSSI[senderID] = tempRSSI
|
||||||
|
self.peripheralRSSI.removeValue(forKey: tempID)
|
||||||
|
}
|
||||||
|
// Also check if RSSI is stored by peripheral UUID
|
||||||
|
let peripheralUUID = peripheral.identifier.uuidString
|
||||||
|
if let peripheralStoredRSSI = self.peripheralRSSI[peripheralUUID] {
|
||||||
|
self.peerRSSI[senderID] = peripheralStoredRSSI
|
||||||
|
}
|
||||||
|
|
||||||
// IMPORTANT: Remove old peer ID from activePeers to prevent duplicates
|
// IMPORTANT: Remove old peer ID from activePeers to prevent duplicates
|
||||||
collectionsQueue.sync(flags: .barrier) {
|
collectionsQueue.sync(flags: .barrier) {
|
||||||
if self.activePeers.contains(tempID) {
|
if self.activePeers.contains(tempID) {
|
||||||
@@ -2549,6 +2671,17 @@ class BluetoothMeshService: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't notify about disconnect - this is just cleanup of temporary ID
|
// Don't notify about disconnect - this is just cleanup of temporary ID
|
||||||
|
} else {
|
||||||
|
SecureLogger.log("handleReceivedPacket: No temp ID found for peripheral, directly mapping \(senderID)", category: SecureLogger.session, level: .debug)
|
||||||
|
// No temp ID found, just add the mapping
|
||||||
|
self.connectedPeripherals[senderID] = peripheral
|
||||||
|
self.peerIDByPeripheralID[peripheral.identifier.uuidString] = senderID
|
||||||
|
|
||||||
|
// Check if RSSI is stored under peripheral UUID and transfer it
|
||||||
|
let peripheralUUID = peripheral.identifier.uuidString
|
||||||
|
if let peripheralStoredRSSI = self.peripheralRSSI[peripheralUUID] {
|
||||||
|
self.peerRSSI[senderID] = peripheralStoredRSSI
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3387,9 +3520,11 @@ extension BluetoothMeshService: CBCentralManagerDelegate {
|
|||||||
if let name = peripheral.name, name.count == 16 {
|
if let name = peripheral.name, name.count == 16 {
|
||||||
// Assume 16-character hex names are peer IDs
|
// Assume 16-character hex names are peer IDs
|
||||||
let peerID = name
|
let peerID = name
|
||||||
|
SecureLogger.log("Discovery: Found peer ID \(peerID) from peripheral name", category: SecureLogger.session, level: .debug)
|
||||||
|
|
||||||
// Don't process our own advertisements (including previous peer IDs)
|
// Don't process our own advertisements (including previous peer IDs)
|
||||||
if isPeerIDOurs(peerID) {
|
if isPeerIDOurs(peerID) {
|
||||||
|
SecureLogger.log("Discovery: Ignoring our own peer ID \(peerID)", category: SecureLogger.session, level: .debug)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3485,6 +3620,7 @@ extension BluetoothMeshService: CBCentralManagerDelegate {
|
|||||||
|
|
||||||
// Store peripheral by its system ID temporarily until we get the real peer ID
|
// Store peripheral by its system ID temporarily until we get the real peer ID
|
||||||
connectedPeripherals[tempID] = peripheral
|
connectedPeripherals[tempID] = peripheral
|
||||||
|
SecureLogger.log("didConnect: Stored peripheral with temp ID \(tempID)", category: SecureLogger.session, level: .debug)
|
||||||
|
|
||||||
// Update connection state to connected (but not authenticated yet)
|
// Update connection state to connected (but not authenticated yet)
|
||||||
// We don't know the real peer ID yet, so we can't update the state
|
// We don't know the real peer ID yet, so we can't update the state
|
||||||
@@ -3505,6 +3641,9 @@ extension BluetoothMeshService: CBCentralManagerDelegate {
|
|||||||
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||||
let peripheralID = peripheral.identifier.uuidString
|
let peripheralID = peripheral.identifier.uuidString
|
||||||
|
|
||||||
|
// Clean up RSSI retry count
|
||||||
|
rssiRetryCount.removeValue(forKey: peripheralID)
|
||||||
|
|
||||||
// Check if this was an intentional disconnect
|
// Check if this was an intentional disconnect
|
||||||
if intentionalDisconnects.contains(peripheralID) {
|
if intentionalDisconnects.contains(peripheralID) {
|
||||||
intentionalDisconnects.remove(peripheralID)
|
intentionalDisconnects.remove(peripheralID)
|
||||||
@@ -3806,23 +3945,45 @@ extension BluetoothMeshService: CBPeripheralDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
|
func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
|
||||||
guard error == nil else { return }
|
let peripheralID = peripheral.identifier.uuidString
|
||||||
|
|
||||||
|
if error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Validate RSSI value - 127 means no RSSI available
|
// Validate RSSI value - 127 means no RSSI available
|
||||||
let rssiValue = RSSI.intValue
|
let rssiValue = RSSI.intValue
|
||||||
|
|
||||||
// Only store valid RSSI values
|
// Only store valid RSSI values
|
||||||
if rssiValue == 127 || rssiValue < -100 || rssiValue > 0 {
|
if rssiValue == 127 || rssiValue < -100 || rssiValue > 0 {
|
||||||
SecureLogger.log("Invalid RSSI value \(rssiValue) from peripheral, will retry", category: SecureLogger.session, level: .debug)
|
// Track retry count
|
||||||
|
let retryCount = rssiRetryCount[peripheralID] ?? 0
|
||||||
|
rssiRetryCount[peripheralID] = retryCount + 1
|
||||||
|
|
||||||
// Retry sooner if we got an invalid value
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak peripheral] in
|
// Retry up to 5 times with exponential backoff
|
||||||
guard let peripheral = peripheral, peripheral.state == .connected else { return }
|
if retryCount < 5 {
|
||||||
peripheral.readRSSI()
|
let delay = min(0.2 * pow(2.0, Double(retryCount)), 2.0) // 0.2s, 0.4s, 0.8s, 1.6s, 2.0s max
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self, weak peripheral] in
|
||||||
|
guard let peripheral = peripheral, peripheral.state == .connected else {
|
||||||
|
self?.rssiRetryCount.removeValue(forKey: peripheralID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
peripheral.readRSSI()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Give up after 5 retries, reset counter
|
||||||
|
rssiRetryCount.removeValue(forKey: peripheralID)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Valid RSSI received, reset retry count
|
||||||
|
rssiRetryCount.removeValue(forKey: peripheralID)
|
||||||
|
|
||||||
|
// Store RSSI by peripheral ID for fallback lookup
|
||||||
|
peripheralRSSI[peripheralID] = RSSI
|
||||||
|
|
||||||
// Find the peer ID for this peripheral
|
// Find the peer ID for this peripheral
|
||||||
if let peerID = connectedPeripherals.first(where: { $0.value == peripheral })?.key {
|
if let peerID = connectedPeripherals.first(where: { $0.value == peripheral })?.key {
|
||||||
// Handle both temp IDs and real peer IDs
|
// Handle both temp IDs and real peer IDs
|
||||||
@@ -3850,6 +4011,7 @@ extension BluetoothMeshService: CBPeripheralDelegate {
|
|||||||
guard let peripheral = peripheral, peripheral.state == .connected else { return }
|
guard let peripheral = peripheral, peripheral.state == .connected else { return }
|
||||||
peripheral.readRSSI()
|
peripheral.readRSSI()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5532,6 +5694,17 @@ extension BluetoothMeshService: CBPeripheralManagerDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update RSSI for all connected peripherals
|
||||||
|
private func updateAllPeripheralRSSI() {
|
||||||
|
|
||||||
|
// Read RSSI for all connected peripherals
|
||||||
|
for (_, peripheral) in connectedPeripherals {
|
||||||
|
if peripheral.state == .connected {
|
||||||
|
peripheral.readRSSI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check peer availability based on last heard time
|
// Check peer availability based on last heard time
|
||||||
private func checkPeerAvailability() {
|
private func checkPeerAvailability() {
|
||||||
let now = Date()
|
let now = Date()
|
||||||
|
|||||||
@@ -600,19 +600,27 @@ struct ContentView: View {
|
|||||||
|
|
||||||
// Show all connected peers
|
// Show all connected peers
|
||||||
let peersToShow: [String] = viewModel.connectedPeers
|
let peersToShow: [String] = viewModel.connectedPeers
|
||||||
|
let _ = print("ContentView: Showing \(peersToShow.count) peers: \(peersToShow.joined(separator: ", "))")
|
||||||
|
|
||||||
// Pre-compute peer data outside ForEach to reduce overhead
|
// Pre-compute peer data outside ForEach to reduce overhead
|
||||||
let peerData = peersToShow.map { peerID in
|
let peerData = peersToShow.map { peerID in
|
||||||
PeerDisplayData(
|
let rssiValue = peerRSSI[peerID]?.intValue
|
||||||
|
if rssiValue == nil {
|
||||||
|
print("ContentView: No RSSI for peer \(peerID) in dictionary with \(peerRSSI.count) entries")
|
||||||
|
print("ContentView: peerRSSI keys: \(peerRSSI.keys.joined(separator: ", "))")
|
||||||
|
} else {
|
||||||
|
print("ContentView: RSSI for peer \(peerID) is \(rssiValue!)")
|
||||||
|
}
|
||||||
|
return PeerDisplayData(
|
||||||
id: peerID,
|
id: peerID,
|
||||||
displayName: peerID == myPeerID ? viewModel.nickname : (peerNicknames[peerID] ?? "anon\(peerID.prefix(4))"),
|
displayName: peerID == myPeerID ? viewModel.nickname : (peerNicknames[peerID] ?? "anon\(peerID.prefix(4))"),
|
||||||
rssi: peerRSSI[peerID]?.intValue,
|
rssi: rssiValue,
|
||||||
isFavorite: viewModel.isFavorite(peerID: peerID),
|
isFavorite: viewModel.isFavorite(peerID: peerID),
|
||||||
isMe: peerID == myPeerID,
|
isMe: peerID == myPeerID,
|
||||||
hasUnreadMessages: viewModel.unreadPrivateMessages.contains(peerID),
|
hasUnreadMessages: viewModel.unreadPrivateMessages.contains(peerID),
|
||||||
encryptionStatus: viewModel.getEncryptionStatus(for: peerID)
|
encryptionStatus: viewModel.getEncryptionStatus(for: peerID)
|
||||||
)
|
)
|
||||||
}.sorted { peer1, peer2 in
|
}.sorted { (peer1: PeerDisplayData, peer2: PeerDisplayData) in
|
||||||
// Sort: favorites first, then alphabetically by nickname
|
// Sort: favorites first, then alphabetically by nickname
|
||||||
if peer1.isFavorite != peer2.isFavorite {
|
if peer1.isFavorite != peer2.isFavorite {
|
||||||
return peer1.isFavorite
|
return peer1.isFavorite
|
||||||
|
|||||||
Reference in New Issue
Block a user