Enhance Wi-Fi Aware robustness and debug UI display

- Clean up transport resources (sockets, server sockets, network callbacks) immediately on peer disconnection.
- Implement resolveScopedAddress to show scoped IPv6 (e.g., %aware0) in Debug UI.
- Fix Map type mismatch warning in ChatViewModel bridge.
- Filter self-ID from peer cleanup tables to prevent recursive self-removal.
This commit is contained in:
aidenvalue
2026-01-03 14:54:24 +01:00
parent a511945838
commit ae87530afb
2 changed files with 47 additions and 13 deletions
@@ -654,7 +654,7 @@ class ChatViewModel(
// Merge nicknames from BLE and WiFi Aware to display names for all peers // Merge nicknames from BLE and WiFi Aware to display names for all peers
val bleNick = meshService.getPeerNicknames() val bleNick = meshService.getPeerNicknames()
val awareNick = try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.getPeerNicknames() } catch (_: Exception) { null } val awareNick = try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.getPeerNicknamesMap() } catch (_: Exception) { null }
val mergedNick = if (awareNick != null) bleNick + awareNick.filterKeys { it !in bleNick || bleNick[it].isNullOrBlank() } else bleNick val mergedNick = if (awareNick != null) bleNick + awareNick.filterKeys { it !in bleNick || bleNick[it].isNullOrBlank() } else bleNick
state.setPeerNicknames(mergedNick) state.setPeerNicknames(mergedNick)
@@ -826,24 +826,30 @@ class WifiAwareMeshService(private val context: Context) {
} }
if (routedPeerId == null) { if (routedPeerId == null) {
routedPeerId = senderPeerHex
peerSockets[routedPeerId] = socket
}
Log.d(TAG, "RX: packet type=${pkt.type} from ${senderPeerHex.take(8)}… (bytes=${raw.size})") Log.d(TAG, "RX: packet type=${pkt.type} from ${senderPeerHex.take(8)}… (bytes=${raw.size})")
packetProcessor.processPacket(RoutedPacket(pkt, routedPeerId)) packetProcessor.processPacket(RoutedPacket(pkt, routedPeerId))
} }
// Loop break -> disconnection
handlePeerDisconnection(initialLogicalPeerId, routedPeerId)
socket.closeQuietly() socket.closeQuietly()
routedPeerId?.let { }
peerSockets.remove(it)
peerManager.removePeer(it) private fun handlePeerDisconnection(initialId: String, routedId: String?) {
serviceScope.launch {
Log.w(TAG, "Cleaning up peer: $initialId / $routedId")
val possible = setOfNotNull(initialId, routedId).filter { it.isNotEmpty() && it != myPeerID }
possible.forEach { id ->
peerSockets.remove(id)?.closeQuietly()
serverSockets.remove(id)?.closeQuietly()
networkCallbacks.remove(id)?.let { runCatching { cm.unregisterNetworkCallback(it) } }
peerManager.removePeer(id)
}
} }
} }
/** /**
* Sends a broadcast message to all peers. * Sends a broadcast message to all peers.
*
* @param content Text content of the message * @param content Text content of the message
* @param mentions Optional list of mentioned peer IDs * @param mentions Optional list of mentioned peer IDs
* @param channel Optional channel name * @param channel Optional channel name
@@ -1160,15 +1166,43 @@ class WifiAwareMeshService(private val context: Context) {
/** /**
* @return the current IPv4/IPv6 address of a connected peer, if any. * @return the current IPv4/IPv6 address of a connected peer, if any.
* Prefers the scoped IPv6 address format.
*/ */
fun getDeviceAddressForPeer(peerID: String): String? = fun getDeviceAddressForPeer(peerID: String): String? =
peerSockets[peerID]?.inetAddress?.hostAddress peerSockets[peerID]?.let { resolveScopedAddress(it) }
/**
* Helper to resolve a scoped IPv6 address from a socket for UI display.
*/
private fun resolveScopedAddress(sock: Socket): String? {
val addr = sock.inetAddress as? Inet6Address ?: return sock.inetAddress?.hostAddress
if (addr.scopeId != 0 || addr.isLoopbackAddress) return addr.hostAddress
// If address has no scope but we are on Aware (Link-Local fe80), attempt interface resolution
val iface = try {
val lp = cm.getLinkProperties(cm.activeNetwork)
lp?.interfaceName ?: "aware0"
} catch (_: Exception) { "aware0" }
return "${addr.hostAddress}%$iface"
}
/** /**
* @return a mapping of peerID → connected device IP address for all active sockets. * @return a mapping of peerID → connected device IP address for all active sockets.
* Results are formatted as scoped addresses if applicable.
*/ */
fun getDeviceAddressToPeerMapping(): Map<String, String> = fun getDeviceAddressToPeerMapping(): Map<String, String> {
peerSockets.mapValues { it.value.inetAddress.hostAddress } val map = mutableMapOf<String, String>()
peerSockets.forEach { (pid, sock) ->
map[pid] = resolveScopedAddress(sock) ?: "unknown"
}
return map
}
/**
* @return map of peer ID to nickname, bridged for UI warning fix.
*/
fun getPeerNicknamesMap(): Map<String, String?> = peerManager.getAllPeerNicknames()
/** Returns recently discovered peer IDs via Aware discovery (may not be connected). */ /** Returns recently discovered peer IDs via Aware discovery (may not be connected). */
fun getDiscoveredPeerIds(): Set<String> = fun getDiscoveredPeerIds(): Set<String> =