Start expiration at end of handling each message type treating call and extraction as DaR

This commit is contained in:
Andrew 2024-01-23 09:09:16 +10:00
parent e2e5a36f51
commit 848dbd2eb0
8 changed files with 42 additions and 42 deletions

View File

@ -37,7 +37,7 @@ class DisappearingMessages @Inject constructor(
sentTimestamp = expiryChangeTimestampMs sentTimestamp = expiryChangeTimestampMs
} }
messageExpirationManager.setExpirationTimer(message) messageExpirationManager.insertExpirationTimerMessage(message)
MessageSender.send(message, address) MessageSender.send(message, address)
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context) ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context)
} }

View File

@ -19,9 +19,6 @@ import kotlinx.coroutines.launch
import network.loki.messenger.BuildConfig import network.loki.messenger.BuildConfig
import network.loki.messenger.libsession_util.util.ExpiryMode import network.loki.messenger.libsession_util.util.ExpiryMode
import org.session.libsession.messaging.messages.ExpirationConfiguration import org.session.libsession.messaging.messages.ExpirationConfiguration
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.SSKEnvironment.MessageExpirationManagerProtocol import org.session.libsession.utilities.SSKEnvironment.MessageExpirationManagerProtocol
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.ExpiryCallbacks import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.ExpiryCallbacks
@ -30,13 +27,13 @@ import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.toUiState
import org.thoughtcrime.securesms.database.GroupDatabase import org.thoughtcrime.securesms.database.GroupDatabase
import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.database.ThreadDatabase import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
class DisappearingMessagesViewModel( class DisappearingMessagesViewModel(
private val threadId: Long, private val threadId: Long,
private val application: Application, private val application: Application,
private val textSecurePreferences: TextSecurePreferences, private val textSecurePreferences: TextSecurePreferences,
private val messageExpirationManager: MessageExpirationManagerProtocol, private val messageExpirationManager: MessageExpirationManagerProtocol,
private val disappearingMessages: DisappearingMessages,
private val threadDb: ThreadDatabase, private val threadDb: ThreadDatabase,
private val groupDb: GroupDatabase, private val groupDb: GroupDatabase,
private val storage: Storage, private val storage: Storage,
@ -90,20 +87,7 @@ class DisappearingMessagesViewModel(
return@launch return@launch
} }
val expiryChangeTimestampMs = SnodeAPI.nowWithOffset disappearingMessages.set(threadId, address, mode)
storage.setExpirationConfiguration(ExpirationConfiguration(threadId, mode, expiryChangeTimestampMs))
val message = ExpirationTimerUpdate().apply {
expiryMode = mode
sender = textSecurePreferences.getLocalNumber()
isSenderSelf = true
recipient = address.serialize()
sentTimestamp = expiryChangeTimestampMs
}
messageExpirationManager.setExpirationTimer(message)
MessageSender.send(message, address)
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(application)
_event.send(Event.SUCCESS) _event.send(Event.SUCCESS)
} }
@ -121,6 +105,7 @@ class DisappearingMessagesViewModel(
private val application: Application, private val application: Application,
private val textSecurePreferences: TextSecurePreferences, private val textSecurePreferences: TextSecurePreferences,
private val messageExpirationManager: MessageExpirationManagerProtocol, private val messageExpirationManager: MessageExpirationManagerProtocol,
private val disappearingMessages: DisappearingMessages,
private val threadDb: ThreadDatabase, private val threadDb: ThreadDatabase,
private val groupDb: GroupDatabase, private val groupDb: GroupDatabase,
private val storage: Storage private val storage: Storage
@ -131,6 +116,7 @@ class DisappearingMessagesViewModel(
application, application,
textSecurePreferences, textSecurePreferences,
messageExpirationManager, messageExpirationManager,
disappearingMessages,
threadDb, threadDb,
groupDb, groupDb,
storage, storage,

View File

@ -253,6 +253,8 @@ public class SmsDatabase extends MessagingDatabase {
@Override @Override
public void markExpireStarted(long id, long startedAtTimestamp) { public void markExpireStarted(long id, long startedAtTimestamp) {
Log.d(TAG, "markExpireStarted() called with: id = [" + id + "], startedAtTimestamp = [" + startedAtTimestamp + "]");
ContentValues contentValues = new ContentValues(); ContentValues contentValues = new ContentValues();
contentValues.put(EXPIRE_STARTED, startedAtTimestamp); contentValues.put(EXPIRE_STARTED, startedAtTimestamp);

View File

@ -56,10 +56,10 @@ class MarkReadReceiver : BroadcastReceiver() {
context: Context, context: Context,
markedReadMessages: List<MarkedMessageInfo> markedReadMessages: List<MarkedMessageInfo>
) { ) {
if (markedReadMessages.isEmpty()) return
Log.d(TAG, "process() called with: markedReadMessages = $markedReadMessages") Log.d(TAG, "process() called with: markedReadMessages = $markedReadMessages")
if (markedReadMessages.isEmpty()) return
sendReadReceipts(context, markedReadMessages) sendReadReceipts(context, markedReadMessages)
markedReadMessages.forEach { scheduleDeletion(context, it.expirationInfo) } markedReadMessages.forEach { scheduleDeletion(context, it.expirationInfo) }

View File

@ -8,7 +8,6 @@ import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
import org.session.libsession.messaging.messages.signal.IncomingMediaMessage import org.session.libsession.messaging.messages.signal.IncomingMediaMessage
import org.session.libsession.messaging.messages.signal.OutgoingExpirationUpdateMessage import org.session.libsession.messaging.messages.signal.OutgoingExpirationUpdateMessage
import org.session.libsession.snode.SnodeAPI.nowWithOffset import org.session.libsession.snode.SnodeAPI.nowWithOffset
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Address.Companion.fromSerialized import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.GroupUtil.doubleEncodeGroupID import org.session.libsession.utilities.GroupUtil.doubleEncodeGroupID
import org.session.libsession.utilities.GroupUtil.getDecodedGroupIDAsData import org.session.libsession.utilities.GroupUtil.getDecodedGroupIDAsData
@ -21,7 +20,6 @@ import org.session.libsignal.utilities.guava.Optional
import org.thoughtcrime.securesms.database.MmsDatabase import org.thoughtcrime.securesms.database.MmsDatabase
import org.thoughtcrime.securesms.database.MmsSmsDatabase import org.thoughtcrime.securesms.database.MmsSmsDatabase
import org.thoughtcrime.securesms.database.SmsDatabase import org.thoughtcrime.securesms.database.SmsDatabase
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get
import org.thoughtcrime.securesms.mms.MmsException import org.thoughtcrime.securesms.mms.MmsException
import java.io.IOException import java.io.IOException
@ -149,15 +147,14 @@ class ExpiringMessageManager(context: Context) : MessageExpirationManagerProtoco
} }
} }
override fun setExpirationTimer(message: ExpirationTimerUpdate) { override fun insertExpirationTimerMessage(message: ExpirationTimerUpdate) {
val expiryMode: ExpiryMode = message.expiryMode val expiryMode: ExpiryMode = message.expiryMode
Log.d(TAG, "setExpirationTimer() called with: message = $message, expiryMode = $expiryMode") Log.d(TAG, "setExpirationTimer() called with: message = $message, expiryMode = $expiryMode")
val userPublicKey = getLocalNumber(context) val userPublicKey = getLocalNumber(context)
val senderPublicKey = message.sender val senderPublicKey = message.sender
val sentTimestamp = if (message.sentTimestamp == null) 0 else message.sentTimestamp!! val sentTimestamp = if (message.sentTimestamp == null) 0 else message.sentTimestamp!!
val expireStartedAt = val expireStartedAt = if (expiryMode is AfterSend || message.isSenderSelf) sentTimestamp else 0
if (expiryMode is AfterSend || message.isSenderSelf) sentTimestamp else 0
// Notify the user // Notify the user
if (senderPublicKey == null || userPublicKey == senderPublicKey) { if (senderPublicKey == null || userPublicKey == senderPublicKey) {
@ -167,14 +164,13 @@ class ExpiringMessageManager(context: Context) : MessageExpirationManagerProtoco
insertIncomingExpirationTimerMessage(message, expireStartedAt) insertIncomingExpirationTimerMessage(message, expireStartedAt)
} }
if (expiryMode is AfterSend && expiryMode.expirySeconds > 0 && message.sentTimestamp != null && senderPublicKey != null) { startAnyExpiration(message)
startAnyExpiration(message.sentTimestamp!!, senderPublicKey, expireStartedAt)
}
} }
override fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long) { override fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long) {
Log.d(TAG, "startAnyExpiration() called with: timestamp = $timestamp, author = $author, expireStartedAt = $expireStartedAt") Log.d(TAG, "startAnyExpiration() called with: timestamp = $timestamp, author = $author, expireStartedAt = $expireStartedAt")
val messageRecord = mmsSmsDatabase.getMessageFor(timestamp, author) ?: return val messageRecord = mmsSmsDatabase.getMessageFor(timestamp, author) ?: throw Exception("no message record!!!")
Log.d(TAG, "startAnyExpiration() $messageRecord")
val mms = messageRecord.isMms() val mms = messageRecord.isMms()
getDatabase(mms).markExpireStarted(messageRecord.getId(), expireStartedAt) getDatabase(mms).markExpireStarted(messageRecord.getId(), expireStartedAt)
scheduleDeletion(messageRecord.getId(), mms, expireStartedAt, messageRecord.expiresIn) scheduleDeletion(messageRecord.getId(), mms, expireStartedAt, messageRecord.expiresIn)

View File

@ -421,9 +421,10 @@ object MessageSender {
storage.markUnidentified(timestamp, userPublicKey) storage.markUnidentified(timestamp, userPublicKey)
// Start the disappearing messages timer if needed // Start the disappearing messages timer if needed
Log.d("MessageSender", "Start the disappearing messages timer if needed message.recipient = ${message.recipient}, userPublicKey = $userPublicKey, isSyncMessage = $isSyncMessage") Log.d("MessageSender", "Start the disappearing messages timer if needed message.recipient = ${message.recipient}, userPublicKey = $userPublicKey, isSyncMessage = $isSyncMessage")
message.threadID?.let(storage::getExpirationConfiguration)?.takeIf { it.expiryMode.expirySeconds > 0 }?.let { config -> message.threadID?.let(storage::getExpirationConfiguration)?.expiryMode?.takeIf { it.expirySeconds > 0 }?.let { mode ->
if (message.recipient == userPublicKey || !isSyncMessage) { if (message.recipient == userPublicKey || !isSyncMessage) {
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(timestamp, userPublicKey, timestamp) val expireStartedAt = if (mode is ExpiryMode.AfterRead) timestamp + 1 else timestamp
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(timestamp, userPublicKey, expireStartedAt)
} }
} }
} ?: run { } ?: run {

View File

@ -65,6 +65,8 @@ internal fun MessageReceiver.isBlocked(publicKey: String): Boolean {
} }
fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content, threadId: Long, openGroupID: String?) { fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content, threadId: Long, openGroupID: String?) {
Log.d("MessageReceiver", "handle() called with: message = $message, proto = $proto, threadId = $threadId, openGroupID = $openGroupID")
// Do nothing if the message was outdated // Do nothing if the message was outdated
if (MessageReceiver.messageIsOutdated(message, threadId, openGroupID)) { return } if (MessageReceiver.messageIsOutdated(message, threadId, openGroupID)) { return }
@ -122,6 +124,7 @@ private fun MessageReceiver.handleReadReceipt(message: ReadReceipt) {
private fun MessageReceiver.handleCallMessage(message: CallMessage) { private fun MessageReceiver.handleCallMessage(message: CallMessage) {
// TODO: refactor this out to persistence, just to help debug the flow and send/receive in synchronous testing // TODO: refactor this out to persistence, just to help debug the flow and send/receive in synchronous testing
WebRtcUtils.SIGNAL_QUEUE.trySend(message) WebRtcUtils.SIGNAL_QUEUE.trySend(message)
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message, coerceToDisappearAfterRead = true)
} }
private fun MessageReceiver.handleTypingIndicator(message: TypingIndicator) { private fun MessageReceiver.handleTypingIndicator(message: TypingIndicator) {
@ -153,7 +156,7 @@ fun MessageReceiver.cancelTypingIndicatorsIfNeeded(senderPublicKey: String) {
} }
private fun MessageReceiver.handleExpirationTimerUpdate(message: ExpirationTimerUpdate) { private fun MessageReceiver.handleExpirationTimerUpdate(message: ExpirationTimerUpdate) {
SSKEnvironment.shared.messageExpirationManager.setExpirationTimer(message) SSKEnvironment.shared.messageExpirationManager.insertExpirationTimerMessage(message)
if (isNewConfigEnabled) return if (isNewConfigEnabled) return
@ -186,6 +189,7 @@ private fun MessageReceiver.handleDataExtractionNotification(message: DataExtrac
else -> return else -> return
} }
storage.insertDataExtractionNotificationMessage(senderPublicKey, notification, message.sentTimestamp!!) storage.insertDataExtractionNotificationMessage(senderPublicKey, notification, message.sentTimestamp!!)
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message, coerceToDisappearAfterRead = true)
} }
private fun handleConfigurationMessage(message: ConfigurationMessage) { private fun handleConfigurationMessage(message: ConfigurationMessage) {
@ -285,6 +289,8 @@ fun MessageReceiver.handleVisibleMessage(
runThreadUpdate: Boolean, runThreadUpdate: Boolean,
runProfileUpdate: Boolean runProfileUpdate: Boolean
): Long? { ): Long? {
Log.d("ReceivedMessageHandler", "handleVisibleMessage() called with: message = $message, proto = $proto, openGroupID = $openGroupID, threadId = $threadId, runThreadUpdate = $runThreadUpdate, runProfileUpdate = $runProfileUpdate")
val storage = MessagingModuleConfiguration.shared.storage val storage = MessagingModuleConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context val context = MessagingModuleConfiguration.shared.context
val userPublicKey = storage.getUserPublicKey() val userPublicKey = storage.getUserPublicKey()
@ -386,14 +392,7 @@ fun MessageReceiver.handleVisibleMessage(
} }
} }
// Parse attachments if needed // Parse attachments if needed
val attachments = proto.dataMessage.attachmentsList.mapNotNull { attachmentProto -> val attachments = proto.dataMessage.attachmentsList.map(Attachment::fromProto).filter { it.isValid() }
val attachment = Attachment.fromProto(attachmentProto)
if (!attachment.isValid()) {
return@mapNotNull null
} else {
return@mapNotNull attachment
}
}
// Cancel any typing indicators if needed // Cancel any typing indicators if needed
cancelTypingIndicatorsIfNeeded(message.sender!!) cancelTypingIndicatorsIfNeeded(message.sender!!)
// Parse reaction if needed // Parse reaction if needed
@ -429,6 +428,7 @@ fun MessageReceiver.handleVisibleMessage(
val isSms = !message.isMediaMessage() && attachments.isEmpty() val isSms = !message.isMediaMessage() && attachments.isEmpty()
storage.setOpenGroupServerMessageID(messageID, it, threadID, isSms) storage.setOpenGroupServerMessageID(messageID, it, threadID, isSms)
} }
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message)
return messageID return messageID
} }
return null return null

View File

@ -1,10 +1,13 @@
package org.session.libsession.utilities package org.session.libsession.utilities
import android.content.Context import android.content.Context
import android.util.Log
import network.loki.messenger.libsession_util.util.ExpiryMode import network.loki.messenger.libsession_util.util.ExpiryMode
import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.Recipient
class SSKEnvironment( class SSKEnvironment(
@ -38,8 +41,20 @@ class SSKEnvironment(
} }
interface MessageExpirationManagerProtocol { interface MessageExpirationManagerProtocol {
fun setExpirationTimer(message: ExpirationTimerUpdate) fun insertExpirationTimerMessage(message: ExpirationTimerUpdate)
fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long) fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long)
fun startAnyExpiration(message: Message, coerceToDisappearAfterRead: Boolean = false) {
Log.d("MessageExpirationManagerProtocol", "startAnyExpiration() called with: message = $message, coerceToDisappearAfterRead = $coerceToDisappearAfterRead")
val timestamp = message.sentTimestamp ?: return
startAnyExpiration(
timestamp = timestamp,
author = message.sender ?: return,
expireStartedAt = if (message.expiryMode is ExpiryMode.AfterRead || coerceToDisappearAfterRead && message.expiryMode.expiryMillis > 0) SnodeAPI.nowWithOffset.coerceAtLeast(timestamp + 1)
else if (message.expiryMode is ExpiryMode.AfterSend) timestamp
else return
)
}
} }
companion object { companion object {