Merge pull request #42 from loki-project/batch-name-updating

Public chat batch name updating
This commit is contained in:
gmbnt 2019-11-18 13:19:39 +11:00 committed by GitHub
commit 053183a628
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,12 +1,17 @@
package org.thoughtcrime.securesms.loki package org.thoughtcrime.securesms.loki
import android.content.Context import android.content.Context
import android.os.AsyncTask
import android.os.Handler import android.os.Handler
import android.util.Log import android.util.Log
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.then
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.jobs.PushDecryptJob import org.thoughtcrime.securesms.jobs.PushDecryptJob
import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.Util
import org.whispersystems.libsignal.util.guava.Optional import org.whispersystems.libsignal.util.guava.Optional
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer
import org.whispersystems.signalservice.api.messages.SignalServiceContent import org.whispersystems.signalservice.api.messages.SignalServiceContent
@ -18,7 +23,6 @@ import org.whispersystems.signalservice.loki.api.LokiPublicChat
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI
import org.whispersystems.signalservice.loki.api.LokiPublicChatMessage import org.whispersystems.signalservice.loki.api.LokiPublicChatMessage
import org.whispersystems.signalservice.loki.api.LokiStorageAPI import org.whispersystems.signalservice.loki.api.LokiStorageAPI
import org.whispersystems.signalservice.loki.utilities.get
import org.whispersystems.signalservice.loki.utilities.successBackground import org.whispersystems.signalservice.loki.utilities.successBackground
import java.util.* import java.util.*
@ -28,6 +32,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
// region Convenience // region Convenience
private val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) private val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
private var displayNameUpdatees = setOf<String>()
private val api: LokiPublicChatAPI private val api: LokiPublicChatAPI
get() = { get() = {
@ -62,6 +67,13 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
handler.postDelayed(this, pollForModeratorsInterval) handler.postDelayed(this, pollForModeratorsInterval)
} }
} }
private val pollForDisplayNamesTask = object : Runnable {
override fun run() {
pollForDisplayNames()
handler.postDelayed(this, pollForDisplayNamesInterval)
}
}
// endregion // endregion
// region Settings // region Settings
@ -69,6 +81,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
private val pollForNewMessagesInterval: Long = 4 * 1000 private val pollForNewMessagesInterval: Long = 4 * 1000
private val pollForDeletedMessagesInterval: Long = 20 * 1000 private val pollForDeletedMessagesInterval: Long = 20 * 1000
private val pollForModeratorsInterval: Long = 10 * 60 * 1000 private val pollForModeratorsInterval: Long = 10 * 60 * 1000
private val pollForDisplayNamesInterval: Long = 60 * 1000
} }
// endregion // endregion
@ -78,6 +91,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
pollForNewMessagesTask.run() pollForNewMessagesTask.run()
pollForDeletedMessagesTask.run() pollForDeletedMessagesTask.run()
pollForModeratorsTask.run() pollForModeratorsTask.run()
pollForDisplayNamesTask.run()
hasStarted = true hasStarted = true
} }
@ -85,6 +99,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
handler.removeCallbacks(pollForNewMessagesTask) handler.removeCallbacks(pollForNewMessagesTask)
handler.removeCallbacks(pollForDeletedMessagesTask) handler.removeCallbacks(pollForDeletedMessagesTask)
handler.removeCallbacks(pollForModeratorsTask) handler.removeCallbacks(pollForModeratorsTask)
handler.removeCallbacks(pollForDisplayNamesTask)
hasStarted = false hasStarted = false
} }
// endregion // endregion
@ -136,14 +151,21 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
private fun pollForNewMessages() { private fun pollForNewMessages() {
fun processIncomingMessage(message: LokiPublicChatMessage) { fun processIncomingMessage(message: LokiPublicChatMessage) {
// If the sender of the current message is not a secondary device, we need to set the display name in the database
val primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(message.hexEncodedPublicKey).get()
if (primaryDevice == null) {
val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})"
DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName)
}
val senderPublicKey = primaryDevice ?: message.hexEncodedPublicKey
val serviceDataMessage = getDataMessage(message) val serviceDataMessage = getDataMessage(message)
val serviceContent = SignalServiceContent(serviceDataMessage, message.hexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false) val serviceContent = SignalServiceContent(serviceDataMessage, senderPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false)
val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" Util.runOnMain {
DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) if (serviceDataMessage.quote.isPresent || (serviceDataMessage.attachments.isPresent && serviceDataMessage.attachments.get().size > 0) || serviceDataMessage.previews.isPresent) {
if (serviceDataMessage.quote.isPresent || (serviceDataMessage.attachments.isPresent && serviceDataMessage.attachments.get().size > 0) || serviceDataMessage.previews.isPresent) { PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID))
PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) } else {
} else { PushDecryptJob(context).handleTextMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID))
PushDecryptJob(context).handleTextMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) }
} }
} }
fun processOutgoingMessage(message: LokiPublicChatMessage) { fun processOutgoingMessage(message: LokiPublicChatMessage) {
@ -155,18 +177,44 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
val dataMessage = getDataMessage(message) val dataMessage = getDataMessage(message)
val transcript = SentTranscriptMessage(localNumber, dataMessage.timestamp, dataMessage, dataMessage.expiresInSeconds.toLong(), Collections.singletonMap(localNumber, false)) val transcript = SentTranscriptMessage(localNumber, dataMessage.timestamp, dataMessage, dataMessage.expiresInSeconds.toLong(), Collections.singletonMap(localNumber, false))
transcript.messageServerID = messageServerID transcript.messageServerID = messageServerID
if (dataMessage.quote.isPresent || (dataMessage.attachments.isPresent && dataMessage.attachments.get().size > 0) || dataMessage.previews.isPresent) { Util.runOnMain {
PushDecryptJob(context).handleSynchronizeSentMediaMessage(transcript) if (dataMessage.quote.isPresent || (dataMessage.attachments.isPresent && dataMessage.attachments.get().size > 0) || dataMessage.previews.isPresent) {
} else { PushDecryptJob(context).handleSynchronizeSentMediaMessage(transcript)
PushDecryptJob(context).handleSynchronizeSentTextMessage(transcript) } else {
PushDecryptJob(context).handleSynchronizeSentTextMessage(transcript)
}
} }
} }
api.getMessages(group.channel, group.server).successBackground { messages -> var userDevices = setOf<String>()
var uniqueDevices = setOf<String>()
LokiStorageAPI.shared.getAllDevicePublicKeys(userHexEncodedPublicKey).bind { devices ->
userDevices = devices
api.getMessages(group.channel, group.server)
}.bind { messages ->
if (messages.isNotEmpty()) { if (messages.isNotEmpty()) {
val ourDevices = LokiStorageAPI.shared.getAllDevicePublicKeys(userHexEncodedPublicKey).get(setOf()) // We need to fetch device mappings for all the devices we don't have
// Process messages in the background uniqueDevices = messages.map { it.hexEncodedPublicKey }.toSet()
messages.forEach { message -> val devicesToUpdate = uniqueDevices.filter { !userDevices.contains(it) && LokiStorageAPI.shared.hasCacheExpired(it) }
if (ourDevices.contains(message.hexEncodedPublicKey)) { if (devicesToUpdate.isNotEmpty()) {
return@bind LokiStorageAPI.shared.getDeviceMappings(devicesToUpdate.toSet()).then { messages }
}
}
Promise.of(messages)
}.successBackground {
// Get the set of primary device pubKeys FROM the secondary devices in uniqueDevices
val newDisplayNameUpdatees = uniqueDevices.mapNotNull {
// This will return null if current device is primary
// So if it's non-null then we know the device is a secondary device
val primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(it).get()
primaryDevice
}.toSet()
// Fetch the display names of the primary devices
displayNameUpdatees = displayNameUpdatees.union(newDisplayNameUpdatees)
}.success { messages ->
// Process messages in the background
messages.forEach { message ->
AsyncTask.execute {
if (userDevices.contains(message.hexEncodedPublicKey)) {
processOutgoingMessage(message) processOutgoingMessage(message)
} else { } else {
processIncomingMessage(message) processIncomingMessage(message)
@ -178,6 +226,20 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
} }
} }
private fun pollForDisplayNames() {
if (displayNameUpdatees.isEmpty()) { return }
val hexEncodedPublicKeys = displayNameUpdatees
displayNameUpdatees = setOf()
api.getDisplayNames(hexEncodedPublicKeys, group.server).successBackground { mapping ->
for (pair in mapping.entries) {
val senderDisplayName = "${pair.value} (...${pair.key.takeLast(8)})"
DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, pair.key, senderDisplayName)
}
}.fail {
displayNameUpdatees = displayNameUpdatees.union(hexEncodedPublicKeys)
}
}
private fun pollForDeletedMessages() { private fun pollForDeletedMessages() {
api.getDeletedMessageServerIDs(group.channel, group.server).success { deletedMessageServerIDs -> api.getDeletedMessageServerIDs(group.channel, group.server).success { deletedMessageServerIDs ->
val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context)