From 2b79590881b3791713e504e0323ced4f66ec9818 Mon Sep 17 00:00:00 2001 From: Dane Evans Date: Fri, 31 Oct 2025 01:55:37 +1100 Subject: [PATCH] fix #2062: Remap channels when rearranged (#3561) --- .../core/data/repository/PacketRepository.kt | 4 +++ .../meshtastic/core/database/dao/PacketDao.kt | 26 +++++++++++++++++++ .../settings/radio/RadioConfigViewModel.kt | 9 ++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/PacketRepository.kt b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/PacketRepository.kt index 87e24182f..d39c36147 100644 --- a/core/data/src/main/kotlin/org/meshtastic/core/data/repository/PacketRepository.kt +++ b/core/data/src/main/kotlin/org/meshtastic/core/data/repository/PacketRepository.kt @@ -29,6 +29,7 @@ import org.meshtastic.core.database.entity.ReactionEntity import org.meshtastic.core.database.model.Node import org.meshtastic.core.model.DataPacket import org.meshtastic.core.model.MessageStatus +import org.meshtastic.proto.ChannelProtos.ChannelSettings import org.meshtastic.proto.Portnums.PortNum import javax.inject.Inject @@ -103,4 +104,7 @@ class PacketRepository @Inject constructor(private val packetDaoLazy: Lazy, newSettings: List) = + packetDao.migrateChannelsByPSK(oldSettings, newSettings) } diff --git a/core/database/src/main/kotlin/org/meshtastic/core/database/dao/PacketDao.kt b/core/database/src/main/kotlin/org/meshtastic/core/database/dao/PacketDao.kt index 20d0e1111..7b9379ff0 100644 --- a/core/database/src/main/kotlin/org/meshtastic/core/database/dao/PacketDao.kt +++ b/core/database/src/main/kotlin/org/meshtastic/core/database/dao/PacketDao.kt @@ -30,6 +30,7 @@ import org.meshtastic.core.database.entity.PacketEntity import org.meshtastic.core.database.entity.ReactionEntity import org.meshtastic.core.model.DataPacket import org.meshtastic.core.model.MessageStatus +import org.meshtastic.proto.ChannelProtos.ChannelSettings @Suppress("TooManyFunctions") @Dao @@ -250,4 +251,29 @@ interface PacketDao { @Query("DELETE FROM packet") suspend fun deleteAll() + + /** + * One-time migration: Remap all message DataPacket.channel indices to new mapping using PSK after a channel + * reorder. For each Packet (with port_num = 1), finds the old PSK then sets the channel index to the matching + * newSettings index. Skips if PSKs do not match or are missing. + */ + @Transaction + suspend fun migrateChannelsByPSK(oldSettings: List, newSettings: List) { + val pskToNewIndex = newSettings.mapIndexed { idx, ch -> ch.psk to idx }.toMap() + val allPackets = getAllUserPacketsForMigration() + for (packet in allPackets) { + val oldIndex = packet.data.channel + val oldPSK = oldSettings.getOrNull(oldIndex)?.psk + val newIndex = if (oldPSK != null) pskToNewIndex[oldPSK] else null + if (oldPSK != null && newIndex != null && oldIndex != newIndex) { + // Rebuild contact_key with the new index, keeping the rest unchanged + val oldKeySuffix = packet.contact_key.drop(1) // removes only the channelIndex prefix + val newContactKey = "$newIndex$oldKeySuffix" + update(packet.copy(contact_key = newContactKey, data = packet.data.copy(channel = newIndex))) + } + } + } + + @Query("SELECT * FROM packet WHERE port_num = 1") + suspend fun getAllUserPacketsForMigration(): List } diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt index 591338ea8..1b99cda5e 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt @@ -49,6 +49,7 @@ import kotlinx.coroutines.withContext import org.json.JSONObject import org.meshtastic.core.data.repository.LocationRepository import org.meshtastic.core.data.repository.NodeRepository +import org.meshtastic.core.data.repository.PacketRepository import org.meshtastic.core.data.repository.RadioConfigRepository import org.meshtastic.core.database.entity.MyNodeEntity import org.meshtastic.core.database.model.Node @@ -108,6 +109,7 @@ constructor( savedStateHandle: SavedStateHandle, private val app: Application, private val radioConfigRepository: RadioConfigRepository, + private val packetRepository: PacketRepository, private val serviceRepository: ServiceRepository, private val nodeRepository: NodeRepository, private val locationRepository: LocationRepository, @@ -247,7 +249,12 @@ constructor( val destNum = destNode.value?.num ?: return getChannelList(new, old).forEach { setRemoteChannel(destNum, it) } - if (destNum == myNodeNum) viewModelScope.launch { radioConfigRepository.replaceAllSettings(new) } + if (destNum == myNodeNum) { + viewModelScope.launch { + packetRepository.migrateChannelsByPSK(old, new) + radioConfigRepository.replaceAllSettings(new) + } + } _radioConfigState.update { it.copy(channelList = new) } }