From 5cfbb8405c5136dba9fbf9ddf1ae84a886ef5b3b Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 12 Dec 2023 17:11:00 +1100 Subject: [PATCH] fix: use expiry from swarm to update readAt & expiresAt for msg --- ts/models/message.ts | 16 +++------ ts/models/messageType.ts | 1 + ts/session/apis/snode_api/expireRequest.ts | 15 ++++----- ts/session/disappearing_messages/index.ts | 33 ++++++++++++++++--- .../jobs/FetchMsgExpirySwarmJob.ts | 29 +++++++++++++--- 5 files changed, 65 insertions(+), 29 deletions(-) diff --git a/ts/models/message.ts b/ts/models/message.ts index f18f6cc33..263b961b3 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -1157,26 +1157,18 @@ export class MessageModel extends Backbone.Model { } public isExpired() { - return this.msTilExpire() <= 0; - } - - public msTilExpire() { if (!this.isExpiring()) { - return Infinity; + return false; } const now = Date.now(); const start = this.getExpirationStartTimestamp(); if (!start) { - return Infinity; + return false; } const delta = this.getExpireTimer() * 1000; - let msFromNow = start + delta - now; - if (msFromNow < 0) { - msFromNow = 0; - } - return msFromNow; + const msFromNow = start + delta - now; + return msFromNow < 0; } - public async setToExpire() { if (this.isExpiring() && !this.getExpiresAt()) { const start = this.getExpirationStartTimestamp(); diff --git a/ts/models/messageType.ts b/ts/models/messageType.ts index 1b8e51f3e..4c4002911 100644 --- a/ts/models/messageType.ts +++ b/ts/models/messageType.ts @@ -31,6 +31,7 @@ export interface MessageAttributes { expirationType?: DisappearingMessageType; /** in seconds, 0 means no expiration */ expireTimer: number; + /** in milliseconds */ expirationStartTimestamp: number; expires_at?: number; expirationTimerUpdate?: ExpirationTimerUpdate; diff --git a/ts/session/apis/snode_api/expireRequest.ts b/ts/session/apis/snode_api/expireRequest.ts index a79979658..18594617a 100644 --- a/ts/session/apis/snode_api/expireRequest.ts +++ b/ts/session/apis/snode_api/expireRequest.ts @@ -148,8 +148,8 @@ export async function processExpireRequestResponse( return results; } -type UpdatedExpiryWithHashes = { messageHashes: Array; updatedExpiry: number }; -type UpdatedExpiryWithHash = { messageHash: string; updatedExpiry: number }; +type UpdatedExpiryWithHashes = { messageHashes: Array; updatedExpiryMs: number }; +type UpdatedExpiryWithHash = { messageHash: string; updatedExpiryMs: number }; async function updateExpiryOnNodes( targetNode: Snode, @@ -210,7 +210,7 @@ async function updateExpiryOnNodes( } changesValid.push({ messageHashes: expirationResult.hashes, - updatedExpiry: expirationResult.expiry, + updatedExpiryMs: expirationResult.expiry, }); } @@ -222,17 +222,16 @@ async function updateExpiryOnNodes( // we requested hashes which are not part of the result. They most likely expired already so let's mark those messages as expiring now. changesValid.push({ messageHashes: hashesRequestedButNotInResults, - updatedExpiry: Date.now(), + updatedExpiryMs: Date.now(), }); } const expiryWithIndividualHash: Array = flatten( changesValid.map(change => - change.messageHashes.map(h => ({ messageHash: h, updatedExpiry: change.updatedExpiry })) + change.messageHashes.map(h => ({ messageHash: h, updatedExpiryMs: change.updatedExpiryMs })) ) ); - debugger; - console.warn('update expiry expiryWithIndividualHash: ', expiryWithIndividualHash); + window.log.debug('update expiry expiryWithIndividualHash: ', expiryWithIndividualHash); return expiryWithIndividualHash; } catch (err) { // NOTE batch requests have their own retry logic which includes abort errors that will break our retry logic so we need to catch them and throw regular errors @@ -373,7 +372,7 @@ export type ExpiringDetails = Array< export async function expireMessagesOnSnode( expiringDetails: ExpiringDetails, options: WithShortenOrExtend -): Promise> { +): Promise> { const ourPubKey = UserUtils.getOurPubKeyStrFromCache(); if (!ourPubKey) { throw new Error('[expireMessageOnSnode] No pubkey found'); diff --git a/ts/session/disappearing_messages/index.ts b/ts/session/disappearing_messages/index.ts index 59be30a3a..987f17a6f 100644 --- a/ts/session/disappearing_messages/index.ts +++ b/ts/session/disappearing_messages/index.ts @@ -79,10 +79,22 @@ async function destroyExpiredMessages() { messages.forEach(expired => { window.log.info('Message expired', { sentAt: expired.get('sent_at'), + hash: expired.getMessageHash(), }); }); await destroyMessagesAndUpdateRedux(messagesExpiredDetails); + const convosToRefresh = uniq(messagesExpiredDetails.map(m => m.conversationKey)); + await Promise.all( + convosToRefresh.map(async c => { + getConversationController() + .get(c) + ?.updateLastMessage(); + return getConversationController() + .get(c) + ?.refreshInMemoryDetails(); + }) + ); } catch (error) { window.log.error( 'destroyExpiredMessages: Error deleting expired messages', @@ -552,7 +564,7 @@ async function updateMessageExpiriesOnSwarm(messages: Array) { window.log.debug(`[updateMessageExpiriesOnSwarm] no expiringDetails to update`); return; } - console.warn('expiringDetails', expiringDetails); + window.log.debug('updateMessageExpiriesOnSwarm: expiringDetails', expiringDetails); const newTTLs = await expireMessagesOnSnode(expiringDetails, { shortenOrExtend: 'shorten' }); const updatedMsgModels: Array = []; @@ -562,10 +574,23 @@ async function updateMessageExpiriesOnSwarm(messages: Array) { return; } - const newTTL = m.updatedExpiry; - if (newTTL && newTTL !== message.getExpiresAt()) { + const newTTLms = m.updatedExpiryMs; + const realReadAt = newTTLms - message.getExpireTimer() * 1000; + if ( + newTTLms && + (newTTLms !== message.getExpiresAt() || + message.get('expirationStartTimestamp') !== realReadAt) && + message.getExpireTimer() + ) { + window.log.debug(`updateMessageExpiriesOnSwarm: setting for msg hash ${m.messageHash}:`, { + expires_at: newTTLms, + expirationStartTimestamp: realReadAt, + unread: READ_MESSAGE_STATE.read, + }); message.set({ - expires_at: newTTL, + expires_at: newTTLms, + expirationStartTimestamp: realReadAt, + unread: READ_MESSAGE_STATE.read, }); updatedMsgModels.push(message); diff --git a/ts/session/utils/job_runners/jobs/FetchMsgExpirySwarmJob.ts b/ts/session/utils/job_runners/jobs/FetchMsgExpirySwarmJob.ts index addebc7b0..0957735f9 100644 --- a/ts/session/utils/job_runners/jobs/FetchMsgExpirySwarmJob.ts +++ b/ts/session/utils/job_runners/jobs/FetchMsgExpirySwarmJob.ts @@ -2,6 +2,7 @@ import { compact, isEmpty, isNumber, uniq } from 'lodash'; import { v4 } from 'uuid'; import { Data } from '../../../../data/data'; +import { READ_MESSAGE_STATE } from '../../../../models/conversationAttributes'; import { MessageModel } from '../../../../models/message'; import { isSignInByLinking } from '../../../../util/storage'; import { getExpiriesFromSnode } from '../../../apis/snode_api/getExpiriesRequest'; @@ -66,13 +67,31 @@ class FetchMsgExpirySwarmJob extends PersistedJob m.getMessageHash() === expiry.messageHash); - if (!found) { + const message = msgModels.find(m => m.getMessageHash() === expiry.messageHash); + if (!message) { continue; } - if (found.get('expires_at') !== expiry.fetchedExpiry) { - found.set('expires_at', expiry.fetchedExpiry); - updatedMsgModels.push(found); + const realReadAt = expiry.fetchedExpiry - message.getExpireTimer() * 1000; + + if ( + (message.get('expirationStartTimestamp') !== realReadAt || + message.get('expires_at') !== expiry.fetchedExpiry) && + message.getExpireTimer() + ) { + window.log.debug( + `FetchMsgExpirySwarmJob: setting for msg hash ${message.getMessageHash()}:`, + { + expires_at: expiry.fetchedExpiry, + unread: READ_MESSAGE_STATE.read, + expirationStartTimestamp: realReadAt, + } + ); + message.set({ + expires_at: expiry.fetchedExpiry, + unread: READ_MESSAGE_STATE.read, + expirationStartTimestamp: realReadAt, + }); + updatedMsgModels.push(message); } } }