mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-24 23:45:18 +00:00
Peer icons: faster, accurate reachability\n\n- Run connectivity checks every maintenance tick (5s)\n- Publish peer snapshots on central unsubscribe for instant UI refresh\n- Lower inactivity timeout to 8s and disconnect debounce to 0.9s\n- Gate reachability on mesh-attached (>=1 direct link); no links => no reachable peers\n- Keep 21s retention for verified/unverified, but only when attached to mesh\n\nImproves list responsiveness when walking out of range and prevents stale 'reachable' states when isolated.
This commit is contained in:
@@ -528,8 +528,17 @@ final class BLEService: NSObject {
|
|||||||
}
|
}
|
||||||
return peerID
|
return peerID
|
||||||
}()
|
}()
|
||||||
// A peer is reachable if we have a recent entry for it (connected or recently seen via mesh)
|
return collectionsQueue.sync {
|
||||||
return collectionsQueue.sync { peers[shortID] != nil }
|
// Must be mesh-attached: at least one live direct link to the mesh
|
||||||
|
let meshAttached = peers.values.contains { $0.isConnected }
|
||||||
|
guard let info = peers[shortID] else { return false }
|
||||||
|
if info.isConnected { return true }
|
||||||
|
guard meshAttached else { return false }
|
||||||
|
// Apply reachability retention window
|
||||||
|
let isVerified = info.isVerifiedNickname
|
||||||
|
let retention: TimeInterval = isVerified ? TransportConfig.bleReachabilityRetentionVerifiedSeconds : TransportConfig.bleReachabilityRetentionUnverifiedSeconds
|
||||||
|
return Date().timeIntervalSince(info.lastSeen) <= retention
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func peerNickname(peerID: String) -> String? {
|
func peerNickname(peerID: String) -> String? {
|
||||||
@@ -1995,10 +2004,8 @@ final class BLEService: NSObject {
|
|||||||
updateScanningDutyCycle(connectedCount: connectedCount)
|
updateScanningDutyCycle(connectedCount: connectedCount)
|
||||||
updateRSSIThreshold(connectedCount: connectedCount)
|
updateRSSIThreshold(connectedCount: connectedCount)
|
||||||
|
|
||||||
// Every 20 seconds (2 cycles): Check peer connectivity
|
// Check peer connectivity every cycle for snappier UI updates
|
||||||
if maintenanceCounter % 2 == 0 {
|
checkPeerConnectivity()
|
||||||
checkPeerConnectivity()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Every 30 seconds (3 cycles): Cleanup
|
// Every 30 seconds (3 cycles): Cleanup
|
||||||
if maintenanceCounter % 3 == 0 {
|
if maintenanceCounter % 3 == 0 {
|
||||||
@@ -2847,6 +2854,8 @@ extension BLEService: CBPeripheralManagerDelegate {
|
|||||||
let currentPeerIDs = self.collectionsQueue.sync { Array(self.peers.keys) }
|
let currentPeerIDs = self.collectionsQueue.sync { Array(self.peers.keys) }
|
||||||
|
|
||||||
self.notifyPeerDisconnectedDebounced(peerID)
|
self.notifyPeerDisconnectedDebounced(peerID)
|
||||||
|
// Publish snapshots so UnifiedPeerService can refresh icons promptly
|
||||||
|
self.publishFullPeerData()
|
||||||
self.delegate?.didUpdatePeerList(currentPeerIDs)
|
self.delegate?.didUpdatePeerList(currentPeerIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,9 @@ enum TransportConfig {
|
|||||||
static let bleRSSIIsolatedRelaxed: Int = -92
|
static let bleRSSIIsolatedRelaxed: Int = -92
|
||||||
static let bleRSSIConnectedThreshold: Int = -85
|
static let bleRSSIConnectedThreshold: Int = -85
|
||||||
static let bleRSSIHighTimeoutThreshold: Int = -80
|
static let bleRSSIHighTimeoutThreshold: Int = -80
|
||||||
static let blePeerInactivityTimeoutSeconds: TimeInterval = 20.0
|
// How long without seeing traffic before we sanity-check the direct link
|
||||||
|
// Lowered to make connected→reachable icon changes react faster when walking out of range
|
||||||
|
static let blePeerInactivityTimeoutSeconds: TimeInterval = 8.0
|
||||||
// How long to retain a peer as "reachable" (not directly connected) since lastSeen
|
// How long to retain a peer as "reachable" (not directly connected) since lastSeen
|
||||||
static let bleReachabilityRetentionVerifiedSeconds: TimeInterval = 21.0 // 21s for verified/favorites
|
static let bleReachabilityRetentionVerifiedSeconds: TimeInterval = 21.0 // 21s for verified/favorites
|
||||||
static let bleReachabilityRetentionUnverifiedSeconds: TimeInterval = 21.0 // 21s for unknown/unverified
|
static let bleReachabilityRetentionUnverifiedSeconds: TimeInterval = 21.0 // 21s for unknown/unverified
|
||||||
@@ -144,7 +146,8 @@ enum TransportConfig {
|
|||||||
static let bleDirectedSpoolWindowSeconds: TimeInterval = 15.0
|
static let bleDirectedSpoolWindowSeconds: TimeInterval = 15.0
|
||||||
|
|
||||||
// Log/UI debounce windows
|
// Log/UI debounce windows
|
||||||
static let bleDisconnectNotifyDebounceSeconds: TimeInterval = 1.5
|
// Shorter debounce so UI reacts faster while still suppressing duplicate callbacks
|
||||||
|
static let bleDisconnectNotifyDebounceSeconds: TimeInterval = 0.9
|
||||||
static let bleReconnectLogDebounceSeconds: TimeInterval = 2.0
|
static let bleReconnectLogDebounceSeconds: TimeInterval = 2.0
|
||||||
|
|
||||||
// Weak-link cooldown after connection timeouts
|
// Weak-link cooldown after connection timeouts
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
|
|||||||
|
|
||||||
private func updatePeers() {
|
private func updatePeers() {
|
||||||
let meshPeers = meshService.currentPeerSnapshots()
|
let meshPeers = meshService.currentPeerSnapshots()
|
||||||
|
// If we have no direct links at all, peers should not be marked reachable
|
||||||
|
// "Reachable" means mesh-attached via at least one live link.
|
||||||
|
let hasAnyConnected = meshPeers.contains { $0.isConnected }
|
||||||
let favorites = favoritesService.favorites
|
let favorites = favoritesService.favorites
|
||||||
|
|
||||||
var enrichedPeers: [BitchatPeer] = []
|
var enrichedPeers: [BitchatPeer] = []
|
||||||
@@ -81,7 +84,8 @@ class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
|
|||||||
|
|
||||||
let peer = buildPeerFromMesh(
|
let peer = buildPeerFromMesh(
|
||||||
peerInfo: peerInfo,
|
peerInfo: peerInfo,
|
||||||
favorites: favorites
|
favorites: favorites,
|
||||||
|
meshAttached: hasAnyConnected
|
||||||
)
|
)
|
||||||
|
|
||||||
enrichedPeers.append(peer)
|
enrichedPeers.append(peer)
|
||||||
@@ -163,7 +167,8 @@ class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
|
|||||||
|
|
||||||
private func buildPeerFromMesh(
|
private func buildPeerFromMesh(
|
||||||
peerInfo: TransportPeerSnapshot,
|
peerInfo: TransportPeerSnapshot,
|
||||||
favorites: [Data: FavoritesPersistenceService.FavoriteRelationship]
|
favorites: [Data: FavoritesPersistenceService.FavoriteRelationship],
|
||||||
|
meshAttached: Bool
|
||||||
) -> BitchatPeer {
|
) -> BitchatPeer {
|
||||||
// Determine reachability based on lastSeen and identity trust
|
// Determine reachability based on lastSeen and identity trust
|
||||||
let now = Date()
|
let now = Date()
|
||||||
@@ -171,7 +176,9 @@ class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
|
|||||||
let isVerified = fingerprint.map { SecureIdentityStateManager.shared.isVerified(fingerprint: $0) } ?? false
|
let isVerified = fingerprint.map { SecureIdentityStateManager.shared.isVerified(fingerprint: $0) } ?? false
|
||||||
let isFav = peerInfo.noisePublicKey.flatMap { favorites[$0]?.isFavorite } ?? false
|
let isFav = peerInfo.noisePublicKey.flatMap { favorites[$0]?.isFavorite } ?? false
|
||||||
let retention: TimeInterval = (isVerified || isFav) ? TransportConfig.bleReachabilityRetentionVerifiedSeconds : TransportConfig.bleReachabilityRetentionUnverifiedSeconds
|
let retention: TimeInterval = (isVerified || isFav) ? TransportConfig.bleReachabilityRetentionVerifiedSeconds : TransportConfig.bleReachabilityRetentionUnverifiedSeconds
|
||||||
let isReachable = now.timeIntervalSince(peerInfo.lastSeen) <= retention
|
// A peer is reachable if we recently saw them AND we are attached to the mesh
|
||||||
|
let withinRetention = now.timeIntervalSince(peerInfo.lastSeen) <= retention
|
||||||
|
let isReachable = peerInfo.isConnected ? true : (withinRetention && meshAttached)
|
||||||
|
|
||||||
var peer = BitchatPeer(
|
var peer = BitchatPeer(
|
||||||
id: peerInfo.id,
|
id: peerInfo.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user