fix review

This commit is contained in:
CC
2026-06-10 12:16:00 +02:00
parent c7edea5ebb
commit 4566d5d228
5 changed files with 107 additions and 32 deletions
@@ -101,20 +101,9 @@ class BluetoothMeshService(private val context: Context) : TransportBridgeServic
}
)
// Wire sync manager delegate
gossipSyncManager.delegate = object : GossipSyncManager.Delegate {
override fun sendPacket(packet: BitchatPacket) {
broadcastRoutedPacket(RoutedPacket(packet))
}
override fun sendPacketToPeer(peerID: String, packet: BitchatPacket) {
sendPacketToPeerAcrossTransports(peerID, packet)
}
override fun signPacketForBroadcast(packet: BitchatPacket): BitchatPacket {
return signPacketBeforeBroadcast(packet)
}
com.bitchat.android.service.MeshServiceHolder.setGossipManager(gossipSyncManager) { packet ->
signPacketBeforeBroadcast(packet)
}
com.bitchat.android.service.MeshServiceHolder.setGossipManager(gossipSyncManager)
if (isBleTransportEnabled()) {
TransportBridgeService.register("BLE", this)
}
@@ -144,13 +133,6 @@ class BluetoothMeshService(private val context: Context) : TransportBridgeServic
TransportBridgeService.broadcast("BLE", routed)
}
private fun sendPacketToPeerAcrossTransports(peerID: String, packet: BitchatPacket): Boolean {
if (!isBleTransportEnabled()) return false
val sentOverBle = connectionManager.sendPacketToPeer(peerID, packet)
TransportBridgeService.sendToPeer("BLE", peerID, packet)
return sentOverBle
}
private fun isBleTransportEnabled(): Boolean {
return try {
com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().bleEnabled.value
@@ -670,8 +652,9 @@ class BluetoothMeshService(private val context: Context) : TransportBridgeServic
Log.i(TAG, "BLE transport disabled by debug settings; not starting mesh service")
connectionManager.disableTransport()
TransportBridgeService.unregister("BLE")
com.bitchat.android.service.MeshServiceHolder.stopSharedGossip("BLE")
try { com.bitchat.android.services.AppStateStore.clearTransportPeers("BLE") } catch (_: Exception) { }
try { com.bitchat.android.services.AppStateStore.clearTransportDirectPeers("BLE") } catch (_: Exception) { }
try { com.bitchat.android.services.AppStateStore.clearTransportDirectPeers("BLE") } catch (_: Exception) { }
return
}
if (terminated) {
@@ -690,7 +673,7 @@ class BluetoothMeshService(private val context: Context) : TransportBridgeServic
sendPeriodicBroadcastAnnounce()
Log.d(TAG, "Started periodic broadcast announcements (every 30 seconds)")
// Start periodic syncs
gossipSyncManager.start()
com.bitchat.android.service.MeshServiceHolder.startSharedGossip("BLE")
Log.d(TAG, "GossipSyncManager started")
} else {
Log.e(TAG, "Failed to start Bluetooth services")
@@ -713,7 +696,7 @@ class BluetoothMeshService(private val context: Context) : TransportBridgeServic
isActive = false
announceJob?.cancel()
announceJob = null
try { gossipSyncManager.stop() } catch (_: Exception) { }
com.bitchat.android.service.MeshServiceHolder.stopSharedGossip("BLE")
TransportBridgeService.unregister("BLE")
try { com.bitchat.android.services.AppStateStore.clearTransportPeers("BLE") } catch (_: Exception) { }
try { com.bitchat.android.services.AppStateStore.clearTransportDirectPeers("BLE") } catch (_: Exception) { }
@@ -746,7 +729,7 @@ class BluetoothMeshService(private val context: Context) : TransportBridgeServic
delay(200) // Give leave message time to send
// Stop all components
gossipSyncManager.stop()
com.bitchat.android.service.MeshServiceHolder.stopSharedGossip("BLE")
Log.d(TAG, "GossipSyncManager stopped")
connectionManager.stopServices()
Log.d(TAG, "BluetoothConnectionManager stop requested")
@@ -3,6 +3,9 @@ package com.bitchat.android.service
import android.content.Context
import com.bitchat.android.mesh.BluetoothMeshService
import com.bitchat.android.mesh.UnifiedMeshService
import com.bitchat.android.model.RoutedPacket
import com.bitchat.android.protocol.BitchatPacket
import com.bitchat.android.sync.GossipSyncManager
/**
* Process-wide holder to share a single BluetoothMeshService instance
@@ -11,10 +14,59 @@ import com.bitchat.android.mesh.UnifiedMeshService
object MeshServiceHolder {
private const val TAG = "MeshServiceHolder"
@Volatile
var sharedGossipSyncManager: com.bitchat.android.sync.GossipSyncManager? = null
var sharedGossipSyncManager: GossipSyncManager? = null
private set
fun setGossipManager(mgr: com.bitchat.android.sync.GossipSyncManager) { sharedGossipSyncManager = mgr }
private val activeGossipOwners = mutableSetOf<String>()
@Synchronized
fun setGossipManager(
mgr: GossipSyncManager,
signer: (BitchatPacket) -> BitchatPacket
) {
val previous = sharedGossipSyncManager
if (previous !== mgr) {
try { previous?.stop() } catch (_: Exception) { }
}
sharedGossipSyncManager = mgr
mgr.delegate = TransportGossipDelegate(signer)
if (activeGossipOwners.isNotEmpty()) {
mgr.start()
}
}
@Synchronized
fun startSharedGossip(owner: String) {
val wasIdle = activeGossipOwners.isEmpty()
activeGossipOwners.add(owner)
if (wasIdle) {
sharedGossipSyncManager?.start()
}
}
@Synchronized
fun stopSharedGossip(owner: String) {
activeGossipOwners.remove(owner)
if (activeGossipOwners.isEmpty()) {
sharedGossipSyncManager?.stop()
}
}
private class TransportGossipDelegate(
private val signer: (BitchatPacket) -> BitchatPacket
) : GossipSyncManager.Delegate {
override fun sendPacket(packet: BitchatPacket) {
TransportBridgeService.broadcastFromLocal(RoutedPacket(packet))
}
override fun sendPacketToPeer(peerID: String, packet: BitchatPacket) {
TransportBridgeService.sendToPeerFromLocal(peerID, packet)
}
override fun signPacketForBroadcast(packet: BitchatPacket): BitchatPacket {
return signer(packet)
}
}
@Volatile
var meshService: BluetoothMeshService? = null
@@ -84,6 +136,9 @@ object MeshServiceHolder {
@Synchronized
fun clear() {
android.util.Log.d(TAG, "Clearing BluetoothMeshService from holder")
try { sharedGossipSyncManager?.stop() } catch (_: Exception) { }
sharedGossipSyncManager = null
activeGossipOwners.clear()
meshService = null
unifiedMeshService = null
}
@@ -105,6 +105,40 @@ object TransportBridgeService {
}
}
/**
* Send a locally originated packet to every active transport without applying relay TTL
* handling. This is used for neighbor-only packets such as REQUEST_SYNC whose TTL is
* intentionally zero on the first radio hop.
*/
fun broadcastFromLocal(packet: RoutedPacket) {
val targets = transports.toMap()
if (targets.isEmpty()) return
targets.forEach { (id, layer) ->
try {
layer.send(packet)
} catch (e: Exception) {
Log.e(TAG, "Failed to send local packet to $id: ${e.message}")
}
}
}
/**
* Send a locally originated packet directly to a peer on every active transport.
*/
fun sendToPeerFromLocal(peerID: String, packet: BitchatPacket) {
val targets = transports.toMap()
if (targets.isEmpty()) return
targets.forEach { (id, layer) ->
try {
layer.sendToPeer(peerID, packet)
} catch (e: Exception) {
Log.e(TAG, "Failed to send local peer packet to $id: ${e.message}")
}
}
}
private fun prepareForwardedPacket(kind: String, packet: BitchatPacket): BitchatPacket? {
if (packet.ttl == 0u.toUByte()) {
Log.d(TAG, "Dropping bridged packet type ${packet.type}: TTL expired")
@@ -492,12 +492,13 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
}
}, Handler(Looper.getMainLooper()))
meshCore.startCore()
startPeriodicConnectionMaintenance()
connectionTracker.start()
// Register with cross-layer transport bridge
TransportBridgeService.register("WIFI", this)
meshCore.startCore()
com.bitchat.android.service.MeshServiceHolder.startSharedGossip("WIFI")
startPeriodicConnectionMaintenance()
connectionTracker.start()
}
/**
@@ -511,6 +512,7 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
// Unregister from bridge
TransportBridgeService.unregister("WIFI")
com.bitchat.android.service.MeshServiceHolder.stopSharedGossip("WIFI")
try { com.bitchat.android.services.AppStateStore.clearTransportPeers("WIFI") } catch (_: Exception) { }
try { com.bitchat.android.services.AppStateStore.clearTransportDirectPeers("WIFI") } catch (_: Exception) { }
@@ -554,6 +556,7 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
recoveryInProgress = true
isActive = false
TransportBridgeService.unregister("WIFI")
com.bitchat.android.service.MeshServiceHolder.stopSharedGossip("WIFI")
try { com.bitchat.android.services.AppStateStore.clearTransportPeers("WIFI") } catch (_: Exception) { }
try { com.bitchat.android.services.AppStateStore.clearTransportDirectPeers("WIFI") } catch (_: Exception) { }
val oldPublishSession = publishSession
@@ -2,7 +2,7 @@ package com.bitchat.android.ui
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.bitchat.android.mesh.BluetoothMeshService
import com.bitchat.android.mesh.MeshService
import com.bitchat.android.model.BitchatMessage
import junit.framework.TestCase.assertEquals
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -34,7 +34,7 @@ class CommandProcessorTest() {
coroutineScope = testScope
)
private val meshService: BluetoothMeshService = mock()
private val meshService: MeshService = mock()
@Before
fun setup() {