mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor: KMP Migration, Messaging Modularization, and Handshake Robustness (#4631)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
b3f88bd94f
commit
d408964f07
144 changed files with 1460 additions and 664 deletions
|
|
@ -35,13 +35,15 @@ import org.meshtastic.core.common.util.nowMillis
|
|||
import org.meshtastic.core.common.util.nowSeconds
|
||||
import org.meshtastic.core.data.repository.NodeRepository
|
||||
import org.meshtastic.core.data.repository.RadioConfigRepository
|
||||
import org.meshtastic.core.model.TelemetryType
|
||||
import org.meshtastic.core.prefs.ui.UiPrefs
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.connected_count
|
||||
import org.meshtastic.core.resources.connected
|
||||
import org.meshtastic.core.resources.connecting
|
||||
import org.meshtastic.core.resources.device_sleeping
|
||||
import org.meshtastic.core.resources.disconnected
|
||||
import org.meshtastic.core.resources.getString
|
||||
import org.meshtastic.core.resources.meshtastic_app_name
|
||||
import org.meshtastic.core.service.ConnectionState
|
||||
import org.meshtastic.core.service.MeshServiceNotifications
|
||||
import org.meshtastic.proto.AdminMessage
|
||||
|
|
@ -77,12 +79,16 @@ constructor(
|
|||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private var sleepTimeout: Job? = null
|
||||
private var locationRequestsJob: Job? = null
|
||||
private var handshakeTimeout: Job? = null
|
||||
private var connectTimeMsec = 0L
|
||||
|
||||
fun start(scope: CoroutineScope) {
|
||||
this.scope = scope
|
||||
radioInterfaceService.connectionState.onEach(::onRadioConnectionState).launchIn(scope)
|
||||
|
||||
// Ensure notification title and content stay in sync with state changes
|
||||
connectionStateHolder.connectionState.onEach { updateStatusNotification() }.launchIn(scope)
|
||||
|
||||
nodeRepository.myNodeInfo
|
||||
.onEach { myNodeEntity ->
|
||||
locationRequestsJob?.cancel()
|
||||
|
|
@ -122,11 +128,21 @@ constructor(
|
|||
}
|
||||
|
||||
private fun onConnectionChanged(c: ConnectionState) {
|
||||
if (connectionStateHolder.connectionState.value == c && c !is ConnectionState.Connected) return
|
||||
Logger.d { "onConnectionChanged: ${connectionStateHolder.connectionState.value} -> $c" }
|
||||
val current = connectionStateHolder.connectionState.value
|
||||
if (current == c) return
|
||||
|
||||
// If the transport reports 'Connected', but we are already in the middle of a handshake (Connecting)
|
||||
if (c is ConnectionState.Connected && current is ConnectionState.Connecting) {
|
||||
Logger.d { "Ignoring redundant transport connection signal while handshake is in progress" }
|
||||
return
|
||||
}
|
||||
|
||||
Logger.i { "onConnectionChanged: $current -> $c" }
|
||||
|
||||
sleepTimeout?.cancel()
|
||||
sleepTimeout = null
|
||||
handshakeTimeout?.cancel()
|
||||
handshakeTimeout = null
|
||||
|
||||
when (c) {
|
||||
is ConnectionState.Connecting -> connectionStateHolder.setState(ConnectionState.Connecting)
|
||||
|
|
@ -134,19 +150,33 @@ constructor(
|
|||
is ConnectionState.DeviceSleep -> handleDeviceSleep()
|
||||
is ConnectionState.Disconnected -> handleDisconnected()
|
||||
}
|
||||
updateStatusNotification()
|
||||
}
|
||||
|
||||
private fun handleConnected() {
|
||||
// The service state remains 'Connecting' until config is fully loaded
|
||||
if (connectionStateHolder.connectionState.value == ConnectionState.Disconnected) {
|
||||
if (connectionStateHolder.connectionState.value != ConnectionState.Connected) {
|
||||
connectionStateHolder.setState(ConnectionState.Connecting)
|
||||
}
|
||||
serviceBroadcasts.broadcastConnection()
|
||||
Logger.d { "Starting connect" }
|
||||
Logger.i { "Starting mesh handshake (Stage 1)" }
|
||||
connectTimeMsec = nowMillis
|
||||
scope.handledLaunch { nodeRepository.clearMyNodeInfo() }
|
||||
startConfigOnly()
|
||||
|
||||
// Guard against handshake stalls
|
||||
handshakeTimeout =
|
||||
scope.handledLaunch {
|
||||
delay(HANDSHAKE_TIMEOUT)
|
||||
if (connectionStateHolder.connectionState.value is ConnectionState.Connecting) {
|
||||
Logger.w { "Handshake stall detected! Retrying Stage 1." }
|
||||
startConfigOnly()
|
||||
// Recursive timeout for one more try
|
||||
delay(HANDSHAKE_TIMEOUT)
|
||||
if (connectionStateHolder.connectionState.value is ConnectionState.Connecting) {
|
||||
Logger.e { "Handshake still stalled after retry. Resetting connection." }
|
||||
onConnectionChanged(ConnectionState.Disconnected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDeviceSleep() {
|
||||
|
|
@ -215,6 +245,9 @@ constructor(
|
|||
}
|
||||
|
||||
fun onNodeDbReady() {
|
||||
handshakeTimeout?.cancel()
|
||||
handshakeTimeout = null
|
||||
|
||||
// Start MQTT if enabled
|
||||
scope.handledLaunch {
|
||||
val moduleConfig = radioConfigRepository.moduleConfigFlow.first()
|
||||
|
|
@ -236,7 +269,9 @@ constructor(
|
|||
}
|
||||
}
|
||||
|
||||
updateStatusNotification()
|
||||
// Request immediate LocalStats and DeviceMetrics update on connection with proper request IDs
|
||||
commandSender.requestTelemetry(commandSender.generatePacketId(), myNodeNum, TelemetryType.LOCAL_STATS.ordinal)
|
||||
commandSender.requestTelemetry(commandSender.generatePacketId(), myNodeNum, TelemetryType.DEVICE.ordinal)
|
||||
}
|
||||
|
||||
private fun reportConnection() {
|
||||
|
|
@ -258,8 +293,7 @@ constructor(
|
|||
val summary =
|
||||
when (connectionStateHolder.connectionState.value) {
|
||||
is ConnectionState.Connected ->
|
||||
getString(Res.string.connected_count)
|
||||
.format(nodeManager.nodeDBbyNodeNum.values.count { it.isOnline })
|
||||
getString(Res.string.meshtastic_app_name) + ": " + getString(Res.string.connected)
|
||||
is ConnectionState.Disconnected -> getString(Res.string.disconnected)
|
||||
is ConnectionState.DeviceSleep -> getString(Res.string.device_sleeping)
|
||||
is ConnectionState.Connecting -> getString(Res.string.connecting)
|
||||
|
|
@ -271,6 +305,7 @@ constructor(
|
|||
private const val CONFIG_ONLY_NONCE = 69420
|
||||
private const val NODE_INFO_NONCE = 69421
|
||||
private const val DEVICE_SLEEP_TIMEOUT_SECONDS = 30
|
||||
private val HANDSHAKE_TIMEOUT = 10.seconds
|
||||
|
||||
private const val EVENT_CONNECTED_SECONDS = "connected_seconds"
|
||||
private const val EVENT_MESH_DISCONNECT = "mesh_disconnect"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue