Skip to content

Commit 0cc7994

Browse files
committed
fix: speed up expiration/deletion of messages by batching updates in UI
1 parent ad22482 commit 0cc7994

File tree

11 files changed

+191
-92
lines changed

11 files changed

+191
-92
lines changed

ts/components/conversation/message/message-item/GenericReadableMessage.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import _ from 'lodash';
88
import { Data } from '../../../../data/data';
99
import { MessageRenderingProps } from '../../../../models/messageType';
1010
import { getConversationController } from '../../../../session/conversations';
11-
import { messageExpired } from '../../../../state/ducks/conversations';
11+
import { messagesExpired } from '../../../../state/ducks/conversations';
1212
import {
1313
getGenericReadableMessageSelectorProps,
1414
getIsMessageSelected,
@@ -68,10 +68,12 @@ function useIsExpired(props: ExpiringProps) {
6868
await Data.removeMessage(messageId);
6969
if (convoId) {
7070
dispatch(
71-
messageExpired({
72-
conversationKey: convoId,
73-
messageId,
74-
})
71+
messagesExpired([
72+
{
73+
conversationKey: convoId,
74+
messageId,
75+
},
76+
])
7577
);
7678
const convo = getConversationController().get(convoId);
7779
convo?.updateLastMessage();

ts/data/data.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export const Data = {
139139
saveMessage,
140140
saveMessages,
141141
removeMessage,
142-
_removeMessages,
142+
removeMessagesByIds,
143143
getMessageIdsFromServerIds,
144144
getMessageById,
145145
getMessageBySenderAndSentAt,
@@ -390,9 +390,13 @@ async function removeMessage(id: string): Promise<void> {
390390
}
391391
}
392392

393-
// Note: this method will not clean up external files, just delete from SQL
394-
async function _removeMessages(ids: Array<string>): Promise<void> {
395-
await channels.removeMessage(ids);
393+
/**
394+
* Note: this method will not clean up external files, just delete from SQL.
395+
* File are cleaned up on app start if they are not linked to any messages
396+
*
397+
*/
398+
async function removeMessagesByIds(ids: Array<string>): Promise<void> {
399+
await channels.removeMessagesByIds(ids);
396400
}
397401

398402
async function getMessageIdsFromServerIds(
@@ -630,7 +634,7 @@ async function removeAllMessagesInConversation(conversationId: string): Promise<
630634
await Promise.all(messages.map(message => message.cleanup()));
631635

632636
// eslint-disable-next-line no-await-in-loop
633-
await channels.removeMessage(ids);
637+
await channels.removeMessagesByIds(ids);
634638
} while (messages.length > 0);
635639
}
636640

ts/data/dataInit.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const channelsToMake = new Set([
3838
'saveSeenMessageHashes',
3939
'saveMessages',
4040
'removeMessage',
41-
'_removeMessages',
41+
'removeMessagesByIds',
4242
'getUnreadByConversation',
4343
'markAllAsReadByConversationNoExpiration',
4444
'getUnreadCountByConversation',

ts/mains/main_renderer.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,18 +212,23 @@ async function start() {
212212
);
213213

214214
window.log.info(`Cleanup: Found ${messagesForCleanup.length} messages for cleanup`);
215+
216+
const idsToCleanUp: Array<string> = [];
215217
await Promise.all(
216-
messagesForCleanup.map(async (message: MessageModel) => {
218+
messagesForCleanup.map((message: MessageModel) => {
217219
const sentAt = message.get('sent_at');
218220

219221
if (message.hasErrors()) {
220222
return;
221223
}
222224

223225
window.log.info(`Cleanup: Deleting unsent message ${sentAt}`);
224-
await Data.removeMessage(message.id);
226+
idsToCleanUp.push(message.id);
225227
})
226228
);
229+
if (idsToCleanUp.length) {
230+
await Data.removeMessagesByIds(idsToCleanUp);
231+
}
227232
window.log.info('Cleanup: complete');
228233

229234
window.log.info('listening for registration events');

ts/models/conversation.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -248,12 +248,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
248248
await deleteExternalFilesOfConversation(this.attributes);
249249
}
250250

251-
public async onExpired(_message: MessageModel) {
252-
await this.updateLastMessage();
253-
254-
// removeMessage();
255-
}
256-
257251
public getGroupAdmins(): Array<string> {
258252
const groupAdmins = this.get('groupAdmins');
259253

@@ -1681,15 +1675,17 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
16811675
return this.get('type') === ConversationTypeEnum.GROUP;
16821676
}
16831677

1684-
public async removeMessage(messageId: any) {
1678+
public async removeMessage(messageId: string) {
16851679
await Data.removeMessage(messageId);
16861680
this.updateLastMessage();
16871681

16881682
window.inboxStore?.dispatch(
1689-
conversationActions.messageDeleted({
1690-
conversationKey: this.id,
1691-
messageId,
1692-
})
1683+
conversationActions.messagesDeleted([
1684+
{
1685+
conversationKey: this.id,
1686+
messageId,
1687+
},
1688+
])
16931689
);
16941690
}
16951691

ts/models/message.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
125125
throw new Error('A message always needs to have an conversationId.');
126126
}
127127

128-
// this.on('expired', this.onExpired);
129128
if (!attributes.skipTimerInit) {
130129
void this.setToExpire();
131130
}

ts/node/sql.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -945,21 +945,44 @@ function saveMessages(arrayOfMessages: Array<any>) {
945945
}
946946

947947
function removeMessage(id: string, instance?: BetterSqlite3.Database) {
948-
if (!Array.isArray(id)) {
949-
assertGlobalInstanceOrInstance(instance)
950-
.prepare(`DELETE FROM ${MESSAGES_TABLE} WHERE id = $id;`)
951-
.run({ id });
948+
if (!isString(id)) {
949+
throw new Error('removeMessage: only takes single message to delete!');
950+
952951
return;
953952
}
954953

955-
if (!id.length) {
956-
throw new Error('removeMessages: No ids to delete!');
954+
assertGlobalInstanceOrInstance(instance)
955+
.prepare(`DELETE FROM ${MESSAGES_TABLE} WHERE id = $id;`)
956+
.run({ id });
957+
}
958+
959+
function removeMessagesByIds(ids: Array<string>, instance?: BetterSqlite3.Database) {
960+
if (!Array.isArray(ids)) {
961+
throw new Error('removeMessagesByIds only allowed an array of strings');
962+
}
963+
964+
if (!ids.length) {
965+
throw new Error('removeMessagesByIds: No ids to delete!');
957966
}
958967

959968
// Our node interface doesn't seem to allow you to replace one single ? with an array
960969
assertGlobalInstanceOrInstance(instance)
961-
.prepare(`DELETE FROM ${MESSAGES_TABLE} WHERE id IN ( ${id.map(() => '?').join(', ')} );`)
962-
.run(id);
970+
.prepare(`DELETE FROM ${MESSAGES_TABLE} WHERE id IN ( ${ids.map(() => '?').join(', ')} );`)
971+
.run(ids);
972+
}
973+
974+
function removeAllMessagesInConversation(
975+
conversationId: string,
976+
instance?: BetterSqlite3.Database
977+
) {
978+
if (!conversationId) {
979+
return;
980+
}
981+
982+
// Our node interface doesn't seem to allow you to replace one single ? with an array
983+
assertGlobalInstanceOrInstance(instance)
984+
.prepare(`DELETE FROM ${MESSAGES_TABLE} WHERE conversationId = $conversationId`)
985+
.run({ conversationId });
963986
}
964987

965988
function getMessageIdsFromServerIds(serverIds: Array<string | number>, conversationId: string) {
@@ -2435,6 +2458,8 @@ export const sqlNode = {
24352458
updateLastHash,
24362459
saveMessages,
24372460
removeMessage,
2461+
removeMessagesByIds,
2462+
removeAllMessagesInConversation,
24382463
getUnreadByConversation,
24392464
markAllAsReadByConversationNoExpiration,
24402465
getUnreadCountByConversation,

ts/session/apis/open_group_api/sogsv3/sogsApiV3.ts

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import _, { compact, isArray, isNumber, isObject, pick } from 'lodash';
1+
import _, { compact, isArray, isEmpty, isNumber, isObject, pick } from 'lodash';
22
import { OpenGroupData } from '../../../../data/opengroups';
33
import { handleOpenGroupV4Message } from '../../../../receiver/opengroup';
44
import { OpenGroupRequestCommonType } from '../opengroupV2/ApiUtil';
@@ -35,6 +35,7 @@ import { ConversationTypeEnum } from '../../../../models/conversationAttributes'
3535
import { createSwarmMessageSentFromUs } from '../../../../models/messageFactory';
3636
import { Data } from '../../../../data/data';
3737
import { processMessagesUsingCache } from './sogsV3MutationCache';
38+
import { destroyMessagesAndUpdateRedux } from '../../../../util/expiringMessages';
3839

3940
/**
4041
* Get the convo matching those criteria and make sure it is an opengroup convo, or return null.
@@ -154,6 +155,7 @@ async function filterOutMessagesInvalidSignature(
154155
return signaturesValidMessages;
155156
}
156157

158+
let totalDeletedMessages = 0;
157159
const handleSogsV3DeletedMessages = async (
158160
messages: Array<OpenGroupMessageV4>,
159161
serverUrl: string,
@@ -164,29 +166,38 @@ const handleSogsV3DeletedMessages = async (
164166
if (!deletions.length) {
165167
return messages;
166168
}
169+
totalDeletedMessages += deletions.length;
170+
console.warn(
171+
JSON.stringify({
172+
totalDeletedMessages,
173+
})
174+
);
167175
const allIdsRemoved = deletions.map(m => m.id);
168176
try {
169177
const convoId = getOpenGroupV2ConversationId(serverUrl, roomId);
170178
const convo = getConversationController().get(convoId);
171179
const messageIds = await Data.getMessageIdsFromServerIds(allIdsRemoved, convo.id);
172180

173-
// we shouldn't get too many messages to delete at a time, so no need to add a function to remove multiple messages for now
174-
175-
await Promise.all(
176-
(messageIds || []).map(async id => {
177-
if (convo) {
178-
await convo.removeMessage(id);
179-
}
180-
await Data.removeMessage(id);
181-
})
182-
);
181+
if (messageIds && messageIds.length) {
182+
await destroyMessagesAndUpdateRedux(
183+
messageIds.map(messageId => ({
184+
conversationKey: convoId,
185+
messageId,
186+
}))
187+
);
188+
}
183189
} catch (e) {
184190
window?.log?.warn('handleDeletions failed:', e);
185191
}
186192
return exceptDeletion;
187193
};
188194

189-
// tslint:disable-next-line: cyclomatic-complexity
195+
// tslint:disable-next-line: one-variable-per-declaration
196+
let totalEmptyReactions = 0,
197+
totalMessagesWithResolvedBlindedIdsIfFound = 0,
198+
totalMessageReactions = 0;
199+
200+
// tslint:disable-next-line: max-func-body-length cyclomatic-complexity
190201
const handleMessagesResponseV4 = async (
191202
messages: Array<OpenGroupMessageV4>,
192203
serverUrl: string,
@@ -284,6 +295,9 @@ const handleMessagesResponseV4 = async (
284295

285296
const incomingMessageSeqNo = compact(messages.map(n => n.seqno));
286297
const maxNewMessageSeqNo = Math.max(...incomingMessageSeqNo);
298+
299+
totalMessagesWithResolvedBlindedIdsIfFound += messagesWithResolvedBlindedIdsIfFound.length;
300+
287301
for (let index = 0; index < messagesWithResolvedBlindedIdsIfFound.length; index++) {
288302
const msgToHandle = messagesWithResolvedBlindedIdsIfFound[index];
289303
try {
@@ -309,6 +323,18 @@ const handleMessagesResponseV4 = async (
309323
await OpenGroupData.saveV2OpenGroupRoom(roomInfosRefreshed);
310324

311325
const messagesWithReactions = messages.filter(m => m.reactions !== undefined);
326+
const messagesWithEmptyReactions = messagesWithReactions.filter(m => isEmpty(m.reactions));
327+
328+
totalMessageReactions += messagesWithReactions.length;
329+
totalEmptyReactions += messagesWithEmptyReactions.length;
330+
console.warn(
331+
JSON.stringify({
332+
totalMessagesWithResolvedBlindedIdsIfFound,
333+
totalMessageReactions,
334+
totalEmptyReactions,
335+
})
336+
);
337+
312338
if (messagesWithReactions.length > 0) {
313339
const conversationId = getOpenGroupV2ConversationId(serverUrl, roomId);
314340
const groupConvo = getConversationController().get(conversationId);
@@ -526,6 +552,7 @@ export const handleBatchPollResults = async (
526552
break;
527553
case 'pollInfo':
528554
await handlePollInfoResponse(subResponse.code, subResponse.body, serverUrl);
555+
529556
break;
530557
case 'inbox':
531558
await handleInboxOutboxMessages(subResponse.body, serverUrl, false);

ts/session/apis/open_group_api/sogsv3/sogsV3BatchPoll.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ const makeBatchRequestPayload = (
241241
method: 'GET',
242242
path: isNumber(options.messages.sinceSeqNo)
243243
? `/room/${options.messages.roomId}/messages/since/${options.messages.sinceSeqNo}?t=r&reactors=${Reactions.SOGSReactorsFetchCount}`
244-
: `/room/${options.messages.roomId}/messages/recent?reactors=${Reactions.SOGSReactorsFetchCount}`,
244+
: // : `/room/${options.messages.roomId}/messages/since/180000?t=r&reactors=${Reactions.SOGSReactorsFetchCount}`,
245+
`/room/${options.messages.roomId}/messages/recent?reactors=${Reactions.SOGSReactorsFetchCount}`,
245246
};
246247
}
247248
break;

0 commit comments

Comments
 (0)