mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-12 08:42:01 -04:00
fix: remove SFPP vestige, resource-back badge strings, add bridge tests
- Remove handleStoreForwardPlusPlus() from interface + impl (dead code post-SDK cutover) - Move StoreForwardBadge/CongestionBadge hardcoded strings to string resources (i18n) - Add SdkStateBridge tests: congestion warning → ServiceRepository, S&F server propagation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -34,7 +34,7 @@ import kotlin.time.Duration.Companion.milliseconds
|
||||
/**
|
||||
* Implementation of [StoreForwardPacketHandler] that keeps legacy S&F parsing for backward compatibility.
|
||||
*
|
||||
* SF++ parsing/status updates are now delegated to the SDK and consumed via [org.meshtastic.core.data.radio.SdkStateBridge].
|
||||
* SF++ parsing/status updates are delegated to the SDK and consumed via [org.meshtastic.core.data.radio.SdkStateBridge].
|
||||
*/
|
||||
@Single
|
||||
class StoreForwardPacketHandlerImpl(
|
||||
@@ -50,10 +50,6 @@ class StoreForwardPacketHandlerImpl(
|
||||
handleReceivedStoreAndForward(dataPacket, u, myNodeNum)
|
||||
}
|
||||
|
||||
override fun handleStoreForwardPlusPlus(packet: MeshPacket) {
|
||||
Logger.d { "SFPP packet received from=${packet.from} (handled by SDK)" }
|
||||
}
|
||||
|
||||
private fun handleReceivedStoreAndForward(dataPacket: DataPacket, s: StoreAndForward, myNodeNum: Int) {
|
||||
val lastRequest = s.history?.last_request ?: 0
|
||||
Logger.d { "StoreAndForward from=${dataPacket.from} lastRequest=$lastRequest" }
|
||||
|
||||
@@ -185,28 +185,4 @@ class StoreForwardPacketHandlerImplTest {
|
||||
advanceUntilIdle()
|
||||
// No crash — falls through to else branch
|
||||
}
|
||||
|
||||
// ---------- SF++: delegated to SDK ----------
|
||||
|
||||
@Test
|
||||
fun `handleStoreForwardPlusPlus logs only and leaves repository untouched`() = testScope.runTest {
|
||||
val packet =
|
||||
MeshPacket(
|
||||
from = 999,
|
||||
decoded = Data(
|
||||
portnum = PortNum.STORE_FORWARD_APP,
|
||||
payload = "ignored".encodeToByteArray().toByteString(),
|
||||
),
|
||||
)
|
||||
|
||||
handler.handleStoreForwardPlusPlus(packet)
|
||||
advanceUntilIdle()
|
||||
|
||||
verifySuspend(mode = VerifyMode.exactly(0)) {
|
||||
packetRepository.updateSFPPStatus(any(), any(), any(), any(), any(), any(), any())
|
||||
}
|
||||
verifySuspend(mode = VerifyMode.exactly(0)) {
|
||||
packetRepository.updateSFPPStatusByHash(any(), any(), any())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ import org.meshtastic.sdk.TransportIdentity
|
||||
import org.meshtastic.sdk.testing.FakeRadioTransport
|
||||
import org.meshtastic.sdk.testing.InMemoryStorage
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.time.Clock
|
||||
@@ -196,6 +197,65 @@ class SdkStateBridgeTest {
|
||||
client.disconnect()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `congestion warning updates service repository congestion level`() = runTest {
|
||||
val serviceRepo = FakeServiceRepository()
|
||||
val (transport, client) = connectedClient(SeededHeartbeatStorageProvider(emptyMap()))
|
||||
buildBridge(client, FakeNodeRepository(), serviceRepository = serviceRepo)
|
||||
|
||||
client.connect()
|
||||
runCurrent()
|
||||
|
||||
// Inject a telemetry packet with high air utilization to trigger CongestionWarning
|
||||
transport.injectPacket(
|
||||
MeshPacket(
|
||||
from = 0x11111111, // "own node" — triggers congestion from local metrics
|
||||
to = 0,
|
||||
decoded = Data(
|
||||
portnum = PortNum.TELEMETRY_APP,
|
||||
payload = org.meshtastic.proto.Telemetry(
|
||||
device_metrics = org.meshtastic.proto.DeviceMetrics(
|
||||
air_util_tx = 80f,
|
||||
channel_utilization = 85f,
|
||||
),
|
||||
).let { org.meshtastic.proto.Telemetry.ADAPTER.encode(it).toByteString() },
|
||||
),
|
||||
),
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertEquals(org.meshtastic.sdk.CongestionLevel.CRITICAL, serviceRepo.congestionLevel.value)
|
||||
|
||||
client.disconnect()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `store forward server list propagates to service repository`() = runTest {
|
||||
val serviceRepo = FakeServiceRepository()
|
||||
val (transport, client) = connectedClient(SeededHeartbeatStorageProvider(emptyMap()))
|
||||
buildBridge(client, FakeNodeRepository(), serviceRepository = serviceRepo)
|
||||
|
||||
client.connect()
|
||||
runCurrent()
|
||||
|
||||
// Inject a StoreAndForward heartbeat from a server node to trigger server discovery
|
||||
transport.injectStoreForwardResponse(
|
||||
requestId = 0,
|
||||
message = org.meshtastic.proto.StoreAndForward(
|
||||
rr = org.meshtastic.proto.StoreAndForward.RequestResponse.ROUTER_HEARTBEAT,
|
||||
heartbeat = org.meshtastic.proto.StoreAndForward.Heartbeat(period = 900, secondary = 0),
|
||||
),
|
||||
fromNode = 0xABCD1234.toInt(),
|
||||
)
|
||||
runCurrent()
|
||||
advanceTimeBy(1.seconds)
|
||||
runCurrent()
|
||||
|
||||
assertTrue(serviceRepo.storeForwardServers.value.contains(0xABCD1234.toInt()))
|
||||
|
||||
client.disconnect()
|
||||
}
|
||||
|
||||
private fun TestScope.connectedClient(
|
||||
storage: StorageProvider,
|
||||
myNodeNum: Int = 0x11111111,
|
||||
@@ -217,10 +277,11 @@ class SdkStateBridgeTest {
|
||||
client: RadioClient,
|
||||
nodeRepository: FakeNodeRepository,
|
||||
packetRepository: PacketRepository = mock(MockMode.autofill),
|
||||
serviceRepository: FakeServiceRepository = FakeServiceRepository(),
|
||||
): SdkStateBridge =
|
||||
SdkStateBridge(
|
||||
accessor = TestRadioClientAccessor(client),
|
||||
serviceRepository = FakeServiceRepository(),
|
||||
serviceRepository = serviceRepository,
|
||||
nodeRepository = nodeRepository,
|
||||
packetRepository = lazyOf(packetRepository),
|
||||
locationManager = NoOpLocationManager,
|
||||
|
||||
@@ -19,7 +19,7 @@ package org.meshtastic.core.repository
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
|
||||
/** Interface for handling Store & Forward (legacy) and SF++ packets. */
|
||||
/** Interface for handling Store & Forward (legacy) packets. */
|
||||
interface StoreForwardPacketHandler {
|
||||
/**
|
||||
* Handles a legacy Store & Forward packet.
|
||||
@@ -29,11 +29,4 @@ interface StoreForwardPacketHandler {
|
||||
* @param myNodeNum The local node number.
|
||||
*/
|
||||
fun handleStoreAndForward(packet: MeshPacket, dataPacket: DataPacket, myNodeNum: Int)
|
||||
|
||||
/**
|
||||
* Handles a Store Forward++ packet.
|
||||
*
|
||||
* @param packet The received mesh packet.
|
||||
*/
|
||||
fun handleStoreForwardPlusPlus(packet: MeshPacket)
|
||||
}
|
||||
|
||||
@@ -1144,6 +1144,8 @@
|
||||
<string name="store_forward">Store & Forward</string>
|
||||
<string name="store_forward_config">Store & Forward Config</string>
|
||||
<string name="store_forward_enabled">Store & Forward enabled</string>
|
||||
<string name="store_forward_server">Store & Forward server</string>
|
||||
<string name="congestion_level">Channel: %1$s</string>
|
||||
<string name="subnet">Subred</string>
|
||||
<string name="super_deep_sleep_duration_seconds">Super deep sleep duration</string>
|
||||
<string name="supported">Supported</string>
|
||||
|
||||
@@ -39,12 +39,14 @@ import org.jetbrains.compose.resources.stringResource
|
||||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.DeviceType
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.congestion_level
|
||||
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.favorite
|
||||
import org.meshtastic.core.resources.mute_always
|
||||
import org.meshtastic.core.resources.store_forward_server
|
||||
import org.meshtastic.core.resources.unmessageable
|
||||
import org.meshtastic.core.resources.unmonitored_or_infrastructure
|
||||
import org.meshtastic.core.ui.component.ConnectionsNavIcon
|
||||
@@ -142,14 +144,15 @@ private fun ThisNodeStatusBadge(connectionState: ConnectionState, deviceType: De
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun StoreForwardBadge() {
|
||||
val text = stringResource(Res.string.store_forward_server)
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
|
||||
tooltip = { PlainTooltip { Text("Store & Forward server") } },
|
||||
tooltip = { PlainTooltip { Text(text) } },
|
||||
state = rememberTooltipState(),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MeshtasticIcons.CloudDownload,
|
||||
contentDescription = "Store & Forward server",
|
||||
contentDescription = text,
|
||||
modifier = Modifier.size(24.dp),
|
||||
tint = MaterialTheme.colorScheme.StatusBlue,
|
||||
)
|
||||
@@ -166,14 +169,15 @@ private fun CongestionBadge(level: CongestionLevel) {
|
||||
CongestionLevel.CRITICAL -> MaterialTheme.colorScheme.StatusRed
|
||||
else -> return
|
||||
}
|
||||
val tooltipText = stringResource(Res.string.congestion_level, level.name)
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
|
||||
tooltip = { PlainTooltip { Text("Channel: ${level.name}") } },
|
||||
tooltip = { PlainTooltip { Text(tooltipText) } },
|
||||
state = rememberTooltipState(),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MeshtasticIcons.Warning,
|
||||
contentDescription = "Congestion: ${level.name}",
|
||||
contentDescription = tooltipText,
|
||||
modifier = Modifier.size(24.dp),
|
||||
tint = color,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user