Disallow conversation model creation during import
This commit is contained in:
parent
65055fd475
commit
3b78c9885a
5 changed files with 60 additions and 8 deletions
|
@ -150,6 +150,7 @@ export function start(): void {
|
||||||
|
|
||||||
export class ConversationController {
|
export class ConversationController {
|
||||||
#_initialFetchComplete = false;
|
#_initialFetchComplete = false;
|
||||||
|
#isReadOnly = false;
|
||||||
|
|
||||||
private _initialPromise: undefined | Promise<void>;
|
private _initialPromise: undefined | Promise<void>;
|
||||||
|
|
||||||
|
@ -291,6 +292,10 @@ export class ConversationController {
|
||||||
return conversation;
|
return conversation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.#isReadOnly) {
|
||||||
|
throw new Error('ConversationController is read-only');
|
||||||
|
}
|
||||||
|
|
||||||
const id = generateUuid();
|
const id = generateUuid();
|
||||||
|
|
||||||
if (type === 'group') {
|
if (type === 'group') {
|
||||||
|
@ -1299,6 +1304,16 @@ export class ConversationController {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setReadOnly(value: boolean): void {
|
||||||
|
if (this.#isReadOnly === value) {
|
||||||
|
log.warn(`ConversationController: already at readOnly=${value}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(`ConversationController: readOnly=${value}`);
|
||||||
|
this.#isReadOnly = value;
|
||||||
|
}
|
||||||
|
|
||||||
reset(): void {
|
reset(): void {
|
||||||
delete this._initialPromise;
|
delete this._initialPromise;
|
||||||
this.#_initialFetchComplete = false;
|
this.#_initialFetchComplete = false;
|
||||||
|
|
|
@ -1513,10 +1513,10 @@ export async function startApp(): Promise<void> {
|
||||||
});
|
});
|
||||||
|
|
||||||
void updateExpiringMessagesService();
|
void updateExpiringMessagesService();
|
||||||
void tapToViewMessagesDeletionService.update();
|
tapToViewMessagesDeletionService.update();
|
||||||
window.Whisper.events.on('timetravel', () => {
|
window.Whisper.events.on('timetravel', () => {
|
||||||
void updateExpiringMessagesService();
|
void updateExpiringMessagesService();
|
||||||
void tapToViewMessagesDeletionService.update();
|
tapToViewMessagesDeletionService.update();
|
||||||
});
|
});
|
||||||
|
|
||||||
const isCoreDataValid = Boolean(
|
const isCoreDataValid = Boolean(
|
||||||
|
@ -1652,6 +1652,8 @@ export async function startApp(): Promise<void> {
|
||||||
|
|
||||||
const backupDownloadPath = window.storage.get('backupDownloadPath');
|
const backupDownloadPath = window.storage.get('backupDownloadPath');
|
||||||
if (backupDownloadPath) {
|
if (backupDownloadPath) {
|
||||||
|
tapToViewMessagesDeletionService.pause();
|
||||||
|
|
||||||
// Download backup before enabling request handler and storage service
|
// Download backup before enabling request handler and storage service
|
||||||
try {
|
try {
|
||||||
await backupsService.downloadAndImport({
|
await backupsService.downloadAndImport({
|
||||||
|
@ -1670,6 +1672,8 @@ export async function startApp(): Promise<void> {
|
||||||
log.error('afterStart: backup download failed, rejecting');
|
log.error('afterStart: backup download failed, rejecting');
|
||||||
backupReady.reject(error);
|
backupReady.reject(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
} finally {
|
||||||
|
tapToViewMessagesDeletionService.resume();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
backupReady.resolve();
|
backupReady.resolve();
|
||||||
|
|
|
@ -343,6 +343,7 @@ export class BackupImportStream extends Writable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset and reload conversations and storage again
|
// Reset and reload conversations and storage again
|
||||||
|
window.ConversationController.setReadOnly(false);
|
||||||
window.ConversationController.reset();
|
window.ConversationController.reset();
|
||||||
|
|
||||||
await window.ConversationController.load();
|
await window.ConversationController.load();
|
||||||
|
|
|
@ -350,6 +350,8 @@ export class BackupsService {
|
||||||
await DataWriter.disableMessageInsertTriggers();
|
await DataWriter.disableMessageInsertTriggers();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
window.ConversationController.setReadOnly(true);
|
||||||
|
|
||||||
const importStream = await BackupImportStream.create(backupType);
|
const importStream = await BackupImportStream.create(backupType);
|
||||||
if (backupType === BackupType.Ciphertext) {
|
if (backupType === BackupType.Ciphertext) {
|
||||||
const { aesKey, macKey } = getKeyMaterial(
|
const { aesKey, macKey } = getKeyMaterial(
|
||||||
|
@ -440,6 +442,7 @@ export class BackupsService {
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
|
window.ConversationController.setReadOnly(false);
|
||||||
this.#isRunning = false;
|
this.#isRunning = false;
|
||||||
await DataWriter.enableMessageInsertTriggersAndBackfill();
|
await DataWriter.enableMessageInsertTriggersAndBackfill();
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { strictAssert } from '../util/assert';
|
||||||
import { toBoundedDate } from '../util/timestamp';
|
import { toBoundedDate } from '../util/timestamp';
|
||||||
import { getMessageIdForLogging } from '../util/idForLogging';
|
import { getMessageIdForLogging } from '../util/idForLogging';
|
||||||
import { eraseMessageContents } from '../util/cleanup';
|
import { eraseMessageContents } from '../util/cleanup';
|
||||||
|
import { drop } from '../util/drop';
|
||||||
import { MessageModel } from '../models/messages';
|
import { MessageModel } from '../models/messages';
|
||||||
|
|
||||||
async function eraseTapToViewMessages() {
|
async function eraseTapToViewMessages() {
|
||||||
|
@ -53,12 +54,38 @@ async function eraseTapToViewMessages() {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TapToViewMessagesDeletionService {
|
class TapToViewMessagesDeletionService {
|
||||||
public update: () => Promise<void>;
|
|
||||||
|
|
||||||
#timeout?: ReturnType<typeof setTimeout>;
|
#timeout?: ReturnType<typeof setTimeout>;
|
||||||
|
#isPaused = false;
|
||||||
|
#debouncedUpdate = debounce(this.#checkTapToViewMessages);
|
||||||
|
|
||||||
constructor() {
|
update() {
|
||||||
this.update = debounce(this.#checkTapToViewMessages, 1000);
|
drop(this.#debouncedUpdate());
|
||||||
|
}
|
||||||
|
|
||||||
|
pause(): void {
|
||||||
|
if (this.#isPaused) {
|
||||||
|
window.SignalContext.log.warn('checkTapToViewMessages: already paused');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.SignalContext.log.info('checkTapToViewMessages: pause');
|
||||||
|
|
||||||
|
this.#isPaused = true;
|
||||||
|
clearTimeoutIfNecessary(this.#timeout);
|
||||||
|
this.#timeout = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
resume(): void {
|
||||||
|
if (!this.#isPaused) {
|
||||||
|
window.SignalContext.log.warn('checkTapToViewMessages: not paused');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.SignalContext.log.info('checkTapToViewMessages: resuming');
|
||||||
|
this.#isPaused = false;
|
||||||
|
|
||||||
|
this.#debouncedUpdate.cancel();
|
||||||
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
async #checkTapToViewMessages() {
|
async #checkTapToViewMessages() {
|
||||||
|
@ -89,8 +116,10 @@ class TapToViewMessagesDeletionService {
|
||||||
|
|
||||||
clearTimeoutIfNecessary(this.#timeout);
|
clearTimeoutIfNecessary(this.#timeout);
|
||||||
this.#timeout = setTimeout(async () => {
|
this.#timeout = setTimeout(async () => {
|
||||||
await eraseTapToViewMessages();
|
if (!this.#isPaused && !window.SignalContext.isTestOrMockEnvironment()) {
|
||||||
void this.update();
|
await eraseTapToViewMessages();
|
||||||
|
}
|
||||||
|
this.update();
|
||||||
}, wait);
|
}, wait);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue