diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt index 2b7c8159ea..f0caa9d314 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt @@ -142,8 +142,7 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti val messages = rawMessages["messages"] as? List<*> val processed = if (!messages.isNullOrEmpty()) { SnodeAPI.updateLastMessageHashValueIfPossible(snode, userPublicKey, messages, namespace) - SnodeAPI.removeDuplicates(userPublicKey, messages, namespace, true).mapNotNull { messageBody -> - val rawMessageAsJSON = messageBody as? Map<*, *> ?: return@mapNotNull null + SnodeAPI.removeDuplicates(userPublicKey, messages, namespace, true).mapNotNull { rawMessageAsJSON -> val hashValue = rawMessageAsJSON["hash"] as? String ?: return@mapNotNull null val b64EncodedBody = rawMessageAsJSON["data"] as? String ?: return@mapNotNull null val timestamp = rawMessageAsJSON["t"] as? Long ?: SnodeAPI.nowWithOffset diff --git a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt index 9c584ba0fb..72b144be03 100644 --- a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt +++ b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt @@ -660,29 +660,33 @@ object SnodeAPI { } } - fun removeDuplicates(publicKey: String, rawMessages: List<*>, namespace: Int, updateStoredHashes: Boolean): List<*> { - val originalMessageHashValues = database.getReceivedMessageHashValues(publicKey, namespace) ?: emptySet() - val receivedMessageHashValues = originalMessageHashValues.toMutableSet() - return rawMessages.filter { rawMessage -> - (rawMessage as? Map<*, *>) - ?.let { it["hash"] as? String } - ?.let { receivedMessageHashValues.add(it) } - ?: false.also { Log.d("Loki", "Missing hash value for message: ${rawMessage?.prettifiedDescription()}.") } + /** + * + * + * TODO Use a db transaction, synchronizing is sufficient for now because + * database#setReceivedMessageHashValues is only called here. + */ + @Synchronized + fun removeDuplicates(publicKey: String, rawMessages: List<*>, namespace: Int, updateStoredHashes: Boolean): List> { + val hashValues = database.getReceivedMessageHashValues(publicKey, namespace)?.toMutableSet() ?: mutableSetOf() + return rawMessages.filterIsInstance>().filter { rawMessage -> + val hash = rawMessage["hash"] as? String + hash ?: Log.d("Loki", "Missing hash value for message: ${rawMessage.prettifiedDescription()}.") + hash?.let(hashValues::add) == true }.also { - if (updateStoredHashes && originalMessageHashValues.containsAll(receivedMessageHashValues)) { - database.setReceivedMessageHashValues(publicKey, receivedMessageHashValues, namespace) + if (updateStoredHashes && it.isNotEmpty()) { + database.setReceivedMessageHashValues(publicKey, hashValues, namespace) } } } - private fun parseEnvelopes(rawMessages: List<*>): List> = rawMessages.mapNotNull { rawMessage -> - val rawMessageAsJSON = rawMessage as? Map<*, *> - val base64EncodedData = rawMessageAsJSON?.get("data") as? String - val data = base64EncodedData?.let { Base64.decode(it) } + private fun parseEnvelopes(rawMessages: List>): List> = rawMessages.mapNotNull { rawMessage -> + val base64EncodedData = rawMessage["data"] as? String + val data = base64EncodedData?.let(Base64::decode) - data ?: Log.d("Loki", "Failed to decode data for message: ${rawMessage?.prettifiedDescription()}.") + data ?: Log.d("Loki", "Failed to decode data for message: ${rawMessage.prettifiedDescription()}.") - data?.runCatching { MessageWrapper.unwrap(this) to rawMessageAsJSON["hash"] as? String } + data?.runCatching { MessageWrapper.unwrap(this) to rawMessage["hash"] as? String } ?.onFailure { Log.d("Loki", "Failed to unwrap data for message: ${rawMessage.prettifiedDescription()}.") } ?.getOrNull() }