From 228e4ed662f55a74b8b0295a715e915f79e843ef Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 2 Dec 2020 11:26:31 +1100 Subject: [PATCH] move MessageController to typescript --- background.html | 1 - background_test.html | 1 - js/delivery_receipts.js | 4 +- js/expiring_messages.js | 4 +- js/message_controller.js | 65 --------------------- js/models/conversations.js | 8 +-- js/models/messages.js | 4 +- js/modules/attachment_downloads.js | 4 +- js/modules/loki_app_dot_net_api.js | 4 +- js/read_receipts.js | 4 +- js/read_syncs.js | 4 +- preload.js | 3 + test/index.html | 1 - ts/components/session/SessionInboxView.tsx | 2 +- ts/receiver/queuedJob.ts | 8 +-- ts/session/medium_group/index.ts | 9 ++- ts/session/messages/MessageController.ts | 67 ++++++++++++++++++++++ ts/session/messages/index.ts | 3 +- ts/window.d.ts | 3 +- 19 files changed, 101 insertions(+), 98 deletions(-) delete mode 100644 js/message_controller.js create mode 100644 ts/session/messages/MessageController.ts diff --git a/background.html b/background.html index 97d968791..de2fb4e6b 100644 --- a/background.html +++ b/background.html @@ -156,7 +156,6 @@ - diff --git a/background_test.html b/background_test.html index ec617a3d1..e14706bcd 100644 --- a/background_test.html +++ b/background_test.html @@ -161,7 +161,6 @@ - diff --git a/js/delivery_receipts.js b/js/delivery_receipts.js index ccbec509a..3cffe7589 100644 --- a/js/delivery_receipts.js +++ b/js/delivery_receipts.js @@ -2,7 +2,7 @@ Backbone, Whisper, ConversationController, - MessageController, + getMessageController, _, */ @@ -62,7 +62,7 @@ return null; } - return MessageController.register(target.id, target); + return getMessageController().register(target.id, target); }, async onReceipt(receipt) { try { diff --git a/js/expiring_messages.js b/js/expiring_messages.js index fd4e5e881..b89e45a67 100644 --- a/js/expiring_messages.js +++ b/js/expiring_messages.js @@ -2,7 +2,7 @@ _, Backbone, i18n, - MessageController, + getMessageController, moment, Whisper */ @@ -22,7 +22,7 @@ await Promise.all( messages.map(async fromDB => { - const message = MessageController.register(fromDB.id, fromDB); + const message = getMessageController().register(fromDB.id, fromDB); window.log.info('Message expired', { sentAt: message.get('sent_at'), diff --git a/js/message_controller.js b/js/message_controller.js deleted file mode 100644 index 18d58cde9..000000000 --- a/js/message_controller.js +++ /dev/null @@ -1,65 +0,0 @@ -// eslint-disable-next-line func-names -(function() { - 'use strict'; - - window.Whisper = window.Whisper || {}; - - const messageLookup = Object.create(null); - - const SECOND = 1000; - const MINUTE = SECOND * 60; - const FIVE_MINUTES = MINUTE * 5; - const HOUR = MINUTE * 60; - - function register(id, message) { - const existing = messageLookup[id]; - if (existing) { - messageLookup[id] = { - message: existing.message, - timestamp: Date.now(), - }; - return existing.message; - } - - messageLookup[id] = { - message, - timestamp: Date.now(), - }; - - return message; - } - - function unregister(id) { - delete messageLookup[id]; - } - - function cleanup() { - const messages = Object.values(messageLookup); - const now = Date.now(); - - for (let i = 0, max = messages.length; i < max; i += 1) { - const { message, timestamp } = messages[i]; - const conversation = message.getConversation(); - - if ( - now - timestamp > FIVE_MINUTES && - (!conversation || !conversation.messageCollection.length) - ) { - delete messageLookup[message.id]; - } - } - } - - function _get() { - return messageLookup; - } - - setInterval(cleanup, HOUR); - - window.MessageController = { - register, - unregister, - cleanup, - _get, - }; -})(); diff --git a/js/models/conversations.js b/js/models/conversations.js index 17a1692a8..6231dde99 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -5,7 +5,7 @@ Backbone, libsession, ConversationController, - MessageController, + getMessageController, storage, textsecure, Whisper, @@ -461,7 +461,7 @@ this.clearContactTypingTimer(identifier); const model = this.addSingleMessage(message); - MessageController.register(model.id, model); + getMessageController().register(model.id, model); window.Whisper.events.trigger('messageAdded', { conversationKey: this.id, @@ -1297,7 +1297,7 @@ }; const model = this.addSingleMessage(attributes); - const message = MessageController.register(model.id, model); + const message = getMessageController().register(model.id, model); await message.commit(true); @@ -1780,7 +1780,7 @@ let read = await Promise.all( _.map(oldUnread, async providedM => { - const m = MessageController.register(providedM.id, providedM); + const m = getMessageController().register(providedM.id, providedM); if (!this.messageCollection.get(m.id)) { window.log.warn( diff --git a/js/models/messages.js b/js/models/messages.js index 755f0cde5..7757c2a25 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -4,7 +4,7 @@ storage, filesize, ConversationController, - MessageController, + getMessageController, i18n, Signal, textsecure, @@ -302,7 +302,7 @@ this.cleanup(); }, async cleanup() { - MessageController.unregister(this.id); + getMessageController().unregister(this.id); this.unload(); await deleteExternalMessageFiles(this.attributes); }, diff --git a/js/modules/attachment_downloads.js b/js/modules/attachment_downloads.js index aed57b391..dd49daa4f 100644 --- a/js/modules/attachment_downloads.js +++ b/js/modules/attachment_downloads.js @@ -1,4 +1,4 @@ -/* global Whisper, Signal, setTimeout, clearTimeout, MessageController, NewReceiver */ +/* global Whisper, Signal, setTimeout, clearTimeout, getMessageController, NewReceiver */ const { isNumber, omit } = require('lodash'); const getGuid = require('uuid/v4'); @@ -150,7 +150,7 @@ async function _runJob(job) { await _finishJob(null, id); return; } - message = MessageController.register(found.id, found); + message = getMessageController().register(found.id, found); const pending = true; await setAttachmentDownloadJobPending(id, pending); diff --git a/js/modules/loki_app_dot_net_api.js b/js/modules/loki_app_dot_net_api.js index ffa2a27cf..06ed9abfa 100644 --- a/js/modules/loki_app_dot_net_api.js +++ b/js/modules/loki_app_dot_net_api.js @@ -1,5 +1,5 @@ /* global log, textsecure, libloki, Signal, Whisper, ConversationController, -clearTimeout, MessageController, libsignal, StringView, window, _, +clearTimeout, getMessageController, libsignal, StringView, window, _, dcodeIO, Buffer, process */ const nodeFetch = require('node-fetch'); const { URL, URLSearchParams } = require('url'); @@ -2134,7 +2134,7 @@ class LokiPublicChannelAPI { }); if (found) { - const queryMessage = MessageController.register(found.id, found); + const queryMessage = getMessageController().register(found.id, found); const replyTo = queryMessage.get('serverId'); if (replyTo) { payload.reply_to = replyTo; diff --git a/js/read_receipts.js b/js/read_receipts.js index b5a89b9a2..432b894ae 100644 --- a/js/read_receipts.js +++ b/js/read_receipts.js @@ -3,7 +3,7 @@ Backbone, _, ConversationController, - MessageController, + getMessageController, window */ @@ -60,7 +60,7 @@ return null; } - return MessageController.register(target.id, target); + return getMessageController().register(target.id, target); }, async onReceipt(receipt) { try { diff --git a/js/read_syncs.js b/js/read_syncs.js index 932794328..69ea15196 100644 --- a/js/read_syncs.js +++ b/js/read_syncs.js @@ -1,7 +1,7 @@ /* global Backbone, Whisper, - MessageController + getMessageController */ /* eslint-disable more/no-then */ @@ -61,7 +61,7 @@ return; } - const message = MessageController.register(found.id, found); + const message = getMessageController().register(found.id, found); const readAt = receipt.get('read_at'); // If message is unread, we mark it read. Otherwise, we update the expiration diff --git a/preload.js b/preload.js index 3f79ee3d1..28d3c780d 100644 --- a/preload.js +++ b/preload.js @@ -176,6 +176,9 @@ window.setPassword = (passPhrase, oldPhrase) => window.passwordUtil = require('./ts/util/passwordUtils'); window.libsession = require('./ts/session'); +window.getMessageController = + window.libsession.Messages.MessageController.getInstance; + // We never do these in our code, so we'll prevent it everywhere window.open = () => null; // eslint-disable-next-line no-eval, no-multi-assign diff --git a/test/index.html b/test/index.html index 36207ad28..333ca6b3e 100644 --- a/test/index.html +++ b/test/index.html @@ -192,7 +192,6 @@ - diff --git a/ts/components/session/SessionInboxView.tsx b/ts/components/session/SessionInboxView.tsx index 2a3a2a6e4..3b5d5e8e9 100644 --- a/ts/components/session/SessionInboxView.tsx +++ b/ts/components/session/SessionInboxView.tsx @@ -138,7 +138,7 @@ export class SessionInboxView extends React.Component { return null; } - const msg = window.MessageController._get()[m.identifier]; + const msg = window.getMessageController().get(m.identifier); if (!msg || !msg.message) { return null; diff --git a/ts/receiver/queuedJob.ts b/ts/receiver/queuedJob.ts index 128c5ebba..0d538ca8e 100644 --- a/ts/receiver/queuedJob.ts +++ b/ts/receiver/queuedJob.ts @@ -100,7 +100,7 @@ async function copyFromQuotedMessage( quote: Quote, attemptCount: number = 1 ): Promise { - const { Whisper, MessageController } = window; + const { Whisper, getMessageController } = window; const { upgradeMessageSchema } = window.Signal.Migrations; const { Message: TypedMessage, Errors } = window.Signal.Types; @@ -142,7 +142,7 @@ async function copyFromQuotedMessage( window.log.info(`Found quoted message id: ${id}`); quote.referencedMessageNotFound = false; - const queryMessage = MessageController.register(found.id, found); + const queryMessage = getMessageController().register(found.id, found); quote.text = queryMessage.get('body'); if (attemptCount > 1) { @@ -552,11 +552,11 @@ export async function handleMessageJob( ); } - const { Whisper, MessageController } = window; + const { Whisper, getMessageController } = window; const id = await message.commit(); message.set({ id }); - MessageController.register(message.id, message); + getMessageController().register(message.id, message); // Note that this can save the message again, if jobs were queued. We need to // call it after we have an id for this message, because the jobs refer back diff --git a/ts/session/medium_group/index.ts b/ts/session/medium_group/index.ts index c95d3d3ff..972bc2905 100644 --- a/ts/session/medium_group/index.ts +++ b/ts/session/medium_group/index.ts @@ -117,8 +117,7 @@ export async function createMediumGroup( }; const dbMessage = await addUpdateMessage(convo, groupDiff, 'outgoing'); - window.MessageController.register(dbMessage.id, dbMessage); - + window.getMessageController().register(dbMessage.id, dbMessage); // be sure to call this before sending the message. // the sending pipeline needs to know from GroupUtils when a message is for a medium group @@ -177,7 +176,7 @@ export async function createLegacyGroup( }; const dbMessage = await addUpdateMessage(convo, diff, 'outgoing'); - window.MessageController.register(dbMessage.id, dbMessage); + window.getMessageController().register(dbMessage.id, dbMessage); await sendGroupUpdate(convo, diff, groupDetails, dbMessage.id); @@ -217,7 +216,7 @@ export async function leaveMediumGroup(groupId: string) { sent_at: now, received_at: now, }); - window.MessageController.register(dbMessage.id, dbMessage); + window.getMessageController().register(dbMessage.id, dbMessage); const ourPrimary = await UserUtil.getPrimary(); const members = convo.get('members').filter(m => m !== ourPrimary.key); @@ -411,7 +410,7 @@ export async function initiateGroupUpdate( } const dbMessage = await addUpdateMessage(convo, diff, 'outgoing'); - window.MessageController.register(dbMessage.id, dbMessage); + window.getMessageController().register(dbMessage.id, dbMessage); await sendGroupUpdate(convo, diff, updateObj, dbMessage.id); } diff --git a/ts/session/messages/MessageController.ts b/ts/session/messages/MessageController.ts new file mode 100644 index 000000000..994bfcdb6 --- /dev/null +++ b/ts/session/messages/MessageController.ts @@ -0,0 +1,67 @@ +// You can see MessageController for in memory registered messages. +// Ee register messages to it everytime we send one, so that when an event happens we can find which message it was based on this id. +// It's not only data from the db which is stored on the MessageController entries, we could fetch this again. What we cannot fetch from the db and which is stored here is all listeners a particular messages is linked to for instance. We will be able to get rid of this once we don't use backbone models at all +export class MessageController { + private static instance: MessageController | null; + private readonly messageLookup: Map; + + private constructor() { + this.messageLookup = new Map(); + // cleanup every hour the cache + setInterval(this.cleanup, 3600 * 1000); + } + + public static getInstance() { + if (MessageController.instance) { + return MessageController.instance; + } + MessageController.instance = new MessageController(); + return MessageController.instance; + } + + public register(id: string, message: any) { + const existing = this.messageLookup.get(id); + if (existing) { + this.messageLookup.set(id, { + message: existing.message, + timestamp: Date.now(), + }); + return existing.message; + } + + this.messageLookup.set(id, { + message, + timestamp: Date.now(), + }); + + return message; + } + + public unregister(id: string) { + this.messageLookup.delete(id); + } + + public cleanup() { + window.log.warn('Cleaning up getMessageController() oldest messages...'); + const messages = Object.values(this.messageLookup); + const now = Date.now(); + + // tslint:disable-next-line: one-variable-per-declaration + for (let i = 0, max = messages.length; i < max; i += 1) { + const { message, timestamp } = messages[i]; + const conversation = message.getConversation(); + + if ( + now - timestamp > 5 * 60 * 1000 && + (!conversation || !conversation.messageCollection.length) + ) { + this.unregister(message.id); + } + } + } + + // tslint:disable-next-line: function-name + public get(identifier: string) { + return this.messageLookup.get(identifier); + } +} diff --git a/ts/session/messages/index.ts b/ts/session/messages/index.ts index 1358ed9f6..94312c76b 100644 --- a/ts/session/messages/index.ts +++ b/ts/session/messages/index.ts @@ -1,3 +1,4 @@ import * as Outgoing from './outgoing'; +import { MessageController } from './MessageController'; -export { Outgoing }; +export { Outgoing, MessageController }; diff --git a/ts/window.d.ts b/ts/window.d.ts index 1d95b0f8b..477c80c95 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -17,6 +17,7 @@ import {} from 'styled-components/cssprop'; import { ConversationControllerType } from '../js/ConversationController'; import { any } from 'underscore'; import { Store } from 'redux'; +import { MessageController } from './session/messages/MessageController'; /* We declare window stuff here instead of global.d.ts because we are importing other declarations. If you import anything in global.d.ts, the type system won't work correctly. @@ -33,7 +34,7 @@ declare global { LokiFileServerAPI: any; LokiPublicChatAPI: any; LokiSnodeAPI: any; - MessageController: any; + getMessageController: () => MessageController; Session: any; Signal: SignalInterface; StringView: any;