signal-desktop/ts/messages/migrateMessageData.ts

133 lines
3.5 KiB
TypeScript
Raw Normal View History

2023-01-03 19:55:46 +00:00
// Copyright 2018 Signal Messenger, LLC
2020-10-30 20:34:04 +00:00
// SPDX-License-Identifier: AGPL-3.0-only
import { isFunction, isNumber } from 'lodash';
import pMap from 'p-map';
import { CURRENT_SCHEMA_VERSION } from '../types/Message2';
import { isNotNil } from '../util/isNotNil';
import type { MessageAttributesType } from '../model-types.d';
import type { UUIDStringType } from '../types/UUID';
import * as Errors from '../types/errors';
const MAX_CONCURRENCY = 5;
/**
* Ensures that messages in database are at the right schema.
*/
export async function migrateMessageData({
numMessagesPerBatch,
2018-03-21 23:37:39 +00:00
upgradeMessageSchema,
getMessagesNeedingUpgrade,
saveMessages,
maxVersion = CURRENT_SCHEMA_VERSION,
}: Readonly<{
numMessagesPerBatch: number;
upgradeMessageSchema: (
message: MessageAttributesType,
options: { maxVersion: number }
) => Promise<MessageAttributesType>;
getMessagesNeedingUpgrade: (
limit: number,
options: { maxVersion: number }
) => Promise<Array<MessageAttributesType>>;
saveMessages: (
data: ReadonlyArray<MessageAttributesType>,
options: { ourUuid: UUIDStringType }
) => Promise<void>;
maxVersion?: number;
}>): Promise<
| {
done: true;
numProcessed: 0;
}
| {
done: boolean;
numProcessed: number;
fetchDuration: number;
upgradeDuration: number;
saveDuration: number;
totalDuration: number;
}
> {
if (!isNumber(numMessagesPerBatch)) {
2018-04-11 19:44:52 +00:00
throw new TypeError("'numMessagesPerBatch' is required");
2018-03-21 23:37:39 +00:00
}
if (!isFunction(upgradeMessageSchema)) {
2018-04-11 19:44:52 +00:00
throw new TypeError("'upgradeMessageSchema' is required");
2018-03-21 23:37:39 +00:00
}
const startTime = Date.now();
2018-03-27 16:19:55 +00:00
const fetchStartTime = Date.now();
2018-09-21 01:47:19 +00:00
let messagesRequiringSchemaUpgrade;
try {
messagesRequiringSchemaUpgrade = await getMessagesNeedingUpgrade(
numMessagesPerBatch,
{ maxVersion }
2018-09-21 01:47:19 +00:00
);
} catch (error) {
window.SignalContext.log.error(
'migrateMessageData.getMessagesNeedingUpgrade error:',
Errors.toLogFormat(error)
2018-09-21 01:47:19 +00:00
);
return {
done: true,
numProcessed: 0,
};
}
2018-03-27 16:19:55 +00:00
const fetchDuration = Date.now() - fetchStartTime;
2018-03-21 23:37:39 +00:00
2018-03-27 16:19:55 +00:00
const upgradeStartTime = Date.now();
const failedMessages = new Array<MessageAttributesType>();
const upgradedMessages = (
await pMap(
messagesRequiringSchemaUpgrade,
async message => {
try {
return await upgradeMessageSchema(message, { maxVersion });
} catch (error) {
window.SignalContext.log.error(
'migrateMessageData.upgradeMessageSchema error:',
Errors.toLogFormat(error)
);
failedMessages.push(message);
return undefined;
}
},
{ concurrency: MAX_CONCURRENCY }
)
).filter(isNotNil);
2018-03-27 16:19:55 +00:00
const upgradeDuration = Date.now() - upgradeStartTime;
2018-03-21 23:37:39 +00:00
2018-03-27 16:19:55 +00:00
const saveStartTime = Date.now();
const ourUuid = window.textsecure.storage.user.getCheckedUuid().toString();
await saveMessages(
[
...upgradedMessages,
// Increment migration attempts
...failedMessages.map(message => ({
...message,
schemaMigrationAttempts: (message.schemaMigrationAttempts ?? 0) + 1,
})),
],
{ ourUuid }
2021-12-20 21:04:02 +00:00
);
2018-03-27 16:19:55 +00:00
const saveDuration = Date.now() - saveStartTime;
2018-03-21 23:37:39 +00:00
const totalDuration = Date.now() - startTime;
const numProcessed = messagesRequiringSchemaUpgrade.length;
const done = numProcessed < numMessagesPerBatch;
2018-03-21 23:37:39 +00:00
return {
done,
2018-03-21 23:37:39 +00:00
numProcessed,
fetchDuration,
upgradeDuration,
saveDuration,
totalDuration,
};
}