diff --git a/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/PacketRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/PacketRepositoryImpl.kt index 04e09eaf7..a5664b1a0 100644 --- a/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/PacketRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/PacketRepositoryImpl.kt @@ -28,6 +28,7 @@ import kotlinx.coroutines.withContext import okio.ByteString.Companion.toByteString import org.koin.core.annotation.Single import org.meshtastic.core.database.DatabaseProvider +import org.meshtastic.core.database.entity.PacketEntity import org.meshtastic.core.database.entity.toReaction import org.meshtastic.core.di.CoroutineDispatchers import org.meshtastic.core.model.ContactSettings @@ -154,13 +155,14 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val else -> dao.getMessagesFrom(contact) } flow.mapLatest { packets -> + val cachedGetNode = memoize(getNode) + val replyIds = packets.mapNotNull { it.packet.data.replyId?.takeIf { id -> id != 0 } }.distinct() + val replyMap = batchGetPacketsByIds(replyIds) packets.map { packet -> - val message = packet.toMessage(getNode) - message.replyId - .takeIf { it != null && it != 0 } - ?.let { getPacketByPacketIdInternal(it) } - ?.let { originalPacket -> originalPacket.toMessage(getNode) } - ?.let { originalMessage -> message.copy(originalMessage = originalMessage) } ?: message + val message = packet.toMessage(cachedGetNode) + val replyId = message.replyId?.takeIf { it != 0 } + val originalMessage = replyId?.let { replyMap[it] }?.toMessage(cachedGetNode) + if (originalMessage != null) message.copy(originalMessage = originalMessage) else message } } } @@ -177,13 +179,16 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val ) .flow .map { pagingData -> + val cachedGetNode = memoize(getNode) + val replyCache = mutableMapOf() pagingData.map { packet -> - val message = packet.toMessage(getNode) - message.replyId - .takeIf { it != null && it != 0 } - ?.let { getPacketByPacketIdInternal(it) } - ?.let { originalPacket -> originalPacket.toMessage(getNode) } - ?.let { originalMessage -> message.copy(originalMessage = originalMessage) } ?: message + val message = packet.toMessage(cachedGetNode) + val replyId = message.replyId?.takeIf { it != 0 } + val originalMessage = + replyId + ?.let { id -> replyCache.getOrPut(id) { getPacketByPacketIdInternal(id) } } + ?.toMessage(cachedGetNode) + if (originalMessage != null) message.copy(originalMessage = originalMessage) else message } } @@ -204,13 +209,16 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val ) .flow .map { pagingData -> + val cachedGetNode = memoize(getNode) + val replyCache = mutableMapOf() pagingData.map { packet -> - val message = packet.toMessage(getNode) - message.replyId - .takeIf { it != null && it != 0 } - ?.let { getPacketByPacketIdInternal(it) } - ?.let { originalPacket -> originalPacket.toMessage(getNode) } - ?.let { originalMessage -> message.copy(originalMessage = originalMessage) } ?: message + val message = packet.toMessage(cachedGetNode) + val replyId = message.replyId?.takeIf { it != 0 } + val originalMessage = + replyId + ?.let { id -> replyCache.getOrPut(id) { getPacketByPacketIdInternal(id) } } + ?.toMessage(cachedGetNode) + if (originalMessage != null) message.copy(originalMessage = originalMessage) else message } } @@ -230,6 +238,19 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val private suspend fun getPacketByPacketIdInternal(packetId: Int) = withContext(dispatchers.io) { dbManager.currentDb.value.packetDao().getPacketByPacketId(packetId) } + private suspend fun batchGetPacketsByIds(ids: List): Map = if (ids.isEmpty()) { + emptyMap() + } else { + withContext(dispatchers.io) { + dbManager.currentDb.value.packetDao().getPacketsByPacketIds(ids).associateBy { it.packet.packetId } + } + } + + private fun memoize(getNode: suspend (String?) -> Node): suspend (String?) -> Node { + val cache = mutableMapOf() + return { id -> cache.getOrPut(id) { getNode(id) } } + } + override suspend fun insert( packet: DataPacket, myNodeNum: Int, diff --git a/core/database/src/commonMain/kotlin/org/meshtastic/core/database/dao/PacketDao.kt b/core/database/src/commonMain/kotlin/org/meshtastic/core/database/dao/PacketDao.kt index 71017799c..c2ef9c516 100644 --- a/core/database/src/commonMain/kotlin/org/meshtastic/core/database/dao/PacketDao.kt +++ b/core/database/src/commonMain/kotlin/org/meshtastic/core/database/dao/PacketDao.kt @@ -309,6 +309,16 @@ interface PacketDao { ) suspend fun getPacketByPacketId(packetId: Int): PacketEntity? + @Transaction + @Query( + """ + SELECT * FROM packet + WHERE packet_id IN (:packetIds) + AND (myNodeNum = 0 OR myNodeNum = (SELECT myNodeNum FROM my_node)) + """, + ) + suspend fun getPacketsByPacketIds(packetIds: List): List + @Query( """ SELECT * FROM packet