dynamic direct connection detection

This commit is contained in:
callebtc
2026-01-10 00:41:10 +07:00
parent ea6b212c53
commit c848de9d42
2 changed files with 38 additions and 23 deletions
@@ -111,6 +111,13 @@ class BluetoothMeshService(private val context: Context) {
return signPacketBeforeBroadcast(packet)
}
}
// Inject dynamic direct connection check into PeerManager
// Matches iOS logic: checks if we have an active hardware mapping for this peer
peerManager.isPeerDirectlyConnected = { peerID ->
connectionManager.addressPeerMap.containsValue(peerID)
}
Log.d(TAG, "Delegates set up; GossipSyncManager initialized")
}
@@ -478,8 +485,8 @@ class BluetoothMeshService(private val context: Context) {
connectionManager.addressPeerMap[deviceAddress] = pid
Log.d(TAG, "Mapped device $deviceAddress to peer $pid (TTL=${routed.packet.ttl})")
// Mark as directly connected
try { peerManager.setDirectConnection(pid, true) } catch (_: Exception) { }
// Mark as directly connected - refresh UI state
try { peerManager.refreshPeerList() } catch (_: Exception) { }
// Initial sync for this direct peer
try { gossipSyncManager.scheduleInitialSyncToPeer(pid, 1_000) } catch (_: Exception) { }
@@ -584,8 +591,8 @@ class BluetoothMeshService(private val context: Context) {
if (peer != null) {
val stillMapped = connectionManager.addressPeerMap.values.any { it == peer }
if (!stillMapped) {
// Peer might still be reachable indirectly; mark as not-direct
try { peerManager.setDirectConnection(peer, false) } catch (_: Exception) { }
// Peer might still be reachable indirectly; refresh to update state
try { peerManager.refreshPeerList() } catch (_: Exception) { }
}
// Verbose debug: device disconnected
try {
@@ -86,6 +86,9 @@ class PeerManager {
// Delegate for callbacks
var delegate: PeerManagerDelegate? = null
// Callback to check if a peer is directly connected (injected by BluetoothMeshService)
var isPeerDirectlyConnected: ((String) -> Boolean)? = null
// Coroutines
private val managerScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
@@ -145,10 +148,18 @@ class PeerManager {
}
/**
* Get peer info
* Get peer info with dynamic direct connection status
*/
fun getPeerInfo(peerID: String): PeerInfo? {
return peers[peerID]
return peers[peerID]?.let { info ->
// Dynamically check direct connection status from ConnectionManager
val isDirect = isPeerDirectlyConnected?.invoke(peerID) ?: false
if (info.isDirectConnection != isDirect) {
info.copy(isDirectConnection = isDirect)
} else {
info
}
}
}
/**
@@ -159,28 +170,21 @@ class PeerManager {
}
/**
* Get all verified peers
* Get all verified peers with dynamic direct connection status
*/
fun getVerifiedPeers(): Map<String, PeerInfo> {
return peers.filterValues { it.isVerifiedNickname }
return peers.filterValues { it.isVerifiedNickname }.mapValues { (_, info) ->
val isDirect = isPeerDirectlyConnected?.invoke(info.id) ?: false
if (info.isDirectConnection != isDirect) info.copy(isDirectConnection = isDirect) else info
}
}
/**
* Set whether a peer is directly connected over Bluetooth.
* Triggers a peer list update to refresh UI badges.
* Force a peer list update notification.
* Call this when connection state changes to refresh UI badges.
*/
fun setDirectConnection(peerID: String, isDirect: Boolean) {
peers[peerID]?.let { existing ->
if (existing.isDirectConnection != isDirect) {
peers[peerID] = existing.copy(isDirectConnection = isDirect)
notifyPeerListUpdate()
// NEW: notify UI state (if available via delegate path) about directness change
try {
// Best-effort: delegate path flows up to ChatViewModel via didUpdatePeerList
// No direct reference to UI layer here by design.
} catch (_: Exception) { }
}
}
fun refreshPeerList() {
notifyPeerListUpdate()
}
// MARK: - Legacy Methods (maintained for compatibility)
@@ -364,7 +368,11 @@ class PeerManager {
return buildString {
appendLine("=== Peer Manager Debug Info ===")
appendLine("Active Peers: ${activeIds.size}")
peers.forEach { (peerID, info) ->
peers.forEach { (peerID, storedInfo) ->
// Use dynamic direct status for debug log accuracy
val isDirect = isPeerDirectlyConnected?.invoke(peerID) ?: false
val info = if (storedInfo.isDirectConnection != isDirect) storedInfo.copy(isDirectConnection = isDirect) else storedInfo
val timeSince = (now - info.lastSeen) / 1000
val rssi = peerRSSI[peerID]?.let { "${it} dBm" } ?: "No RSSI"
val deviceAddress = addressPeerMap?.entries?.find { it.value == peerID }?.key