move MessageController to typescript

pull/1381/head
Audric Ackermann 4 years ago
parent 727261b36a
commit 228e4ed662
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -156,7 +156,6 @@
<script type='text/javascript' src='js/registration.js'></script> <script type='text/javascript' src='js/registration.js'></script>
<script type='text/javascript' src='js/expire.js'></script> <script type='text/javascript' src='js/expire.js'></script>
<script type='text/javascript' src='js/conversation_controller.js'></script> <script type='text/javascript' src='js/conversation_controller.js'></script>
<script type='text/javascript' src='js/message_controller.js'></script>
<script type='text/javascript' src='js/views/react_wrapper_view.js'></script> <script type='text/javascript' src='js/views/react_wrapper_view.js'></script>
<script type='text/javascript' src='js/views/whisper_view.js'></script> <script type='text/javascript' src='js/views/whisper_view.js'></script>

@ -161,7 +161,6 @@
<script type='text/javascript' src='js/registration.js'></script> <script type='text/javascript' src='js/registration.js'></script>
<script type='text/javascript' src='js/expire.js'></script> <script type='text/javascript' src='js/expire.js'></script>
<script type='text/javascript' src='js/conversation_controller.js'></script> <script type='text/javascript' src='js/conversation_controller.js'></script>
<script type='text/javascript' src='js/message_controller.js'></script>
<script type='text/javascript' src='js/views/react_wrapper_view.js'></script> <script type='text/javascript' src='js/views/react_wrapper_view.js'></script>
<script type='text/javascript' src='js/views/whisper_view.js'></script> <script type='text/javascript' src='js/views/whisper_view.js'></script>

@ -2,7 +2,7 @@
Backbone, Backbone,
Whisper, Whisper,
ConversationController, ConversationController,
MessageController, getMessageController,
_, _,
*/ */
@ -62,7 +62,7 @@
return null; return null;
} }
return MessageController.register(target.id, target); return getMessageController().register(target.id, target);
}, },
async onReceipt(receipt) { async onReceipt(receipt) {
try { try {

@ -2,7 +2,7 @@
_, _,
Backbone, Backbone,
i18n, i18n,
MessageController, getMessageController,
moment, moment,
Whisper Whisper
*/ */
@ -22,7 +22,7 @@
await Promise.all( await Promise.all(
messages.map(async fromDB => { messages.map(async fromDB => {
const message = MessageController.register(fromDB.id, fromDB); const message = getMessageController().register(fromDB.id, fromDB);
window.log.info('Message expired', { window.log.info('Message expired', {
sentAt: message.get('sent_at'), sentAt: message.get('sent_at'),

@ -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,
};
})();

@ -5,7 +5,7 @@
Backbone, Backbone,
libsession, libsession,
ConversationController, ConversationController,
MessageController, getMessageController,
storage, storage,
textsecure, textsecure,
Whisper, Whisper,
@ -461,7 +461,7 @@
this.clearContactTypingTimer(identifier); this.clearContactTypingTimer(identifier);
const model = this.addSingleMessage(message); const model = this.addSingleMessage(message);
MessageController.register(model.id, model); getMessageController().register(model.id, model);
window.Whisper.events.trigger('messageAdded', { window.Whisper.events.trigger('messageAdded', {
conversationKey: this.id, conversationKey: this.id,
@ -1297,7 +1297,7 @@
}; };
const model = this.addSingleMessage(attributes); const model = this.addSingleMessage(attributes);
const message = MessageController.register(model.id, model); const message = getMessageController().register(model.id, model);
await message.commit(true); await message.commit(true);
@ -1780,7 +1780,7 @@
let read = await Promise.all( let read = await Promise.all(
_.map(oldUnread, async providedM => { _.map(oldUnread, async providedM => {
const m = MessageController.register(providedM.id, providedM); const m = getMessageController().register(providedM.id, providedM);
if (!this.messageCollection.get(m.id)) { if (!this.messageCollection.get(m.id)) {
window.log.warn( window.log.warn(

@ -4,7 +4,7 @@
storage, storage,
filesize, filesize,
ConversationController, ConversationController,
MessageController, getMessageController,
i18n, i18n,
Signal, Signal,
textsecure, textsecure,
@ -302,7 +302,7 @@
this.cleanup(); this.cleanup();
}, },
async cleanup() { async cleanup() {
MessageController.unregister(this.id); getMessageController().unregister(this.id);
this.unload(); this.unload();
await deleteExternalMessageFiles(this.attributes); await deleteExternalMessageFiles(this.attributes);
}, },

@ -1,4 +1,4 @@
/* global Whisper, Signal, setTimeout, clearTimeout, MessageController, NewReceiver */ /* global Whisper, Signal, setTimeout, clearTimeout, getMessageController, NewReceiver */
const { isNumber, omit } = require('lodash'); const { isNumber, omit } = require('lodash');
const getGuid = require('uuid/v4'); const getGuid = require('uuid/v4');
@ -150,7 +150,7 @@ async function _runJob(job) {
await _finishJob(null, id); await _finishJob(null, id);
return; return;
} }
message = MessageController.register(found.id, found); message = getMessageController().register(found.id, found);
const pending = true; const pending = true;
await setAttachmentDownloadJobPending(id, pending); await setAttachmentDownloadJobPending(id, pending);

@ -1,5 +1,5 @@
/* global log, textsecure, libloki, Signal, Whisper, ConversationController, /* global log, textsecure, libloki, Signal, Whisper, ConversationController,
clearTimeout, MessageController, libsignal, StringView, window, _, clearTimeout, getMessageController, libsignal, StringView, window, _,
dcodeIO, Buffer, process */ dcodeIO, Buffer, process */
const nodeFetch = require('node-fetch'); const nodeFetch = require('node-fetch');
const { URL, URLSearchParams } = require('url'); const { URL, URLSearchParams } = require('url');
@ -2134,7 +2134,7 @@ class LokiPublicChannelAPI {
}); });
if (found) { if (found) {
const queryMessage = MessageController.register(found.id, found); const queryMessage = getMessageController().register(found.id, found);
const replyTo = queryMessage.get('serverId'); const replyTo = queryMessage.get('serverId');
if (replyTo) { if (replyTo) {
payload.reply_to = replyTo; payload.reply_to = replyTo;

@ -3,7 +3,7 @@
Backbone, Backbone,
_, _,
ConversationController, ConversationController,
MessageController, getMessageController,
window window
*/ */
@ -60,7 +60,7 @@
return null; return null;
} }
return MessageController.register(target.id, target); return getMessageController().register(target.id, target);
}, },
async onReceipt(receipt) { async onReceipt(receipt) {
try { try {

@ -1,7 +1,7 @@
/* global /* global
Backbone, Backbone,
Whisper, Whisper,
MessageController getMessageController
*/ */
/* eslint-disable more/no-then */ /* eslint-disable more/no-then */
@ -61,7 +61,7 @@
return; return;
} }
const message = MessageController.register(found.id, found); const message = getMessageController().register(found.id, found);
const readAt = receipt.get('read_at'); const readAt = receipt.get('read_at');
// If message is unread, we mark it read. Otherwise, we update the expiration // If message is unread, we mark it read. Otherwise, we update the expiration

@ -176,6 +176,9 @@ window.setPassword = (passPhrase, oldPhrase) =>
window.passwordUtil = require('./ts/util/passwordUtils'); window.passwordUtil = require('./ts/util/passwordUtils');
window.libsession = require('./ts/session'); 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 // We never do these in our code, so we'll prevent it everywhere
window.open = () => null; window.open = () => null;
// eslint-disable-next-line no-eval, no-multi-assign // eslint-disable-next-line no-eval, no-multi-assign

@ -192,7 +192,6 @@
<script type="text/javascript" src="../js/models/messages.js" data-cover></script> <script type="text/javascript" src="../js/models/messages.js" data-cover></script>
<script type="text/javascript" src="../js/models/conversations.js" data-cover></script> <script type="text/javascript" src="../js/models/conversations.js" data-cover></script>
<script type="text/javascript" src="../js/conversation_controller.js" data-cover></script> <script type="text/javascript" src="../js/conversation_controller.js" data-cover></script>
<script type="text/javascript" src="../js/message_controller.js" data-cover></script>
<script type="text/javascript" src="../js/keychange_listener.js" data-cover></script> <script type="text/javascript" src="../js/keychange_listener.js" data-cover></script>
<script type="text/javascript" src="../js/expiring_messages.js" data-cover></script> <script type="text/javascript" src="../js/expiring_messages.js" data-cover></script>
<script type="text/javascript" src="../js/notifications.js" data-cover></script> <script type="text/javascript" src="../js/notifications.js" data-cover></script>

@ -138,7 +138,7 @@ export class SessionInboxView extends React.Component<Props, State> {
return null; return null;
} }
const msg = window.MessageController._get()[m.identifier]; const msg = window.getMessageController().get(m.identifier);
if (!msg || !msg.message) { if (!msg || !msg.message) {
return null; return null;

@ -100,7 +100,7 @@ async function copyFromQuotedMessage(
quote: Quote, quote: Quote,
attemptCount: number = 1 attemptCount: number = 1
): Promise<void> { ): Promise<void> {
const { Whisper, MessageController } = window; const { Whisper, getMessageController } = window;
const { upgradeMessageSchema } = window.Signal.Migrations; const { upgradeMessageSchema } = window.Signal.Migrations;
const { Message: TypedMessage, Errors } = window.Signal.Types; const { Message: TypedMessage, Errors } = window.Signal.Types;
@ -142,7 +142,7 @@ async function copyFromQuotedMessage(
window.log.info(`Found quoted message id: ${id}`); window.log.info(`Found quoted message id: ${id}`);
quote.referencedMessageNotFound = false; quote.referencedMessageNotFound = false;
const queryMessage = MessageController.register(found.id, found); const queryMessage = getMessageController().register(found.id, found);
quote.text = queryMessage.get('body'); quote.text = queryMessage.get('body');
if (attemptCount > 1) { if (attemptCount > 1) {
@ -552,11 +552,11 @@ export async function handleMessageJob(
); );
} }
const { Whisper, MessageController } = window; const { Whisper, getMessageController } = window;
const id = await message.commit(); const id = await message.commit();
message.set({ id }); 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 // 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 // call it after we have an id for this message, because the jobs refer back

@ -117,8 +117,7 @@ export async function createMediumGroup(
}; };
const dbMessage = await addUpdateMessage(convo, groupDiff, 'outgoing'); 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. // 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 // 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'); 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); await sendGroupUpdate(convo, diff, groupDetails, dbMessage.id);
@ -217,7 +216,7 @@ export async function leaveMediumGroup(groupId: string) {
sent_at: now, sent_at: now,
received_at: now, received_at: now,
}); });
window.MessageController.register(dbMessage.id, dbMessage); window.getMessageController().register(dbMessage.id, dbMessage);
const ourPrimary = await UserUtil.getPrimary(); const ourPrimary = await UserUtil.getPrimary();
const members = convo.get('members').filter(m => m !== ourPrimary.key); 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'); 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); await sendGroupUpdate(convo, diff, updateObj, dbMessage.id);
} }

@ -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<string, any>;
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);
}
}

@ -1,3 +1,4 @@
import * as Outgoing from './outgoing'; import * as Outgoing from './outgoing';
import { MessageController } from './MessageController';
export { Outgoing }; export { Outgoing, MessageController };

3
ts/window.d.ts vendored

@ -17,6 +17,7 @@ import {} from 'styled-components/cssprop';
import { ConversationControllerType } from '../js/ConversationController'; import { ConversationControllerType } from '../js/ConversationController';
import { any } from 'underscore'; import { any } from 'underscore';
import { Store } from 'redux'; 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. 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. If you import anything in global.d.ts, the type system won't work correctly.
@ -33,7 +34,7 @@ declare global {
LokiFileServerAPI: any; LokiFileServerAPI: any;
LokiPublicChatAPI: any; LokiPublicChatAPI: any;
LokiSnodeAPI: any; LokiSnodeAPI: any;
MessageController: any; getMessageController: () => MessageController;
Session: any; Session: any;
Signal: SignalInterface; Signal: SignalInterface;
StringView: any; StringView: any;

Loading…
Cancel
Save