168 lines
4.7 KiB
JavaScript
168 lines
4.7 KiB
JavaScript
/* global window, Whisper, textsecure */
|
|
|
|
const { isFunction } = require('lodash');
|
|
|
|
const MessageDataMigrator = require('./messages_data_migrator');
|
|
const {
|
|
run,
|
|
getLatestVersion,
|
|
getDatabase,
|
|
} = require('./migrations/migrations');
|
|
|
|
const MESSAGE_MINIMUM_VERSION = 7;
|
|
|
|
module.exports = {
|
|
doesDatabaseExist,
|
|
mandatoryMessageUpgrade,
|
|
MESSAGE_MINIMUM_VERSION,
|
|
migrateAllToSQLCipher,
|
|
removeDatabase,
|
|
runMigrations,
|
|
};
|
|
|
|
async function runMigrations() {
|
|
window.log.info('Run migrations on database with attachment data');
|
|
await run({
|
|
Backbone: window.Backbone,
|
|
logger: window.log,
|
|
});
|
|
|
|
Whisper.Database.migrations[0].version = getLatestVersion();
|
|
}
|
|
|
|
async function mandatoryMessageUpgrade({ upgradeMessageSchema } = {}) {
|
|
if (!isFunction(upgradeMessageSchema)) {
|
|
throw new Error(
|
|
'mandatoryMessageUpgrade: upgradeMessageSchema must be a function!'
|
|
);
|
|
}
|
|
|
|
const NUM_MESSAGES_PER_BATCH = 10;
|
|
window.log.info(
|
|
'upgradeMessages: Mandatory message schema upgrade started.',
|
|
`Target version: ${MESSAGE_MINIMUM_VERSION}`
|
|
);
|
|
|
|
let isMigrationWithoutIndexComplete = false;
|
|
while (!isMigrationWithoutIndexComplete) {
|
|
const database = getDatabase();
|
|
// eslint-disable-next-line no-await-in-loop
|
|
const batchWithoutIndex = await MessageDataMigrator.processNextBatchWithoutIndex(
|
|
{
|
|
databaseName: database.name,
|
|
minDatabaseVersion: database.version,
|
|
numMessagesPerBatch: NUM_MESSAGES_PER_BATCH,
|
|
upgradeMessageSchema,
|
|
maxVersion: MESSAGE_MINIMUM_VERSION,
|
|
BackboneMessage: Whisper.Message,
|
|
saveMessage: window.Signal.Data.saveLegacyMessage,
|
|
}
|
|
);
|
|
window.log.info(
|
|
'upgradeMessages: upgrade without index',
|
|
batchWithoutIndex
|
|
);
|
|
isMigrationWithoutIndexComplete = batchWithoutIndex.done;
|
|
}
|
|
window.log.info('upgradeMessages: upgrade without index complete!');
|
|
|
|
let isMigrationWithIndexComplete = false;
|
|
while (!isMigrationWithIndexComplete) {
|
|
// eslint-disable-next-line no-await-in-loop
|
|
const batchWithIndex = await MessageDataMigrator.processNext({
|
|
BackboneMessage: Whisper.Message,
|
|
BackboneMessageCollection: Whisper.MessageCollection,
|
|
numMessagesPerBatch: NUM_MESSAGES_PER_BATCH,
|
|
upgradeMessageSchema,
|
|
getMessagesNeedingUpgrade:
|
|
window.Signal.Data.getLegacyMessagesNeedingUpgrade,
|
|
saveMessage: window.Signal.Data.saveLegacyMessage,
|
|
maxVersion: MESSAGE_MINIMUM_VERSION,
|
|
});
|
|
window.log.info('upgradeMessages: upgrade with index', batchWithIndex);
|
|
isMigrationWithIndexComplete = batchWithIndex.done;
|
|
}
|
|
window.log.info('upgradeMessages: upgrade with index complete!');
|
|
|
|
window.log.info('upgradeMessages: Message schema upgrade complete');
|
|
}
|
|
|
|
async function migrateAllToSQLCipher({ writeNewAttachmentData, Views } = {}) {
|
|
if (!isFunction(writeNewAttachmentData)) {
|
|
throw new Error(
|
|
'migrateAllToSQLCipher: writeNewAttachmentData must be a function'
|
|
);
|
|
}
|
|
if (!Views) {
|
|
throw new Error('migrateAllToSQLCipher: Views must be provided!');
|
|
}
|
|
|
|
let totalMessages;
|
|
const db = await Whisper.Database.open();
|
|
|
|
function showMigrationStatus(current) {
|
|
const status = `${current}/${totalMessages}`;
|
|
Views.Initialization.setMessage(
|
|
window.i18n('migratingToSQLCipher', [status])
|
|
);
|
|
}
|
|
|
|
try {
|
|
totalMessages = await MessageDataMigrator.getNumMessages({
|
|
connection: db,
|
|
});
|
|
} catch (error) {
|
|
window.log.error(
|
|
'background.getNumMessages error:',
|
|
error && error.stack ? error.stack : error
|
|
);
|
|
totalMessages = 0;
|
|
}
|
|
|
|
if (totalMessages) {
|
|
window.log.info(`About to migrate ${totalMessages} messages`);
|
|
showMigrationStatus(0);
|
|
} else {
|
|
window.log.info('About to migrate non-messages');
|
|
}
|
|
|
|
await window.Signal.migrateToSQL({
|
|
db,
|
|
clearStores: Whisper.Database.clearStores,
|
|
handleDOMException: Whisper.Database.handleDOMException,
|
|
arrayBufferToString: textsecure.MessageReceiver.arrayBufferToStringBase64,
|
|
countCallback: count => {
|
|
window.log.info(`Migration: ${count} messages complete`);
|
|
showMigrationStatus(count);
|
|
},
|
|
writeNewAttachmentData,
|
|
});
|
|
|
|
db.close();
|
|
}
|
|
|
|
async function doesDatabaseExist() {
|
|
return new Promise((resolve, reject) => {
|
|
const { id } = Whisper.Database;
|
|
const req = window.indexedDB.open(id);
|
|
|
|
let existed = true;
|
|
|
|
req.onerror = reject;
|
|
req.onsuccess = () => {
|
|
req.result.close();
|
|
resolve(existed);
|
|
};
|
|
req.onupgradeneeded = () => {
|
|
if (req.result.version === 1) {
|
|
existed = false;
|
|
window.indexedDB.deleteDatabase(id);
|
|
}
|
|
};
|
|
});
|
|
}
|
|
|
|
function removeDatabase() {
|
|
window.log.info(`Deleting IndexedDB database '${Whisper.Database.id}'`);
|
|
window.indexedDB.deleteDatabase(Whisper.Database.id);
|
|
}
|