|
|
@ -1,8 +1,6 @@
|
|
|
|
package org.session.libsession.messaging.sending_receiving.pollers
|
|
|
|
package org.session.libsession.messaging.sending_receiving.pollers
|
|
|
|
|
|
|
|
|
|
|
|
import android.os.Handler
|
|
|
|
|
|
|
|
import com.google.protobuf.ByteString
|
|
|
|
import com.google.protobuf.ByteString
|
|
|
|
|
|
|
|
|
|
|
|
import nl.komponents.kovenant.Promise
|
|
|
|
import nl.komponents.kovenant.Promise
|
|
|
|
import nl.komponents.kovenant.deferred
|
|
|
|
import nl.komponents.kovenant.deferred
|
|
|
|
import org.session.libsession.messaging.MessagingConfiguration
|
|
|
|
import org.session.libsession.messaging.MessagingConfiguration
|
|
|
@ -11,61 +9,37 @@ import org.session.libsession.messaging.jobs.MessageReceiveJob
|
|
|
|
import org.session.libsession.messaging.opengroups.OpenGroup
|
|
|
|
import org.session.libsession.messaging.opengroups.OpenGroup
|
|
|
|
import org.session.libsession.messaging.opengroups.OpenGroupAPI
|
|
|
|
import org.session.libsession.messaging.opengroups.OpenGroupAPI
|
|
|
|
import org.session.libsession.messaging.opengroups.OpenGroupMessage
|
|
|
|
import org.session.libsession.messaging.opengroups.OpenGroupMessage
|
|
|
|
|
|
|
|
|
|
|
|
import org.session.libsignal.utilities.successBackground
|
|
|
|
|
|
|
|
import org.session.libsignal.utilities.logging.Log
|
|
|
|
|
|
|
|
import org.session.libsignal.service.internal.push.SignalServiceProtos.*
|
|
|
|
import org.session.libsignal.service.internal.push.SignalServiceProtos.*
|
|
|
|
|
|
|
|
import org.session.libsignal.utilities.logging.Log
|
|
|
|
|
|
|
|
import org.session.libsignal.utilities.successBackground
|
|
|
|
import java.util.*
|
|
|
|
import java.util.*
|
|
|
|
|
|
|
|
import java.util.concurrent.ScheduledExecutorService
|
|
|
|
|
|
|
|
import java.util.concurrent.ScheduledFuture
|
|
|
|
|
|
|
|
import java.util.concurrent.TimeUnit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OpenGroupPoller(private val openGroup: OpenGroup, private val executorService: ScheduledExecutorService? = null) {
|
|
|
|
|
|
|
|
|
|
|
|
class OpenGroupPoller(private val openGroup: OpenGroup) {
|
|
|
|
|
|
|
|
private val handler by lazy { Handler() }
|
|
|
|
|
|
|
|
private var hasStarted = false
|
|
|
|
private var hasStarted = false
|
|
|
|
private var isPollOngoing = false
|
|
|
|
@Volatile private var isPollOngoing = false
|
|
|
|
public var isCaughtUp = false
|
|
|
|
var isCaughtUp = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private val cancellableFutures = mutableListOf<ScheduledFuture<out Any>>()
|
|
|
|
|
|
|
|
|
|
|
|
// region Convenience
|
|
|
|
// region Convenience
|
|
|
|
private val userHexEncodedPublicKey = MessagingConfiguration.shared.storage.getUserPublicKey() ?: ""
|
|
|
|
private val userHexEncodedPublicKey = MessagingConfiguration.shared.storage.getUserPublicKey() ?: ""
|
|
|
|
private var displayNameUpdatees = setOf<String>()
|
|
|
|
private var displayNameUpdates = setOf<String>()
|
|
|
|
// endregion
|
|
|
|
// endregion
|
|
|
|
|
|
|
|
|
|
|
|
// region Tasks
|
|
|
|
// region Tasks
|
|
|
|
private val pollForNewMessagesTask = object : Runnable {
|
|
|
|
private val pollForNewMessagesTask = Runnable { pollForNewMessages() }
|
|
|
|
|
|
|
|
private val pollForDeletedMessagesTask = Runnable { pollForDeletedMessages() }
|
|
|
|
override fun run() {
|
|
|
|
private val pollForModeratorsTask = Runnable { pollForModerators() }
|
|
|
|
pollForNewMessages()
|
|
|
|
private val pollForDisplayNamesTask = Runnable { pollForDisplayNames() }
|
|
|
|
handler.postDelayed(this, pollForNewMessagesInterval)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private val pollForDeletedMessagesTask = object : Runnable {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun run() {
|
|
|
|
|
|
|
|
pollForDeletedMessages()
|
|
|
|
|
|
|
|
handler.postDelayed(this, pollForDeletedMessagesInterval)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private val pollForModeratorsTask = object : Runnable {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun run() {
|
|
|
|
|
|
|
|
pollForModerators()
|
|
|
|
|
|
|
|
handler.postDelayed(this, pollForModeratorsInterval)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private val pollForDisplayNamesTask = object : Runnable {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun run() {
|
|
|
|
|
|
|
|
pollForDisplayNames()
|
|
|
|
|
|
|
|
handler.postDelayed(this, pollForDisplayNamesInterval)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// endregion
|
|
|
|
// endregion
|
|
|
|
|
|
|
|
|
|
|
|
// region Settings
|
|
|
|
// region Settings
|
|
|
|
companion object {
|
|
|
|
companion object {
|
|
|
|
private val pollForNewMessagesInterval: Long = 4 * 1000
|
|
|
|
private val pollForNewMessagesInterval: Long = 10 * 1000
|
|
|
|
private val pollForDeletedMessagesInterval: Long = 60 * 1000
|
|
|
|
private val pollForDeletedMessagesInterval: Long = 60 * 1000
|
|
|
|
private val pollForModeratorsInterval: Long = 10 * 60 * 1000
|
|
|
|
private val pollForModeratorsInterval: Long = 10 * 60 * 1000
|
|
|
|
private val pollForDisplayNamesInterval: Long = 60 * 1000
|
|
|
|
private val pollForDisplayNamesInterval: Long = 60 * 1000
|
|
|
@ -74,19 +48,21 @@ class OpenGroupPoller(private val openGroup: OpenGroup) {
|
|
|
|
|
|
|
|
|
|
|
|
// region Lifecycle
|
|
|
|
// region Lifecycle
|
|
|
|
fun startIfNeeded() {
|
|
|
|
fun startIfNeeded() {
|
|
|
|
if (hasStarted) return
|
|
|
|
if (hasStarted || executorService == null) return
|
|
|
|
pollForNewMessagesTask.run()
|
|
|
|
cancellableFutures += listOf(
|
|
|
|
pollForDeletedMessagesTask.run()
|
|
|
|
executorService.scheduleAtFixedRate(pollForNewMessagesTask,0, pollForNewMessagesInterval, TimeUnit.MILLISECONDS),
|
|
|
|
pollForModeratorsTask.run()
|
|
|
|
executorService.scheduleAtFixedRate(pollForDeletedMessagesTask,0, pollForDeletedMessagesInterval, TimeUnit.MILLISECONDS),
|
|
|
|
pollForDisplayNamesTask.run()
|
|
|
|
executorService.scheduleAtFixedRate(pollForModeratorsTask,0, pollForModeratorsInterval, TimeUnit.MILLISECONDS),
|
|
|
|
|
|
|
|
executorService.scheduleAtFixedRate(pollForDisplayNamesTask,0, pollForDisplayNamesInterval, TimeUnit.MILLISECONDS)
|
|
|
|
|
|
|
|
)
|
|
|
|
hasStarted = true
|
|
|
|
hasStarted = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fun stop() {
|
|
|
|
fun stop() {
|
|
|
|
handler.removeCallbacks(pollForNewMessagesTask)
|
|
|
|
cancellableFutures.forEach { future ->
|
|
|
|
handler.removeCallbacks(pollForDeletedMessagesTask)
|
|
|
|
future.cancel(false)
|
|
|
|
handler.removeCallbacks(pollForModeratorsTask)
|
|
|
|
}
|
|
|
|
handler.removeCallbacks(pollForDisplayNamesTask)
|
|
|
|
cancellableFutures.clear()
|
|
|
|
hasStarted = false
|
|
|
|
hasStarted = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// endregion
|
|
|
|
// endregion
|
|
|
@ -96,120 +72,127 @@ class OpenGroupPoller(private val openGroup: OpenGroup) {
|
|
|
|
return pollForNewMessages(false)
|
|
|
|
return pollForNewMessages(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fun pollForNewMessages(isBackgroundPoll: Boolean): Promise<Unit, Exception> {
|
|
|
|
private fun pollForNewMessages(isBackgroundPoll: Boolean): Promise<Unit, Exception> {
|
|
|
|
if (isPollOngoing) { return Promise.of(Unit) }
|
|
|
|
if (isPollOngoing) { return Promise.of(Unit) }
|
|
|
|
isPollOngoing = true
|
|
|
|
isPollOngoing = true
|
|
|
|
val deferred = deferred<Unit, Exception>()
|
|
|
|
val deferred = deferred<Unit, Exception>()
|
|
|
|
// Kovenant propagates a context to chained promises, so OpenGroupAPI.sharedContext should be used for all of the below
|
|
|
|
// Kovenant propagates a context to chained promises, so OpenGroupAPI.sharedContext should be used for all of the below
|
|
|
|
OpenGroupAPI.getMessages(openGroup.channel, openGroup.server).successBackground { messages ->
|
|
|
|
OpenGroupAPI.getMessages(openGroup.channel, openGroup.server).successBackground { messages ->
|
|
|
|
// Process messages in the background
|
|
|
|
// Process messages in the background
|
|
|
|
|
|
|
|
Log.d("Loki", "received ${messages.size} messages")
|
|
|
|
messages.forEach { message ->
|
|
|
|
messages.forEach { message ->
|
|
|
|
val senderPublicKey = message.senderPublicKey
|
|
|
|
try {
|
|
|
|
val wasSentByCurrentUser = (senderPublicKey == userHexEncodedPublicKey)
|
|
|
|
val senderPublicKey = message.senderPublicKey
|
|
|
|
fun generateDisplayName(rawDisplayName: String): String {
|
|
|
|
fun generateDisplayName(rawDisplayName: String): String {
|
|
|
|
return "${rawDisplayName} (${senderPublicKey.takeLast(8)})"
|
|
|
|
return "${rawDisplayName} (${senderPublicKey.takeLast(8)})"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val senderDisplayName = MessagingConfiguration.shared.storage.getOpenGroupDisplayName(senderPublicKey, openGroup.channel, openGroup.server) ?: generateDisplayName("Anonymous")
|
|
|
|
val senderDisplayName = MessagingConfiguration.shared.storage.getOpenGroupDisplayName(senderPublicKey, openGroup.channel, openGroup.server) ?: generateDisplayName("Anonymous")
|
|
|
|
val id = openGroup.id.toByteArray()
|
|
|
|
val id = openGroup.id.toByteArray()
|
|
|
|
// Main message
|
|
|
|
// Main message
|
|
|
|
val dataMessageProto = DataMessage.newBuilder()
|
|
|
|
val dataMessageProto = DataMessage.newBuilder()
|
|
|
|
val body = if (message.body == message.timestamp.toString()) { "" } else { message.body }
|
|
|
|
val body = if (message.body == message.timestamp.toString()) { "" } else { message.body }
|
|
|
|
dataMessageProto.setBody(body)
|
|
|
|
dataMessageProto.setBody(body)
|
|
|
|
dataMessageProto.setTimestamp(message.timestamp)
|
|
|
|
dataMessageProto.setTimestamp(message.timestamp)
|
|
|
|
// Attachments
|
|
|
|
// Attachments
|
|
|
|
val attachmentProtos = message.attachments.mapNotNull { attachment ->
|
|
|
|
val attachmentProtos = message.attachments.mapNotNull { attachment ->
|
|
|
|
if (attachment.kind != OpenGroupMessage.Attachment.Kind.Attachment) { return@mapNotNull null }
|
|
|
|
try {
|
|
|
|
val attachmentProto = AttachmentPointer.newBuilder()
|
|
|
|
if (attachment.kind != OpenGroupMessage.Attachment.Kind.Attachment) { return@mapNotNull null }
|
|
|
|
attachmentProto.setId(attachment.serverID)
|
|
|
|
val attachmentProto = AttachmentPointer.newBuilder()
|
|
|
|
attachmentProto.setContentType(attachment.contentType)
|
|
|
|
attachmentProto.setId(attachment.serverID)
|
|
|
|
attachmentProto.setSize(attachment.size)
|
|
|
|
attachmentProto.setContentType(attachment.contentType)
|
|
|
|
attachmentProto.setFileName(attachment.fileName)
|
|
|
|
attachmentProto.setSize(attachment.size)
|
|
|
|
attachmentProto.setFlags(attachment.flags)
|
|
|
|
attachmentProto.setFileName(attachment.fileName)
|
|
|
|
attachmentProto.setWidth(attachment.width)
|
|
|
|
attachmentProto.setFlags(attachment.flags)
|
|
|
|
attachmentProto.setHeight(attachment.height)
|
|
|
|
attachmentProto.setWidth(attachment.width)
|
|
|
|
attachment.caption.let { attachmentProto.setCaption(it) }
|
|
|
|
attachmentProto.setHeight(attachment.height)
|
|
|
|
attachmentProto.setUrl(attachment.url)
|
|
|
|
attachment.caption?.let { attachmentProto.setCaption(it) }
|
|
|
|
attachmentProto.build()
|
|
|
|
attachmentProto.setUrl(attachment.url)
|
|
|
|
}
|
|
|
|
attachmentProto.build()
|
|
|
|
dataMessageProto.addAllAttachments(attachmentProtos)
|
|
|
|
} catch (e: Exception) {
|
|
|
|
// Link preview
|
|
|
|
Log.e("Loki","Failed to parse attachment as proto",e)
|
|
|
|
val linkPreview = message.attachments.firstOrNull { it.kind == OpenGroupMessage.Attachment.Kind.LinkPreview }
|
|
|
|
null
|
|
|
|
if (linkPreview != null) {
|
|
|
|
}
|
|
|
|
val linkPreviewProto = DataMessage.Preview.newBuilder()
|
|
|
|
}
|
|
|
|
linkPreviewProto.setUrl(linkPreview.linkPreviewURL!!)
|
|
|
|
dataMessageProto.addAllAttachments(attachmentProtos)
|
|
|
|
linkPreviewProto.setTitle(linkPreview.linkPreviewTitle!!)
|
|
|
|
// Link preview
|
|
|
|
val attachmentProto = AttachmentPointer.newBuilder()
|
|
|
|
val linkPreview = message.attachments.firstOrNull { it.kind == OpenGroupMessage.Attachment.Kind.LinkPreview }
|
|
|
|
attachmentProto.setId(linkPreview.serverID)
|
|
|
|
if (linkPreview != null) {
|
|
|
|
attachmentProto.setContentType(linkPreview.contentType)
|
|
|
|
val linkPreviewProto = DataMessage.Preview.newBuilder()
|
|
|
|
attachmentProto.setSize(linkPreview.size)
|
|
|
|
linkPreviewProto.setUrl(linkPreview.linkPreviewURL!!)
|
|
|
|
attachmentProto.setFileName(linkPreview.fileName)
|
|
|
|
linkPreviewProto.setTitle(linkPreview.linkPreviewTitle!!)
|
|
|
|
attachmentProto.setFlags(linkPreview.flags)
|
|
|
|
val attachmentProto = AttachmentPointer.newBuilder()
|
|
|
|
attachmentProto.setWidth(linkPreview.width)
|
|
|
|
attachmentProto.setId(linkPreview.serverID)
|
|
|
|
attachmentProto.setHeight(linkPreview.height)
|
|
|
|
attachmentProto.setContentType(linkPreview.contentType)
|
|
|
|
linkPreview.caption.let { attachmentProto.setCaption(it) }
|
|
|
|
attachmentProto.setSize(linkPreview.size)
|
|
|
|
attachmentProto.setUrl(linkPreview.url)
|
|
|
|
attachmentProto.setFileName(linkPreview.fileName)
|
|
|
|
linkPreviewProto.setImage(attachmentProto.build())
|
|
|
|
attachmentProto.setFlags(linkPreview.flags)
|
|
|
|
dataMessageProto.addPreview(linkPreviewProto.build())
|
|
|
|
attachmentProto.setWidth(linkPreview.width)
|
|
|
|
}
|
|
|
|
attachmentProto.setHeight(linkPreview.height)
|
|
|
|
// Quote
|
|
|
|
linkPreview.caption?.let { attachmentProto.setCaption(it) }
|
|
|
|
val quote = message.quote
|
|
|
|
attachmentProto.setUrl(linkPreview.url)
|
|
|
|
if (quote != null) {
|
|
|
|
linkPreviewProto.setImage(attachmentProto.build())
|
|
|
|
val quoteProto = DataMessage.Quote.newBuilder()
|
|
|
|
dataMessageProto.addPreview(linkPreviewProto.build())
|
|
|
|
quoteProto.setId(quote.quotedMessageTimestamp)
|
|
|
|
}
|
|
|
|
quoteProto.setAuthor(quote.quoteePublicKey)
|
|
|
|
// Quote
|
|
|
|
if (quote.quotedMessageBody != quote.quotedMessageTimestamp.toString()) { quoteProto.setText(quote.quotedMessageBody) }
|
|
|
|
val quote = message.quote
|
|
|
|
dataMessageProto.setQuote(quoteProto.build())
|
|
|
|
if (quote != null) {
|
|
|
|
}
|
|
|
|
val quoteProto = DataMessage.Quote.newBuilder()
|
|
|
|
val messageServerID = message.serverID
|
|
|
|
quoteProto.setId(quote.quotedMessageTimestamp)
|
|
|
|
// Profile
|
|
|
|
quoteProto.setAuthor(quote.quoteePublicKey)
|
|
|
|
val profileProto = DataMessage.LokiProfile.newBuilder()
|
|
|
|
if (quote.quotedMessageBody != quote.quotedMessageTimestamp.toString()) { quoteProto.setText(quote.quotedMessageBody) }
|
|
|
|
profileProto.setDisplayName(message.displayName)
|
|
|
|
dataMessageProto.setQuote(quoteProto.build())
|
|
|
|
val profilePicture = message.profilePicture
|
|
|
|
}
|
|
|
|
if (profilePicture != null) {
|
|
|
|
val messageServerID = message.serverID
|
|
|
|
profileProto.setProfilePicture(profilePicture.url)
|
|
|
|
// Profile
|
|
|
|
dataMessageProto.setProfileKey(ByteString.copyFrom(profilePicture.profileKey))
|
|
|
|
val profileProto = DataMessage.LokiProfile.newBuilder()
|
|
|
|
}
|
|
|
|
profileProto.setDisplayName(message.displayName)
|
|
|
|
dataMessageProto.setProfile(profileProto.build())
|
|
|
|
val profilePicture = message.profilePicture
|
|
|
|
/* TODO: the signal service proto needs to be synced with iOS
|
|
|
|
if (profilePicture != null) {
|
|
|
|
// Open group info
|
|
|
|
profileProto.setProfilePicture(profilePicture.url)
|
|
|
|
if (messageServerID != null) {
|
|
|
|
dataMessageProto.setProfileKey(ByteString.copyFrom(profilePicture.profileKey))
|
|
|
|
val openGroupProto = PublicChatInfo.newBuilder()
|
|
|
|
}
|
|
|
|
openGroupProto.setServerID(messageServerID)
|
|
|
|
dataMessageProto.setProfile(profileProto.build())
|
|
|
|
dataMessageProto.setPublicChatInfo(openGroupProto.build())
|
|
|
|
/* TODO: the signal service proto needs to be synced with iOS
|
|
|
|
}
|
|
|
|
// Open group info
|
|
|
|
*/
|
|
|
|
if (messageServerID != null) {
|
|
|
|
// Signal group context
|
|
|
|
val openGroupProto = PublicChatInfo.newBuilder()
|
|
|
|
val groupProto = GroupContext.newBuilder()
|
|
|
|
openGroupProto.setServerID(messageServerID)
|
|
|
|
groupProto.setId(ByteString.copyFrom(id))
|
|
|
|
dataMessageProto.setPublicChatInfo(openGroupProto.build())
|
|
|
|
groupProto.setType(GroupContext.Type.DELIVER)
|
|
|
|
}
|
|
|
|
groupProto.setName(openGroup.displayName)
|
|
|
|
*/
|
|
|
|
dataMessageProto.setGroup(groupProto.build())
|
|
|
|
// Signal group context
|
|
|
|
// Sync target
|
|
|
|
val groupProto = GroupContext.newBuilder()
|
|
|
|
if (wasSentByCurrentUser) {
|
|
|
|
groupProto.setId(ByteString.copyFrom(id))
|
|
|
|
dataMessageProto.setSyncTarget(openGroup.id)
|
|
|
|
groupProto.setType(GroupContext.Type.DELIVER)
|
|
|
|
}
|
|
|
|
groupProto.setName(openGroup.displayName)
|
|
|
|
// Content
|
|
|
|
dataMessageProto.setGroup(groupProto.build())
|
|
|
|
val content = Content.newBuilder()
|
|
|
|
// Content
|
|
|
|
content.setDataMessage(dataMessageProto.build())
|
|
|
|
val content = Content.newBuilder()
|
|
|
|
// Envelope
|
|
|
|
content.setDataMessage(dataMessageProto.build())
|
|
|
|
val builder = Envelope.newBuilder()
|
|
|
|
// Envelope
|
|
|
|
builder.type = Envelope.Type.UNIDENTIFIED_SENDER
|
|
|
|
val builder = Envelope.newBuilder()
|
|
|
|
builder.source = senderPublicKey
|
|
|
|
builder.type = Envelope.Type.UNIDENTIFIED_SENDER
|
|
|
|
builder.sourceDevice = 1
|
|
|
|
builder.source = senderPublicKey
|
|
|
|
builder.setContent(content.build().toByteString())
|
|
|
|
builder.sourceDevice = 1
|
|
|
|
builder.serverTimestamp = message.serverTimestamp
|
|
|
|
builder.setContent(content.build().toByteString())
|
|
|
|
val envelope = builder.build()
|
|
|
|
builder.timestamp = message.timestamp
|
|
|
|
val job = MessageReceiveJob(envelope.toByteArray(), isBackgroundPoll, messageServerID, openGroup.id)
|
|
|
|
builder.serverTimestamp = message.serverTimestamp
|
|
|
|
if (isBackgroundPoll) {
|
|
|
|
val envelope = builder.build()
|
|
|
|
job.executeAsync().success { deferred.resolve(Unit) }.fail { deferred.resolve(Unit) }
|
|
|
|
val job = MessageReceiveJob(envelope.toByteArray(), isBackgroundPoll, messageServerID, openGroup.id)
|
|
|
|
// The promise is just used to keep track of when we're done
|
|
|
|
Log.d("Loki", "Scheduling Job $job")
|
|
|
|
} else {
|
|
|
|
if (isBackgroundPoll) {
|
|
|
|
JobQueue.shared.add(job)
|
|
|
|
job.executeAsync().always { deferred.resolve(Unit) }
|
|
|
|
deferred.resolve(Unit)
|
|
|
|
// The promise is just used to keep track of when we're done
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
JobQueue.shared.add(job)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
|
|
|
Log.e("Loki", "Exception parsing message", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
isCaughtUp = true
|
|
|
|
isCaughtUp = true
|
|
|
|
isPollOngoing = false
|
|
|
|
isPollOngoing = false
|
|
|
|
|
|
|
|
deferred.resolve(Unit)
|
|
|
|
}.fail {
|
|
|
|
}.fail {
|
|
|
|
Log.d("Loki", "Failed to get messages for group chat with ID: ${openGroup.channel} on server: ${openGroup.server}.")
|
|
|
|
Log.d("Loki", "Failed to get messages for group chat with ID: ${openGroup.channel} on server: ${openGroup.server}.")
|
|
|
|
isPollOngoing = false
|
|
|
|
isPollOngoing = false
|
|
|
@ -218,16 +201,16 @@ class OpenGroupPoller(private val openGroup: OpenGroup) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun pollForDisplayNames() {
|
|
|
|
private fun pollForDisplayNames() {
|
|
|
|
if (displayNameUpdatees.isEmpty()) { return }
|
|
|
|
if (displayNameUpdates.isEmpty()) { return }
|
|
|
|
val hexEncodedPublicKeys = displayNameUpdatees
|
|
|
|
val hexEncodedPublicKeys = displayNameUpdates
|
|
|
|
displayNameUpdatees = setOf()
|
|
|
|
displayNameUpdates = setOf()
|
|
|
|
OpenGroupAPI.getDisplayNames(hexEncodedPublicKeys, openGroup.server).successBackground { mapping ->
|
|
|
|
OpenGroupAPI.getDisplayNames(hexEncodedPublicKeys, openGroup.server).successBackground { mapping ->
|
|
|
|
for (pair in mapping.entries) {
|
|
|
|
for (pair in mapping.entries) {
|
|
|
|
val senderDisplayName = "${pair.value} (...${pair.key.takeLast(8)})"
|
|
|
|
val senderDisplayName = "${pair.value} (...${pair.key.takeLast(8)})"
|
|
|
|
MessagingConfiguration.shared.storage.setOpenGroupDisplayName(pair.key, openGroup.channel, openGroup.server, senderDisplayName)
|
|
|
|
MessagingConfiguration.shared.storage.setOpenGroupDisplayName(pair.key, openGroup.channel, openGroup.server, senderDisplayName)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.fail {
|
|
|
|
}.fail {
|
|
|
|
displayNameUpdatees = displayNameUpdatees.union(hexEncodedPublicKeys)
|
|
|
|
displayNameUpdates = displayNameUpdates.union(hexEncodedPublicKeys)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|