Add synced expiries job

This commit is contained in:
charles
2022-12-19 11:22:13 +11:00
parent 8a51c8882c
commit 065417ebbb
11 changed files with 151 additions and 29 deletions

View File

@@ -23,6 +23,7 @@ interface MessageDataProvider {
fun deleteMessage(messageID: Long, isSms: Boolean)
fun updateMessageAsDeleted(timestamp: Long, author: String)
fun getServerHashForMessage(messageID: Long): String?
fun getServerHashForMessages(messageIDs: List<Long>): List<Pair<Long, String?>>
fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment?
fun getAttachmentStream(attachmentId: Long): SessionServiceAttachmentStream?
fun getAttachmentPointer(attachmentId: Long): SessionServiceAttachmentPointer?

View File

@@ -201,6 +201,6 @@ interface StorageProtocol {
fun blockedContacts(): List<Recipient>
fun getExpirationConfiguration(threadId: Long): ExpirationConfiguration?
fun setExpirationConfiguration(config: ExpirationConfiguration)
fun getExpiringMessages(messageIds: LongArray): List<Pair<String, Int>>
fun getExpiringMessages(messageIds: List<Long>): List<Pair<Long, Long>>
fun updateDisappearingState(address: String, disappearingState: Recipient.DisappearingState)
}

View File

@@ -2,14 +2,13 @@ package org.session.libsession.messaging.jobs
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.ExpirationConfiguration
import org.session.libsession.messaging.messages.control.SyncedExpiriesMessage
import org.session.libsession.messaging.messages.control.SyncedExpiry
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.Data
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.Address
class DisappearingMessagesJob(val messageIds: LongArray = longArrayOf(), val startedAtMs: Long = 0): Job {
class DisappearingMessagesJob(
val messageIds: List<Long> = listOf(),
val startedAtMs: Long = 0,
val threadId: Long = 0
) : Job {
override var delegate: JobDelegate? = null
override var id: String? = null
@@ -18,20 +17,10 @@ class DisappearingMessagesJob(val messageIds: LongArray = longArrayOf(), val sta
override fun execute() {
if (!ExpirationConfiguration.isNewConfigEnabled) return
val userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey() ?: return
val module = MessagingModuleConfiguration.shared
try {
module.storage.getExpiringMessages(messageIds).groupBy { it.second }.forEach { (expiresInSeconds, messages) ->
val serverHashes = messages.map { it.first }
if (serverHashes.isEmpty()) return
val expirationTimestamp = startedAtMs + expiresInSeconds * 1000
val syncTarget = ""
val syncedExpiriesMessage = SyncedExpiriesMessage()
syncedExpiriesMessage.conversationExpiries = mapOf(
syncTarget to serverHashes.map { serverHash -> SyncedExpiry(serverHash, expirationTimestamp) }
)
MessageSender.send(syncedExpiriesMessage, Address.fromSerialized(userPublicKey))
SnodeAPI.updateExpiry(expirationTimestamp, serverHashes)
val ids = MessagingModuleConfiguration.shared.storage.getExpiringMessages(messageIds).map { it.first }
if (ids.isNotEmpty()) {
JobQueue.shared.add(SyncedExpiriesJob(ids, startedAtMs, threadId))
}
} catch (e: Exception) {
delegate?.handleJobFailed(this, e)
@@ -41,8 +30,9 @@ class DisappearingMessagesJob(val messageIds: LongArray = longArrayOf(), val sta
}
override fun serialize(): Data = Data.Builder()
.putLongArray(MESSAGE_IDS, messageIds)
.putLongArray(MESSAGE_IDS, messageIds.toLongArray())
.putLong(STARTED_AT_MS, startedAtMs)
.putLong(THREAD_ID, threadId)
.build()
override fun getFactoryKey(): String = KEY
@@ -50,8 +40,9 @@ class DisappearingMessagesJob(val messageIds: LongArray = longArrayOf(), val sta
class Factory : Job.Factory<DisappearingMessagesJob> {
override fun create(data: Data): DisappearingMessagesJob {
return DisappearingMessagesJob(
data.getLongArray(MESSAGE_IDS),
data.getLong(STARTED_AT_MS)
data.getLongArray(MESSAGE_IDS).toList(),
data.getLong(STARTED_AT_MS),
data.getLong(THREAD_ID)
)
}
}
@@ -61,6 +52,7 @@ class DisappearingMessagesJob(val messageIds: LongArray = longArrayOf(), val sta
private const val MESSAGE_IDS = "messageIds"
private const val STARTED_AT_MS = "startedAtMs"
private const val THREAD_ID = "threadId"
}
}

View File

@@ -115,7 +115,8 @@ class JobQueue : JobDelegate {
while (isActive) {
when (val job = queue.receive()) {
is NotifyPNServerJob, is AttachmentUploadJob, is MessageSendJob, is DisappearingMessagesJob -> {
is NotifyPNServerJob, is AttachmentUploadJob, is MessageSendJob, is DisappearingMessagesJob,
is SyncedExpiriesJob -> {
txQueue.send(job)
}
is AttachmentDownloadJob -> {

View File

@@ -0,0 +1,84 @@
package org.session.libsession.messaging.jobs
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.ExpirationConfiguration
import org.session.libsession.messaging.messages.control.SyncedExpiriesMessage
import org.session.libsession.messaging.messages.control.SyncedExpiry
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.Data
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.Address
class SyncedExpiriesJob(
val messageIds: List<Long> = listOf(),
val startedAtMs: Long = 0,
val threadId: Long = 0
) : Job {
override var delegate: JobDelegate? = null
override var id: String? = null
override var failureCount: Int = 0
override val maxFailureCount: Int = 1
override fun execute() {
if (!ExpirationConfiguration.isNewConfigEnabled) return
val module = MessagingModuleConfiguration.shared
val userPublicKey = module.storage.getUserPublicKey() ?: return
try {
val messageIdsWithNoServerHashByExpiresIn = mutableMapOf<Long, List<Long>>()
module.storage.getExpiringMessages(messageIds).groupBy { it.second }.forEach { (expiresInSeconds, messageIds) ->
val serverHashesByMessageIds = module.messageDataProvider.getServerHashForMessages(messageIds.map { it.first })
val messageIdsWithNoHash = serverHashesByMessageIds.filter { it.second == null }.map { it.first }
if (messageIdsWithNoHash.isNotEmpty()) {
messageIdsWithNoServerHashByExpiresIn[expiresInSeconds] = messageIdsWithNoHash
}
val serverHashes = serverHashesByMessageIds.mapNotNull { it.second }
if (serverHashes.isEmpty()) return
val expirationTimestamp = startedAtMs + expiresInSeconds * 1000
val syncTarget = ""
val syncedExpiriesMessage = SyncedExpiriesMessage()
syncedExpiriesMessage.conversationExpiries = mapOf(
syncTarget to serverHashes.map { serverHash -> SyncedExpiry(serverHash, expirationTimestamp) }
)
MessageSender.send(syncedExpiriesMessage, Address.fromSerialized(userPublicKey))
SnodeAPI.updateExpiry(expirationTimestamp, serverHashes)
}
if (messageIdsWithNoServerHashByExpiresIn.isNotEmpty()) {
JobQueue.shared.add(
SyncedExpiriesJob(messageIdsWithNoServerHashByExpiresIn.flatMap { it.value }, startedAtMs, threadId)
)
}
} catch (e: Exception) {
delegate?.handleJobFailed(this, e)
return
}
delegate?.handleJobSucceeded(this)
}
override fun serialize(): Data = Data.Builder()
.putLongArray(MESSAGE_IDS, messageIds.toLongArray())
.putLong(STARTED_AT_MS, startedAtMs)
.putLong(THREAD_ID, threadId)
.build()
override fun getFactoryKey(): String = KEY
class Factory : Job.Factory<SyncedExpiriesJob> {
override fun create(data: Data): SyncedExpiriesJob {
return SyncedExpiriesJob(
data.getLongArray(MESSAGE_IDS).toList(),
data.getLong(STARTED_AT_MS),
data.getLong(THREAD_ID)
)
}
}
companion object {
const val KEY = "DisappearingMessagesJob"
private const val MESSAGE_IDS = "messageIds"
private const val STARTED_AT_MS = "startedAtMs"
private const val THREAD_ID = "threadId"
}
}

View File

@@ -12,6 +12,6 @@ class ExpirationConfiguration(
val expirationType: ExpirationType? = ExpirationType.valueOf(expirationTypeValue)
companion object {
val isNewConfigEnabled = true//System.currentTimeMillis() > 1_674_000_000_000 // 18/01/2023
val isNewConfigEnabled = true /* TODO: System.currentTimeMillis() > 1_674_000_000_000 // 18/01/2023 */
}
}