1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-12-01 04:43:29 +03:00

Reorganize key backup flow

This will allow the key backup flow to propagate errors for things like version
mismatches more easily.

In addition, it raises the limit of keys sent per request from 10 to 200 to cut
down on the number of requests.
This commit is contained in:
David Baker
2018-12-12 16:13:48 +00:00
committed by J. Ryan Stinnett
parent f53e33723b
commit 66cdb62a3d

View File

@@ -42,6 +42,7 @@ export function isCryptoAvailable() {
}
const MIN_FORCE_SESSION_INTERVAL_MS = 60 * 60 * 1000;
const KEY_BACKUP_KEYS_PER_REQUEST = 200;
/**
* Cryptography bits
@@ -986,29 +987,69 @@ Crypto.prototype.importRoomKeys = function(keys) {
);
};
Crypto.prototype._maybeSendKeyBackup = async function(delay, retry) {
if (retry === undefined) retry = true;
/**
* Schedules sending all keys waiting to be sent to the backup, if not already
* scheduled. Retries if necessary.
*/
Crypto.prototype._scheduleKeyBackupSend = async function() {
if (this._sendingBackups) return;
if (!this._sendingBackups) {
this._sendingBackups = true;
try {
if (delay === undefined) {
// by default, wait between 0 and 10 seconds, to avoid backup
// wait between 0 and 10 seconds, to avoid backup
// requests from different clients hitting the server all at
// the same time when a new key is sent
delay = Math.random() * 10000;
}
const delay = Math.random() * 10000;
await Promise.delay(delay);
let numFailures = 0; // number of consecutive failures
while (1) {
if (!this.backupKey) {
return;
}
// FIXME: figure out what limit is reasonable
const sessions = await this._cryptoStore.getSessionsNeedingBackup(10);
if (!sessions.length) {
try {
const numBackedUp =
await this._backupPendingKeys(KEY_BACKUP_KEYS_PER_REQUEST);
if (numBackedUp === 0) {
// no sessions left needing backup: we're done
return;
}
numFailures = 0;
} catch (err) {
numFailures++;
console.log("Key backup request failed", err);
if (err.data) {
if (
err.data.errcode == 'M_NOT_FOUND' ||
err.data.errcode == 'M_WRONG_ROOM_KEYS_VERSION'
) {
// Backup version has changed or this backup version
// has been deleted
throw err;
}
}
}
if (numFailures) {
// exponential backoff if we have failures
await Promise.delay(1000 * Math.pow(2, Math.min(numFailures - 1, 4)));
}
}
} finally {
this._sendingBackups = false;
}
};
/**
* Take some e2e keys waiting to be backed up and send them
* to the backup.
*
* @param {integer} limit Maximum number of keys to back up
* @returns {integer} Number of sessions backed up
*/
Crypto.prototype._backupPendingKeys = async function(limit) {
const sessions = await this._cryptoStore.getSessionsNeedingBackup(limit);
if (!sessions.length) {
return 0;
}
const data = {};
for (const session of sessions) {
const roomId = session.sessionData.room_id;
@@ -1041,39 +1082,13 @@ Crypto.prototype._maybeSendKeyBackup = async function(delay, retry) {
};
}
try {
await this._baseApis.sendKeyBackup(
undefined, undefined, this.backupInfo.version,
{rooms: data},
);
numFailures = 0;
await this._cryptoStore.unmarkSessionsNeedingBackup(sessions);
} catch (err) {
numFailures++;
console.log("send failed", err);
if (err.httpStatus === 400
|| err.httpStatus === 403
|| err.httpStatus === 401
|| !retry) {
// retrying probably won't help much, so we should give up
// FIXME: disable backups?
throw err;
}
}
if (numFailures) {
// exponential backoff if we have failures
await new Promise((resolve, reject) => {
setTimeout(
resolve,
1000 * Math.pow(2, Math.min(numFailures - 1, 4)),
);
});
}
}
} finally {
this._sendingBackups = false;
}
}
return sessions.length;
};
Crypto.prototype.backupGroupSession = async function(
@@ -1090,7 +1105,9 @@ Crypto.prototype.backupGroupSession = async function(
sessionId: sessionId,
}]);
await this._maybeSendKeyBackup();
// don't wait for this to complete: it will delay so
// happens in the background
this._scheduleKeyBackupSend();
};
Crypto.prototype.backupAllGroupSessions = async function(version) {
@@ -1109,7 +1126,10 @@ Crypto.prototype.backupAllGroupSessions = async function(version) {
},
);
await this._maybeSendKeyBackup(0, false);
let numKeysBackedUp;
do {
numKeysBackedUp = this._backupPendingKeys(KEY_BACKUP_KEYS_PER_REQUEST);
} while (numKeysBackedUp > 0);
};
/* eslint-disable valid-jsdoc */ //https://github.com/eslint/eslint/issues/7307