Remove messageCollection from Conversation model

This commit is contained in:
Scott Nonnenberg 2021-06-15 17:44:14 -07:00 committed by GitHub
parent 61ad1231df
commit 1520c80013
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 332 additions and 431 deletions

View file

@ -136,8 +136,6 @@ export class ConversationModel extends window.Backbone
jobQueue?: typeof window.PQueueType;
messageCollection?: MessageModelCollectionType;
ourNumber?: string;
ourUuid?: string;
@ -168,6 +166,8 @@ export class ConversationModel extends window.Backbone
private isFetchingUUID?: boolean;
private hasAddedHistoryDisclaimer?: boolean;
// eslint-disable-next-line class-methods-use-this
defaults(): Partial<ConversationAttributesType> {
return {
@ -198,10 +198,6 @@ export class ConversationModel extends window.Backbone
return this.get('uuid') || this.get('e164');
}
handleMessageError(message: unknown, errors: unknown): void {
this.trigger('messageError', message, errors);
}
// eslint-disable-next-line class-methods-use-this
getContactCollection(): Backbone.Collection<ConversationModel> {
const collection = new window.Backbone.Collection<ConversationModel>();
@ -252,30 +248,9 @@ export class ConversationModel extends window.Backbone
);
}
this.messageCollection = new window.Whisper.MessageCollection([], {
conversation: this,
});
this.messageCollection.on('change:errors', this.handleMessageError, this);
this.messageCollection.on('send-error', this.onMessageError, this);
this.listenTo(
this.messageCollection,
'add remove destroy content-changed',
this.debouncedUpdateLastMessage
);
this.listenTo(this.messageCollection, 'sent', this.updateLastMessage);
this.listenTo(this.messageCollection, 'send-error', this.updateLastMessage);
this.on('newmessage', this.onNewMessage);
this.on('change:profileKey', this.onChangeProfileKey);
// Listening for out-of-band data updates
this.on('delivered', this.updateAndMerge);
this.on('read', this.updateAndMerge);
this.on('expiration-change', this.updateAndMerge);
this.on('expired', this.onExpired);
const sealedSender = this.get('sealedSender');
if (sealedSender === undefined) {
this.set({ sealedSender: SEALED_SENDER.UNKNOWN });
@ -1238,64 +1213,10 @@ export class ConversationModel extends window.Backbone
);
}
async updateAndMerge(message: MessageModel): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.debouncedUpdateLastMessage!();
const mergeMessage = () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const existing = this.messageCollection!.get(message.id);
if (!existing) {
return;
}
existing.merge(message.attributes);
};
await this.inProgressFetch;
mergeMessage();
}
async onExpired(message: MessageModel): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.debouncedUpdateLastMessage!();
const removeMessage = () => {
const { id } = message;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const existing = this.messageCollection!.get(id);
if (!existing) {
return;
}
window.log.info('Remove expired message from collection', {
sentAt: existing.get('sent_at'),
});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.messageCollection!.remove(id);
existing.trigger('expired');
existing.cleanup();
// An expired message only counts as decrementing the message count, not
// the sent message count
this.decrementMessageCount();
};
// If a fetch is in progress, then we need to wait until that's complete to
// do this removal. Otherwise we could remove from messageCollection, then
// the async database fetch could include the removed message.
await this.inProgressFetch;
removeMessage();
}
async onNewMessage(message: WhatIsThis): Promise<void> {
const uuid = message.get ? message.get('sourceUuid') : message.sourceUuid;
const e164 = message.get ? message.get('source') : message.source;
const sourceDevice = message.get
? message.get('sourceDevice')
: message.sourceDevice;
async onNewMessage(message: MessageModel): Promise<void> {
const uuid = message.get('sourceUuid');
const e164 = message.get('source');
const sourceDevice = message.get('sourceDevice');
const sourceId = window.ConversationController.ensureContactIds({
uuid,
@ -1306,33 +1227,26 @@ export class ConversationModel extends window.Backbone
// Clear typing indicator for a given contact if we receive a message from them
this.clearContactTypingTimer(typingToken);
this.addSingleMessage(message);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.debouncedUpdateLastMessage!();
}
// For outgoing messages, we can call this directly. We're already loaded.
addSingleMessage(message: MessageModel): MessageModel {
const { id } = message;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const existing = this.messageCollection!.get(id);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const model = this.messageCollection!.add(message, { merge: true });
// TODO use MessageUpdater.setToExpire
model.setToExpire();
message.setToExpire();
if (!existing) {
const { messagesAdded } = window.reduxActions.conversations;
const isNewMessage = true;
messagesAdded(
this.id,
[model.getReduxData()],
isNewMessage,
window.isActive()
);
}
const { messagesAdded } = window.reduxActions.conversations;
const isNewMessage = true;
messagesAdded(
this.id,
[message.getReduxData()],
isNewMessage,
window.isActive()
);
return model;
return message;
}
// For incoming messages, they might arrive while we're in the middle of a bulk fetch
@ -2119,10 +2033,6 @@ export class ConversationModel extends window.Backbone
return true;
}
onMessageError(): void {
this.updateVerified();
}
async safeGetVerified(): Promise<number> {
const promise = window.textsecure.storage.protocol.getVerified(this.id);
return promise.catch(
@ -3629,12 +3539,14 @@ export class ConversationModel extends window.Backbone
if (isDirectConversation(this.attributes)) {
messageWithSchema.destination = destination;
}
const attributes: MessageModel = {
const attributes: MessageAttributesType = {
...messageWithSchema,
id: window.getGuid(),
};
const model = this.addSingleMessage(attributes);
const model = this.addSingleMessage(
new window.Whisper.Message(attributes)
);
if (sticker) {
await addStickerPackReference(model.id, sticker.packId);
}
@ -4205,16 +4117,17 @@ export class ConversationModel extends window.Backbone
return message;
}
async addMessageHistoryDisclaimer(): Promise<MessageModel> {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const lastMessage = this.messageCollection!.last();
if (lastMessage && lastMessage.get('type') === 'message-history-unsynced') {
// We do not need another message history disclaimer
return lastMessage;
}
async addMessageHistoryDisclaimer(): Promise<void> {
const timestamp = Date.now();
if (this.hasAddedHistoryDisclaimer) {
window.log.warn(
`addMessageHistoryDisclaimer/${this.idForLogging()}: Refusing to add another this session`
);
return;
}
this.hasAddedHistoryDisclaimer = true;
const model = new window.Whisper.Message(({
type: 'message-history-unsynced',
// Even though this isn't reflected to the user, we want to place the last seen
@ -4238,8 +4151,6 @@ export class ConversationModel extends window.Backbone
const message = window.MessageController.register(id, model);
this.addSingleMessage(message);
return message;
}
isSearchable(): boolean {
@ -4816,9 +4727,6 @@ export class ConversationModel extends window.Backbone
}
async destroyMessages(): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.messageCollection!.reset([]);
this.set({
lastMessage: null,
timestamp: null,

View file

@ -284,7 +284,6 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
this.on('change:expirationStartTimestamp', this.setToExpire);
this.on('change:expireTimer', this.setToExpire);
this.on('unload', this.unload);
this.on('expired', this.onExpired);
this.setToExpire();
this.on('change', this.notifyRedux);
@ -517,9 +516,6 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
errors: errorsForContact,
isOutgoingKeyError,
isUnidentifiedDelivery,
onSendAnyway: () =>
this.trigger('force-send', { contactId: id, messageId: this.id }),
onShowSafetyNumber: () => this.trigger('show-identity', id),
};
}
);
@ -1797,6 +1793,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
async cleanup(): Promise<void> {
const { messageDeleted } = window.reduxActions.conversations;
messageDeleted(this.id, this.get('conversationId'));
this.getConversation()?.debouncedUpdateLastMessage?.();
window.MessageController.unregister(this.id);
this.unload();
await this.deleteData();
@ -1953,7 +1952,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
preview: [],
...additionalProperties,
});
this.trigger('content-changed');
this.getConversation()?.debouncedUpdateLastMessage?.();
if (shouldPersist) {
await window.Signal.Data.saveMessage(this.attributes, {
@ -2625,10 +2624,17 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
async send(
promise: Promise<CallbackResultType | void | null>
): Promise<void | Array<void>> {
this.trigger('pending');
const conversation = this.getConversation();
const updateLeftPane = conversation?.debouncedUpdateLastMessage;
if (updateLeftPane) {
updateLeftPane();
}
return (promise as Promise<CallbackResultType>)
.then(async result => {
this.trigger('done');
if (updateLeftPane) {
updateLeftPane();
}
// This is used by sendSyncMessage, then set to null
if (result.dataMessage) {
@ -2652,11 +2658,15 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
});
}
this.trigger('sent', this);
if (updateLeftPane) {
updateLeftPane();
}
this.sendSyncMessage();
})
.catch((result: CustomError | CallbackResultType) => {
this.trigger('done');
if (updateLeftPane) {
updateLeftPane();
}
if ('dataMessage' in result && result.dataMessage) {
this.set({ dataMessage: result.dataMessage });
@ -2756,7 +2766,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
);
}
this.trigger('send-error', this.get('errors'));
if (updateLeftPane) {
updateLeftPane();
}
return Promise.all(promises);
});
@ -2820,6 +2832,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const conv = this.getConversation()!;
this.set({ dataMessage });
const updateLeftPane = conv?.debouncedUpdateLastMessage;
try {
this.set({
// These are the same as a normal send()
@ -2846,13 +2860,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
await window.Signal.Data.saveMessage(this.attributes, {
Message: window.Whisper.Message,
});
this.trigger('done');
const errors = this.get('errors');
if (errors) {
this.trigger('send-error', errors);
} else {
this.trigger('sent');
if (updateLeftPane) {
updateLeftPane();
}
}
}