Further improve in-memory transactions in MessageReceiver
This commit is contained in:
parent
7c07fdd589
commit
7b164fdf91
1 changed files with 72 additions and 34 deletions
|
@ -135,6 +135,11 @@ type LockedStores = {
|
||||||
readonly zone?: Zone;
|
readonly zone?: Zone;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum TaskType {
|
||||||
|
Encrypted = 'Encrypted',
|
||||||
|
Decrypted = 'Decrypted',
|
||||||
|
}
|
||||||
|
|
||||||
class MessageReceiverInner extends EventTarget {
|
class MessageReceiverInner extends EventTarget {
|
||||||
_onClose?: (ev: any) => Promise<void>;
|
_onClose?: (ev: any) => Promise<void>;
|
||||||
|
|
||||||
|
@ -162,7 +167,9 @@ class MessageReceiverInner extends EventTarget {
|
||||||
|
|
||||||
password: string;
|
password: string;
|
||||||
|
|
||||||
pendingQueue: PQueue;
|
encryptedQueue: PQueue;
|
||||||
|
|
||||||
|
decryptedQueue: PQueue;
|
||||||
|
|
||||||
retryCachedTimeout: any;
|
retryCachedTimeout: any;
|
||||||
|
|
||||||
|
@ -227,9 +234,18 @@ class MessageReceiverInner extends EventTarget {
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
this.incomingQueue = new PQueue({ concurrency: 1, timeout: 1000 * 60 * 2 });
|
this.incomingQueue = new PQueue({ concurrency: 1, timeout: 1000 * 60 * 2 });
|
||||||
this.pendingQueue = new PQueue({ concurrency: 1, timeout: 1000 * 60 * 2 });
|
|
||||||
this.appQueue = new PQueue({ concurrency: 1, timeout: 1000 * 60 * 2 });
|
this.appQueue = new PQueue({ concurrency: 1, timeout: 1000 * 60 * 2 });
|
||||||
|
|
||||||
|
// All envelopes start in encryptedQueue and progress to decryptedQueue
|
||||||
|
this.encryptedQueue = new PQueue({
|
||||||
|
concurrency: 1,
|
||||||
|
timeout: 1000 * 60 * 2,
|
||||||
|
});
|
||||||
|
this.decryptedQueue = new PQueue({
|
||||||
|
concurrency: 1,
|
||||||
|
timeout: 1000 * 60 * 2,
|
||||||
|
});
|
||||||
|
|
||||||
this.cacheAddBatcher = createBatcher<CacheAddItemType>({
|
this.cacheAddBatcher = createBatcher<CacheAddItemType>({
|
||||||
name: 'MessageReceiver.cacheAddBatcher',
|
name: 'MessageReceiver.cacheAddBatcher',
|
||||||
wait: 75,
|
wait: 75,
|
||||||
|
@ -268,7 +284,7 @@ class MessageReceiverInner extends EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We always process our cache before processing a new websocket message
|
// We always process our cache before processing a new websocket message
|
||||||
this.pendingQueue.add(async () => this.queueAllCached());
|
this.encryptedQueue.add(async () => this.queueAllCached());
|
||||||
|
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
if (this.hasConnected) {
|
if (this.hasConnected) {
|
||||||
|
@ -514,20 +530,21 @@ class MessageReceiverInner extends EventTarget {
|
||||||
return messageAgeSec;
|
return messageAgeSec;
|
||||||
}
|
}
|
||||||
|
|
||||||
async addToQueue<T>(task: () => Promise<T>): Promise<T> {
|
async addToQueue<T>(task: () => Promise<T>, taskType: TaskType): Promise<T> {
|
||||||
|
if (taskType === TaskType.Encrypted) {
|
||||||
this.count += 1;
|
this.count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
const promise = this.pendingQueue.add(task);
|
const queue =
|
||||||
|
taskType === TaskType.Encrypted
|
||||||
|
? this.encryptedQueue
|
||||||
|
: this.decryptedQueue;
|
||||||
|
|
||||||
const { count } = this;
|
try {
|
||||||
|
return await queue.add(task);
|
||||||
const update = () => {
|
} finally {
|
||||||
this.updateProgress(count);
|
this.updateProgress(this.count);
|
||||||
};
|
}
|
||||||
|
|
||||||
promise.then(update, update);
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasEmptied(): boolean {
|
hasEmptied(): boolean {
|
||||||
|
@ -549,7 +566,7 @@ class MessageReceiverInner extends EventTarget {
|
||||||
this.maybeScheduleRetryTimeout();
|
this.maybeScheduleRetryTimeout();
|
||||||
};
|
};
|
||||||
|
|
||||||
const waitForPendingQueue = async () => {
|
const waitForDecryptedQueue = async () => {
|
||||||
window.log.info(
|
window.log.info(
|
||||||
"MessageReceiver: finished processing messages after 'empty', now waiting for application"
|
"MessageReceiver: finished processing messages after 'empty', now waiting for application"
|
||||||
);
|
);
|
||||||
|
@ -558,8 +575,12 @@ class MessageReceiverInner extends EventTarget {
|
||||||
this.appQueue.add(emitEmpty);
|
this.appQueue.add(emitEmpty);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const waitForEncryptedQueue = async () => {
|
||||||
|
this.addToQueue(waitForDecryptedQueue, TaskType.Decrypted);
|
||||||
|
};
|
||||||
|
|
||||||
const waitForIncomingQueue = () => {
|
const waitForIncomingQueue = () => {
|
||||||
this.addToQueue(waitForPendingQueue);
|
this.addToQueue(waitForEncryptedQueue, TaskType.Encrypted);
|
||||||
|
|
||||||
// Note: this.count is used in addToQueue
|
// Note: this.count is used in addToQueue
|
||||||
// Resetting count so everything from the websocket after this starts at zero
|
// Resetting count so everything from the websocket after this starts at zero
|
||||||
|
@ -575,10 +596,13 @@ class MessageReceiverInner extends EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
async drain() {
|
async drain() {
|
||||||
const waitForIncomingQueue = async () =>
|
const waitForEncryptedQueue = async () =>
|
||||||
this.addToQueue(async () => {
|
this.addToQueue(async () => {
|
||||||
window.log.info('drained');
|
window.log.info('drained');
|
||||||
});
|
}, TaskType.Decrypted);
|
||||||
|
|
||||||
|
const waitForIncomingQueue = async () =>
|
||||||
|
this.addToQueue(waitForEncryptedQueue, TaskType.Encrypted);
|
||||||
|
|
||||||
return this.incomingQueue.add(waitForIncomingQueue);
|
return this.incomingQueue.add(waitForIncomingQueue);
|
||||||
}
|
}
|
||||||
|
@ -656,15 +680,13 @@ class MessageReceiverInner extends EventTarget {
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Cached decrypted value was not a string!');
|
throw new Error('Cached decrypted value was not a string!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maintain invariant: encrypted queue => decrypted queue
|
||||||
|
this.addToQueue(async () => {
|
||||||
this.queueDecryptedEnvelope(envelope, payloadPlaintext);
|
this.queueDecryptedEnvelope(envelope, payloadPlaintext);
|
||||||
|
}, TaskType.Encrypted);
|
||||||
} else {
|
} else {
|
||||||
this.queueEnvelope(
|
this.queueCachedEnvelope(envelope);
|
||||||
{
|
|
||||||
sessionStore: new Sessions(),
|
|
||||||
identityKeyStore: new IdentityKeys(),
|
|
||||||
},
|
|
||||||
envelope
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
window.log.error(
|
window.log.error(
|
||||||
|
@ -713,7 +735,7 @@ class MessageReceiverInner extends EventTarget {
|
||||||
if (this.isEmptied) {
|
if (this.isEmptied) {
|
||||||
this.clearRetryTimeout();
|
this.clearRetryTimeout();
|
||||||
this.retryCachedTimeout = setTimeout(() => {
|
this.retryCachedTimeout = setTimeout(() => {
|
||||||
this.pendingQueue.add(async () => this.queueAllCached());
|
this.encryptedQueue.add(async () => this.queueAllCached());
|
||||||
}, RETRY_TIMEOUT);
|
}, RETRY_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -790,7 +812,7 @@ class MessageReceiverInner extends EventTarget {
|
||||||
await Promise.all<void>(
|
await Promise.all<void>(
|
||||||
items.map(async ({ data, envelope }) => {
|
items.map(async ({ data, envelope }) => {
|
||||||
try {
|
try {
|
||||||
const plaintext = await this.queueEnvelope(
|
const plaintext = await this.queueEncryptedEnvelope(
|
||||||
{ sessionStore, identityKeyStore, zone },
|
{ sessionStore, identityKeyStore, zone },
|
||||||
envelope
|
envelope
|
||||||
);
|
);
|
||||||
|
@ -924,7 +946,7 @@ class MessageReceiverInner extends EventTarget {
|
||||||
task,
|
task,
|
||||||
`queueEncryptedEnvelope ${id}`
|
`queueEncryptedEnvelope ${id}`
|
||||||
);
|
);
|
||||||
const promise = this.addToQueue(taskWithTimeout);
|
const promise = this.addToQueue(taskWithTimeout, TaskType.Decrypted);
|
||||||
|
|
||||||
return promise.catch(error => {
|
return promise.catch(error => {
|
||||||
window.log.error(
|
window.log.error(
|
||||||
|
@ -935,7 +957,7 @@ class MessageReceiverInner extends EventTarget {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async queueEnvelope(
|
async queueEncryptedEnvelope(
|
||||||
stores: LockedStores,
|
stores: LockedStores,
|
||||||
envelope: EnvelopeClass
|
envelope: EnvelopeClass
|
||||||
): Promise<ArrayBuffer | undefined> {
|
): Promise<ArrayBuffer | undefined> {
|
||||||
|
@ -945,14 +967,14 @@ class MessageReceiverInner extends EventTarget {
|
||||||
const task = this.decryptEnvelope.bind(this, stores, envelope);
|
const task = this.decryptEnvelope.bind(this, stores, envelope);
|
||||||
const taskWithTimeout = window.textsecure.createTaskWithTimeout(
|
const taskWithTimeout = window.textsecure.createTaskWithTimeout(
|
||||||
task,
|
task,
|
||||||
`queueEnvelope ${id}`
|
`queueEncryptedEnvelope ${id}`
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await this.addToQueue(taskWithTimeout);
|
return await this.addToQueue(taskWithTimeout, TaskType.Encrypted);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const args = [
|
const args = [
|
||||||
'queueEnvelope error handling envelope',
|
'queueEncryptedEnvelope error handling envelope',
|
||||||
this.getEnvelopeId(envelope),
|
this.getEnvelopeId(envelope),
|
||||||
':',
|
':',
|
||||||
error && error.extra ? JSON.stringify(error.extra) : '',
|
error && error.extra ? JSON.stringify(error.extra) : '',
|
||||||
|
@ -967,6 +989,22 @@ class MessageReceiverInner extends EventTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async queueCachedEnvelope(envelope: EnvelopeClass): Promise<void> {
|
||||||
|
const plaintext = await this.queueEncryptedEnvelope(
|
||||||
|
{
|
||||||
|
sessionStore: new Sessions(),
|
||||||
|
identityKeyStore: new IdentityKeys(),
|
||||||
|
},
|
||||||
|
envelope
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!plaintext) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.queueDecryptedEnvelope(envelope, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
// Called after `decryptEnvelope` decrypted the message.
|
// Called after `decryptEnvelope` decrypted the message.
|
||||||
async handleDecryptedEnvelope(
|
async handleDecryptedEnvelope(
|
||||||
envelope: EnvelopeClass,
|
envelope: EnvelopeClass,
|
||||||
|
|
Loading…
Reference in a new issue