diff --git a/js/expiring_tap_to_view_messages.js b/js/expiring_tap_to_view_messages.js deleted file mode 100644 index 28a3f9d69..000000000 --- a/js/expiring_tap_to_view_messages.js +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2019-2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -/* global - _, - MessageController, - Whisper -*/ - -// eslint-disable-next-line func-names -(function () { - window.Whisper = window.Whisper || {}; - - async function eraseTapToViewMessages() { - try { - window.SignalContext.log.info( - 'eraseTapToViewMessages: Loading messages...' - ); - const messages = - await window.Signal.Data.getTapToViewMessagesNeedingErase({ - MessageCollection: Whisper.MessageCollection, - }); - - await Promise.all( - messages.map(async fromDB => { - const message = MessageController.register(fromDB.id, fromDB); - - window.SignalContext.log.info( - 'eraseTapToViewMessages: message data erased', - message.idForLogging() - ); - - await message.eraseContents(); - }) - ); - } catch (error) { - window.SignalContext.log.error( - 'eraseTapToViewMessages: Error erasing messages', - error && error.stack ? error.stack : error - ); - } - - window.SignalContext.log.info('eraseTapToViewMessages: complete'); - } - - let timeout; - async function checkTapToViewMessages() { - const SECOND = 1000; - const MINUTE = 60 * SECOND; - const HOUR = 60 * MINUTE; - const THIRTY_DAYS = 30 * 24 * HOUR; - - const receivedAt = - await window.Signal.Data.getNextTapToViewMessageTimestampToAgeOut(); - if (!receivedAt) { - return; - } - - const nextCheck = receivedAt + THIRTY_DAYS; - - Whisper.TapToViewMessagesListener.nextCheck = nextCheck; - window.SignalContext.log.info( - 'checkTapToViewMessages: next check at', - new Date(nextCheck).toISOString() - ); - - let wait = nextCheck - Date.now(); - - // In the past - if (wait < 0) { - wait = 0; - } - - // Too far in the future, since it's limited to a 32-bit value - if (wait > 2147483647) { - wait = 2147483647; - } - - clearTimeout(timeout); - timeout = setTimeout(async () => { - await eraseTapToViewMessages(); - checkTapToViewMessages(); - }, wait); - } - const debouncedCheckTapToViewMessages = _.debounce( - checkTapToViewMessages, - 1000 - ); - - Whisper.TapToViewMessagesListener = { - nextCheck: null, - init(events) { - checkTapToViewMessages(); - events.on('timetravel', debouncedCheckTapToViewMessages); - }, - update: debouncedCheckTapToViewMessages, - }; -})(); diff --git a/ts/background.ts b/ts/background.ts index 28eaa4942..5879097c3 100644 --- a/ts/background.ts +++ b/ts/background.ts @@ -39,6 +39,8 @@ import { normalizeUuid } from './util/normalizeUuid'; import { filter } from './util/iterables'; import { isNotNil } from './util/isNotNil'; import { IdleDetector } from './IdleDetector'; +import { expiringMessagesDeletionService } from './services/expiringMessagesDeletion'; +import { tapToViewMessagesDeletionService } from './services/tapToViewMessagesDeletionService'; import { getStoriesForRedux, loadStories } from './services/storyLoader'; import { senderCertificateService } from './services/senderCertificate'; import { GROUP_CREDENTIALS_KEY } from './services/groupCredentialFetcher'; @@ -1731,8 +1733,12 @@ export async function startApp(): Promise { window.Whisper.events.trigger('timetravel'); }); - window.Whisper.ExpiringMessagesListener.init(window.Whisper.events); - window.Whisper.TapToViewMessagesListener.init(window.Whisper.events); + expiringMessagesDeletionService.update(); + tapToViewMessagesDeletionService.update(); + window.Whisper.events.on('timetravel', () => { + expiringMessagesDeletionService.update(); + tapToViewMessagesDeletionService.update(); + }); const isCoreDataValid = Boolean( window.textsecure.storage.user.getUuid() && diff --git a/js/expiring_messages.js b/ts/services/expiringMessagesDeletion.ts similarity index 68% rename from js/expiring_messages.js rename to ts/services/expiringMessagesDeletion.ts index 3cf7099ea..8ea3417c2 100644 --- a/js/expiring_messages.js +++ b/ts/services/expiringMessagesDeletion.ts @@ -1,34 +1,38 @@ -// Copyright 2016-2021 Signal Messenger, LLC +// Copyright 2016-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -/* global - _, - MessageController, - Whisper -*/ +import { debounce } from 'lodash'; +import type { MessageModel } from '../models/messages'; +import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary'; -// eslint-disable-next-line func-names -(function () { - window.Whisper = window.Whisper || {}; +class ExpiringMessagesDeletionService { + public update: typeof this.checkExpiringMessages; - async function destroyExpiredMessages() { + private timeout?: ReturnType; + + constructor() { + this.update = debounce(this.checkExpiringMessages, 1000); + } + + private async destroyExpiredMessages() { try { window.SignalContext.log.info( 'destroyExpiredMessages: Loading messages...' ); - const messages = await window.Signal.Data.getExpiredMessages({ - MessageCollection: Whisper.MessageCollection, - }); + const messages = await window.Signal.Data.getExpiredMessages(); window.SignalContext.log.info( `destroyExpiredMessages: found ${messages.length} messages to expire` ); - const messageIds = []; - const inMemoryMessages = []; - const messageCleanup = []; + const messageIds: Array = []; + const inMemoryMessages: Array = []; + const messageCleanup: Array> = []; messages.forEach(dbMessage => { - const message = MessageController.register(dbMessage.id, dbMessage); + const message = window.MessageController.register( + dbMessage.id, + dbMessage + ); messageIds.push(message.id); inMemoryMessages.push(message); messageCleanup.push(message.cleanup()); @@ -59,11 +63,10 @@ } window.SignalContext.log.info('destroyExpiredMessages: complete'); - checkExpiringMessages(); + this.update(); } - let timeout; - async function checkExpiringMessages() { + private async checkExpiringMessages() { window.SignalContext.log.info( 'checkExpiringMessages: checking for expiring messages' ); @@ -94,19 +97,10 @@ ).toISOString()}; waiting ${wait} ms before clearing` ); - clearTimeout(timeout); - timeout = setTimeout(destroyExpiredMessages, wait); + clearTimeoutIfNecessary(this.timeout); + this.timeout = setTimeout(this.destroyExpiredMessages.bind(this), wait); } - const debouncedCheckExpiringMessages = _.debounce( - checkExpiringMessages, - 1000 - ); +} - Whisper.ExpiringMessagesListener = { - init(events) { - checkExpiringMessages(); - events.on('timetravel', debouncedCheckExpiringMessages); - }, - update: debouncedCheckExpiringMessages, - }; -})(); +export const expiringMessagesDeletionService = + new ExpiringMessagesDeletionService(); diff --git a/ts/services/tapToViewMessagesDeletionService.ts b/ts/services/tapToViewMessagesDeletionService.ts new file mode 100644 index 000000000..e96845578 --- /dev/null +++ b/ts/services/tapToViewMessagesDeletionService.ts @@ -0,0 +1,80 @@ +// Copyright 2019-2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { debounce } from 'lodash'; +import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary'; +import { DAY } from '../util/durations'; + +async function eraseTapToViewMessages() { + try { + window.SignalContext.log.info( + 'eraseTapToViewMessages: Loading messages...' + ); + const messages = + await window.Signal.Data.getTapToViewMessagesNeedingErase(); + await Promise.all( + messages.map(async fromDB => { + const message = window.MessageController.register(fromDB.id, fromDB); + + window.SignalContext.log.info( + 'eraseTapToViewMessages: erasing message contents', + message.idForLogging() + ); + + await message.eraseContents(); + }) + ); + } catch (error) { + window.SignalContext.log.error( + 'eraseTapToViewMessages: Error erasing messages', + error && error.stack ? error.stack : error + ); + } + + window.SignalContext.log.info('eraseTapToViewMessages: complete'); +} + +class TapToViewMessagesDeletionService { + public update: typeof this.checkTapToViewMessages; + + private timeout?: ReturnType; + + constructor() { + this.update = debounce(this.checkTapToViewMessages, 1000); + } + + private async checkTapToViewMessages() { + const receivedAt = + await window.Signal.Data.getNextTapToViewMessageTimestampToAgeOut(); + if (!receivedAt) { + return; + } + + const nextCheck = receivedAt + 30 * DAY; + window.SignalContext.log.info( + 'checkTapToViewMessages: next check at', + new Date(nextCheck).toISOString() + ); + + let wait = nextCheck - Date.now(); + + // In the past + if (wait < 0) { + wait = 0; + } + + // Too far in the future, since it's limited to a 32-bit value + if (wait > 2147483647) { + wait = 2147483647; + } + + clearTimeoutIfNecessary(this.timeout); + this.timeout = setTimeout(async () => { + await eraseTapToViewMessages(); + this.update(); + }, wait); + } +} + +export const tapToViewMessagesDeletionService = + new TapToViewMessagesDeletionService(); diff --git a/ts/sql/Client.ts b/ts/sql/Client.ts index 822e35cfc..5d2fd4699 100644 --- a/ts/sql/Client.ts +++ b/ts/sql/Client.ts @@ -27,6 +27,8 @@ import { } from 'lodash'; import { deleteExternalFiles } from '../types/Conversation'; +import { expiringMessagesDeletionService } from '../services/expiringMessagesDeletion'; +import { tapToViewMessagesDeletionService } from '../services/tapToViewMessagesDeletionService'; import * as Bytes from '../Bytes'; import { CURRENT_SCHEMA_VERSION } from '../../js/modules/types/message'; import { createBatcher } from '../util/batcher'; @@ -1090,8 +1092,8 @@ async function saveMessage( jobToInsert: options.jobToInsert && formatJobForInsert(options.jobToInsert), }); - window.Whisper.ExpiringMessagesListener.update(); - window.Whisper.TapToViewMessagesListener.update(); + expiringMessagesDeletionService.update(); + tapToViewMessagesDeletionService.update(); return id; } @@ -1105,8 +1107,8 @@ async function saveMessages( options ); - window.Whisper.ExpiringMessagesListener.update(); - window.Whisper.TapToViewMessagesListener.update(); + expiringMessagesDeletionService.update(); + tapToViewMessagesDeletionService.update(); } async function removeMessage(id: string) { diff --git a/ts/util/markConversationRead.ts b/ts/util/markConversationRead.ts index ab3c602be..f132d3de1 100644 --- a/ts/util/markConversationRead.ts +++ b/ts/util/markConversationRead.ts @@ -1,4 +1,4 @@ -// Copyright 2021 Signal Messenger, LLC +// Copyright 2021-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { omit } from 'lodash'; @@ -8,6 +8,8 @@ import { hasErrors } from '../state/selectors/message'; import { readReceiptsJobQueue } from '../jobs/readReceiptsJobQueue'; import { readSyncJobQueue } from '../jobs/readSyncJobQueue'; import { notificationService } from '../services/notifications'; +import { expiringMessagesDeletionService } from '../services/expiringMessagesDeletion'; +import { tapToViewMessagesDeletionService } from '../services/tapToViewMessagesDeletionService'; import { isGroup } from './whatTypeOfConversation'; import * as log from '../logging/log'; import { getConversationIdForLogging } from './idForLogging'; @@ -137,8 +139,8 @@ export async function markConversationRead( ); } - window.Whisper.ExpiringMessagesListener.update(); - window.Whisper.TapToViewMessagesListener.update(); + expiringMessagesDeletionService.update(); + tapToViewMessagesDeletionService.update(); return true; } diff --git a/ts/window.d.ts b/ts/window.d.ts index 17b57ec1c..befef2992 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -556,16 +556,6 @@ export type WhisperType = { events: Backbone.Events; activeConfirmationView: WhatIsThis; - ExpiringMessagesListener: { - init: (events: Backbone.Events) => void; - update: () => void; - }; - TapToViewMessagesListener: { - nextCheck: null | number; - init: (events: Backbone.Events) => void; - update: () => void; - }; - // Backbone views // Modernized