Share GossipSyncManager across transports to prevent redundant message synchronization

- Registered BluetoothMeshService's GossipSyncManager as a singleton in MeshServiceHolder.
- Modified WifiAwareMeshService to use the shared GossipSyncManager if available.
- Added background cleanup for peer mappings on socket disconnection.
- Fixed Kotlin type mismatch during nickname map merging.
This commit is contained in:
aidenvalue
2026-01-03 15:03:30 +01:00
parent ae87530afb
commit ddba841280
4 changed files with 44 additions and 23 deletions
@@ -94,6 +94,9 @@ class BluetoothMeshService(private val context: Context) {
} catch (_: Exception) { 0.01 }
}
)
// Register as shared instance for Wi-Fi Aware transport
com.bitchat.android.service.MeshServiceHolder.setGossipManager(gossipSyncManager)
// Wire sync manager delegate
gossipSyncManager.delegate = object : GossipSyncManager.Delegate {
@@ -9,6 +9,12 @@ import com.bitchat.android.mesh.BluetoothMeshService
*/
object MeshServiceHolder {
private const val TAG = "MeshServiceHolder"
@Volatile
var sharedGossipSyncManager: com.bitchat.android.sync.GossipSyncManager? = null
private set
fun setGossipManager(mgr: com.bitchat.android.sync.GossipSyncManager) { sharedGossipSyncManager = mgr }
@Volatile
var meshService: BluetoothMeshService? = null
private set
@@ -654,8 +654,8 @@ class ChatViewModel(
// Merge nicknames from BLE and WiFi Aware to display names for all peers
val bleNick = meshService.getPeerNicknames()
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 awareNickRaw = try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.getPeerNicknamesMap() } catch (_: Exception) { null }
val mergedNick = if (awareNickRaw != null) bleNick + awareNickRaw.filter { it.value != null }.mapValues { it.value!! }.filterKeys { it !in bleNick || bleNick[it].isNullOrBlank() } else bleNick
state.setPeerNicknames(mergedNick)
val rssiValues = meshService.getPeerRSSI()
@@ -106,24 +106,30 @@ class WifiAwareMeshService(private val context: Context) {
setupDelegates()
messageHandler.packetProcessor = packetProcessor
gossipSyncManager = GossipSyncManager(
myPeerID = myPeerID,
scope = serviceScope,
configProvider = object : GossipSyncManager.ConfigProvider {
override fun seenCapacity(): Int = 500
override fun gcsMaxBytes(): Int = 400
override fun gcsTargetFpr(): Double = 0.01
}
)
gossipSyncManager.delegate = object : GossipSyncManager.Delegate {
override fun sendPacketToPeer(peerID: String, packet: BitchatPacket) {
this@WifiAwareMeshService.sendPacketToPeer(peerID, packet)
}
override fun sendPacket(packet: BitchatPacket) {
broadcastPacket(RoutedPacket(packet))
}
override fun signPacketForBroadcast(packet: BitchatPacket): BitchatPacket {
return signPacketBeforeBroadcast(packet)
// Use shared GossipSyncManager from MeshServiceHolder if available (minimal refactor)
val shared = com.bitchat.android.service.MeshServiceHolder.sharedGossipSyncManager
if (shared != null) {
gossipSyncManager = shared
} else {
gossipSyncManager = GossipSyncManager(
myPeerID = myPeerID,
scope = serviceScope,
configProvider = object : GossipSyncManager.ConfigProvider {
override fun seenCapacity(): Int = 500
override fun gcsMaxBytes(): Int = 400
override fun gcsTargetFpr(): Double = 0.01
}
)
gossipSyncManager.delegate = object : GossipSyncManager.Delegate {
override fun sendPacketToPeer(peerID: String, packet: BitchatPacket) {
this@WifiAwareMeshService.sendPacketToPeer(peerID, packet)
}
override fun sendPacket(packet: BitchatPacket) {
broadcastPacket(RoutedPacket(packet))
}
override fun signPacketForBroadcast(packet: BitchatPacket): BitchatPacket {
return signPacketBeforeBroadcast(packet)
}
}
}
}
@@ -619,7 +625,7 @@ class WifiAwareMeshService(private val context: Context) {
}
override fun onLost(network: Network) {
networkCallbacks.remove(peerId)
Log.d(TAG, "SERVER: network lost for ${peerId.take(8)}")
Log.d(TAG, "SERVER: network lost for \${peerId.take(8)}…")
}
}
@@ -826,15 +832,21 @@ class WifiAwareMeshService(private val context: Context) {
}
if (routedPeerId == null) {
routedPeerId = senderPeerHex
peerSockets[routedPeerId] = socket
}
Log.d(TAG, "RX: packet type=${pkt.type} from ${senderPeerHex.take(8)}… (bytes=${raw.size})")
packetProcessor.processPacket(RoutedPacket(pkt, routedPeerId))
}
// Loop break -> disconnection
handlePeerDisconnection(initialLogicalPeerId, routedPeerId)
socket.closeQuietly()
}
/**
* Internal helper to ensure peer is cleaned up from all managers when a socket dies.
*/
private fun handlePeerDisconnection(initialId: String, routedId: String?) {
serviceScope.launch {
Log.w(TAG, "Cleaning up peer: $initialId / $routedId")