You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2026-01-03 23:22:30 +03:00
Fall back to MemoryCryptoStore if indexeddb fails
If we get an error when connecting to th indexeddb, fall back to a MemoryCryptoStore. This takes a bit of reorganising, because we don't get the error until we try to connect to the database.
This commit is contained in:
291
src/crypto/store/indexeddb-crypto-store-backend.js
Normal file
291
src/crypto/store/indexeddb-crypto-store-backend.js
Normal file
@@ -0,0 +1,291 @@
|
||||
import q from 'q';
|
||||
import utils from '../../utils';
|
||||
|
||||
export const VERSION = 1;
|
||||
|
||||
/**
|
||||
* Implementation of a CryptoStore which is backed by an existing
|
||||
* IndexedDB connection. Generally you want IndexedDBCryptoStore
|
||||
* which connects to the database and defers to one of these.
|
||||
*
|
||||
* @implements {module:crypto/store/base~CryptoStore}
|
||||
*/
|
||||
export class Backend {
|
||||
/**
|
||||
* @param {IDBDatabase} db
|
||||
*/
|
||||
constructor(db) {
|
||||
this._db = db;
|
||||
|
||||
// make sure we close the db on `onversionchange` - otherwise
|
||||
// attempts to delete the database will block (and subsequent
|
||||
// attempts to re-create it will also block).
|
||||
db.onversionchange = (ev) => {
|
||||
console.log(`versionchange for indexeddb ${this._dbName}: closing`);
|
||||
db.close();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for an existing outgoing room key request, and if none is found,
|
||||
* add a new one
|
||||
*
|
||||
* @param {module:crypto/store/base~OutgoingRoomKeyRequest} request
|
||||
*
|
||||
* @returns {Promise} resolves to
|
||||
* {@link module:crypto/store/base~OutgoingRoomKeyRequest}: either the
|
||||
* same instance as passed in, or the existing one.
|
||||
*/
|
||||
getOrAddOutgoingRoomKeyRequest(request) {
|
||||
const requestBody = request.requestBody;
|
||||
|
||||
const deferred = q.defer();
|
||||
const txn = this._db.transaction("outgoingRoomKeyRequests", "readwrite");
|
||||
txn.onerror = deferred.reject;
|
||||
|
||||
// first see if we already have an entry for this request.
|
||||
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
|
||||
if (existing) {
|
||||
// this entry matches the request - return it.
|
||||
console.log(
|
||||
`already have key request outstanding for ` +
|
||||
`${requestBody.room_id} / ${requestBody.session_id}: ` +
|
||||
`not sending another`,
|
||||
);
|
||||
deferred.resolve(existing);
|
||||
return;
|
||||
}
|
||||
|
||||
// we got to the end of the list without finding a match
|
||||
// - add the new request.
|
||||
console.log(
|
||||
`enqueueing key request for ${requestBody.room_id} / ` +
|
||||
requestBody.session_id,
|
||||
);
|
||||
const store = txn.objectStore("outgoingRoomKeyRequests");
|
||||
store.add(request);
|
||||
txn.onsuccess = () => { deferred.resolve(request); };
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for an existing room key request
|
||||
*
|
||||
* @param {module:crypto~RoomKeyRequestBody} requestBody
|
||||
* existing request to look for
|
||||
*
|
||||
* @return {Promise} resolves to the matching
|
||||
* {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if
|
||||
* not found
|
||||
*/
|
||||
getOutgoingRoomKeyRequest(requestBody) {
|
||||
const deferred = q.defer();
|
||||
|
||||
const txn = this._db.transaction("outgoingRoomKeyRequests", "readonly");
|
||||
txn.onerror = deferred.reject;
|
||||
|
||||
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
|
||||
deferred.resolve(existing);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* look for an existing room key request in the db
|
||||
*
|
||||
* @private
|
||||
* @param {IDBTransaction} txn database transaction
|
||||
* @param {module:crypto~RoomKeyRequestBody} requestBody
|
||||
* existing request to look for
|
||||
* @param {Function} callback function to call with the results of the
|
||||
* search. Either passed a matching
|
||||
* {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if
|
||||
* not found.
|
||||
*/
|
||||
_getOutgoingRoomKeyRequest(txn, requestBody, callback) {
|
||||
const store = txn.objectStore("outgoingRoomKeyRequests");
|
||||
|
||||
const idx = store.index("session");
|
||||
const cursorReq = idx.openCursor([
|
||||
requestBody.room_id,
|
||||
requestBody.session_id,
|
||||
]);
|
||||
|
||||
cursorReq.onsuccess = (ev) => {
|
||||
const cursor = ev.target.result;
|
||||
if(!cursor) {
|
||||
// no match found
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const existing = cursor.value;
|
||||
|
||||
if (utils.deepCompare(existing.requestBody, requestBody)) {
|
||||
// got a match
|
||||
callback(existing);
|
||||
return;
|
||||
}
|
||||
|
||||
// look at the next entry in the index
|
||||
cursor.continue();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for room key requests by state
|
||||
*
|
||||
* @param {Array<Number>} wantedStates list of acceptable states
|
||||
*
|
||||
* @return {Promise} resolves to the a
|
||||
* {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if
|
||||
* there are no pending requests in those states. If there are multiple
|
||||
* requests in those states, an arbitrary one is chosen.
|
||||
*/
|
||||
getOutgoingRoomKeyRequestByState(wantedStates) {
|
||||
if (wantedStates.length === 0) {
|
||||
return q(null);
|
||||
}
|
||||
|
||||
// this is a bit tortuous because we need to make sure we do the lookup
|
||||
// in a single transaction, to avoid having a race with the insertion
|
||||
// code.
|
||||
|
||||
// index into the wantedStates array
|
||||
let stateIndex = 0;
|
||||
let result;
|
||||
|
||||
function onsuccess(ev) {
|
||||
const cursor = ev.target.result;
|
||||
if (cursor) {
|
||||
// got a match
|
||||
result = cursor.value;
|
||||
return;
|
||||
}
|
||||
|
||||
// try the next state in the list
|
||||
stateIndex++;
|
||||
if (stateIndex >= wantedStates.length) {
|
||||
// no matches
|
||||
return;
|
||||
}
|
||||
|
||||
const wantedState = wantedStates[stateIndex];
|
||||
const cursorReq = ev.target.source.openCursor(wantedState);
|
||||
cursorReq.onsuccess = onsuccess;
|
||||
}
|
||||
|
||||
const txn = this._db.transaction("outgoingRoomKeyRequests", "readonly");
|
||||
const store = txn.objectStore("outgoingRoomKeyRequests");
|
||||
|
||||
const wantedState = wantedStates[stateIndex];
|
||||
const cursorReq = store.index("state").openCursor(wantedState);
|
||||
cursorReq.onsuccess = onsuccess;
|
||||
|
||||
return promiseifyTxn(txn).then(() => result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for an existing room key request by id and state, and update it if
|
||||
* found
|
||||
*
|
||||
* @param {string} requestId ID of request to update
|
||||
* @param {number} expectedState state we expect to find the request in
|
||||
* @param {Object} updates name/value map of updates to apply
|
||||
*
|
||||
* @returns {Promise} resolves to
|
||||
* {@link module:crypto/store/base~OutgoingRoomKeyRequest}
|
||||
* updated request, or null if no matching row was found
|
||||
*/
|
||||
updateOutgoingRoomKeyRequest(requestId, expectedState, updates) {
|
||||
let result = null;
|
||||
|
||||
function onsuccess(ev) {
|
||||
const cursor = ev.target.result;
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
const data = cursor.value;
|
||||
if (data.state != expectedState) {
|
||||
console.warn(
|
||||
`Cannot update room key request from ${expectedState} ` +
|
||||
`as it was already updated to ${data.state}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
Object.assign(data, updates);
|
||||
cursor.update(data);
|
||||
result = data;
|
||||
}
|
||||
|
||||
const txn = this._db.transaction("outgoingRoomKeyRequests", "readwrite");
|
||||
const cursorReq = txn.objectStore("outgoingRoomKeyRequests")
|
||||
.openCursor(requestId);
|
||||
cursorReq.onsuccess = onsuccess;
|
||||
return promiseifyTxn(txn).then(() => result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for an existing room key request by id and state, and delete it if
|
||||
* found
|
||||
*
|
||||
* @param {string} requestId ID of request to update
|
||||
* @param {number} expectedState state we expect to find the request in
|
||||
*
|
||||
* @returns {Promise} resolves once the operation is completed
|
||||
*/
|
||||
deleteOutgoingRoomKeyRequest(requestId, expectedState) {
|
||||
const txn = this._db.transaction("outgoingRoomKeyRequests", "readwrite");
|
||||
const cursorReq = txn.objectStore("outgoingRoomKeyRequests")
|
||||
.openCursor(requestId);
|
||||
cursorReq.onsuccess = (ev) => {
|
||||
const cursor = ev.target.result;
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
const data = cursor.value;
|
||||
if (data.state != expectedState) {
|
||||
console.warn(
|
||||
`Cannot delete room key request in state ${data.state} `
|
||||
+ `(expected ${expectedState})`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
cursor.delete();
|
||||
};
|
||||
return promiseifyTxn(txn);
|
||||
}
|
||||
}
|
||||
|
||||
export function upgradeDatabase(db, oldVersion) {
|
||||
console.log(
|
||||
`Upgrading IndexedDBCryptoStore from version ${oldVersion}`
|
||||
+ ` to ${VERSION}`,
|
||||
);
|
||||
if (oldVersion < 1) { // The database did not previously exist.
|
||||
createDatabase(db);
|
||||
}
|
||||
// Expand as needed.
|
||||
}
|
||||
|
||||
function createDatabase(db) {
|
||||
const outgoingRoomKeyRequestsStore =
|
||||
db.createObjectStore("outgoingRoomKeyRequests", { keyPath: "requestId" });
|
||||
|
||||
// we assume that the RoomKeyRequestBody will have room_id and session_id
|
||||
// properties, to make the index efficient.
|
||||
outgoingRoomKeyRequestsStore.createIndex("session",
|
||||
["requestBody.room_id", "requestBody.session_id"],
|
||||
);
|
||||
|
||||
outgoingRoomKeyRequestsStore.createIndex("state", "state");
|
||||
}
|
||||
|
||||
function promiseifyTxn(txn) {
|
||||
return new q.Promise((resolve, reject) => {
|
||||
txn.oncomplete = resolve;
|
||||
txn.onerror = reject;
|
||||
});
|
||||
}
|
||||
@@ -15,7 +15,9 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import q from 'q';
|
||||
import utils from '../../utils';
|
||||
|
||||
import MemoryCryptoStore from './memory-crypto-store';
|
||||
import * as IndexedDBCryptoStoreBackend from './indexeddb-crypto-store-backend';
|
||||
|
||||
/**
|
||||
* Internal module. indexeddb storage for e2e.
|
||||
@@ -23,9 +25,10 @@ import utils from '../../utils';
|
||||
* @module
|
||||
*/
|
||||
|
||||
const VERSION = 1;
|
||||
|
||||
/**
|
||||
* An implementation of CryptoStore, which is normally backed by an indexeddb,
|
||||
* but with fallback to MemoryCryptoStore.
|
||||
*
|
||||
* @implements {module:crypto/store/base~CryptoStore}
|
||||
*/
|
||||
export default class IndexedDBCryptoStore {
|
||||
@@ -36,40 +39,39 @@ export default class IndexedDBCryptoStore {
|
||||
* @param {string} dbName name of db to connect to
|
||||
*/
|
||||
constructor(indexedDB, dbName) {
|
||||
if (!indexedDB) {
|
||||
throw new Error("must pass indexedDB into IndexedDBCryptoStore");
|
||||
}
|
||||
this._indexedDB = indexedDB;
|
||||
this._dbName = dbName;
|
||||
this._dbPromise = null;
|
||||
this._backendPromise = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the database exists and is up-to-date
|
||||
* Ensure the database exists and is up-to-date, or fall back to
|
||||
* an in-memory store.
|
||||
*
|
||||
* @return {Promise} resolves to an instance of IDBDatabase when
|
||||
* the database is ready
|
||||
* @return {Promise} resolves to either an IndexedDBCryptoStoreBackend.Backend,
|
||||
* or a MemoryCryptoStore
|
||||
*/
|
||||
connect() {
|
||||
if (this._dbPromise) {
|
||||
return this._dbPromise;
|
||||
_connect() {
|
||||
if (this._backendPromise) {
|
||||
return this._backendPromise;
|
||||
}
|
||||
|
||||
this._dbPromise = new q.Promise((resolve, reject) => {
|
||||
this._backendPromise = new q.Promise((resolve, reject) => {
|
||||
if (!this._indexedDB) {
|
||||
reject(new Error('no indexeddb support available'));
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`connecting to indexeddb ${this._dbName}`);
|
||||
const req = this._indexedDB.open(this._dbName, VERSION);
|
||||
|
||||
const req = this._indexedDB.open(
|
||||
this._dbName, IndexedDBCryptoStoreBackend.VERSION,
|
||||
);
|
||||
|
||||
req.onupgradeneeded = (ev) => {
|
||||
const db = ev.target.result;
|
||||
const oldVersion = ev.oldVersion;
|
||||
console.log(
|
||||
`Upgrading IndexedDBCryptoStore from version ${oldVersion}`
|
||||
+ ` to ${VERSION}`,
|
||||
);
|
||||
if (oldVersion < 1) { // The database did not previously exist.
|
||||
createDatabase(db);
|
||||
}
|
||||
// Expand as needed.
|
||||
IndexedDBCryptoStoreBackend.upgradeDatabase(db, oldVersion);
|
||||
};
|
||||
|
||||
req.onblocked = () => {
|
||||
@@ -79,27 +81,24 @@ export default class IndexedDBCryptoStore {
|
||||
};
|
||||
|
||||
req.onerror = (ev) => {
|
||||
reject(new Error(
|
||||
"unable to connect to indexeddb: " + ev.target.error,
|
||||
));
|
||||
reject(ev.target.error);
|
||||
};
|
||||
|
||||
req.onsuccess = (r) => {
|
||||
const db = r.target.result;
|
||||
|
||||
// make sure we close the db on `onversionchange` - otherwise
|
||||
// attempts to delete the database will block (and subsequent
|
||||
// attempts to re-create it will also block).
|
||||
db.onversionchange = (ev) => {
|
||||
console.log(`versionchange for indexeddb ${this._dbName}: closing`);
|
||||
db.close();
|
||||
};
|
||||
|
||||
console.log(`connected to indexeddb ${this._dbName}`);
|
||||
resolve(db);
|
||||
resolve(new IndexedDBCryptoStoreBackend.Backend(db));
|
||||
};
|
||||
}).catch((e) => {
|
||||
console.warn(
|
||||
`unable to connect to indexeddb ${this._dbName}` +
|
||||
`: falling back to in-memory store: ${e}`,
|
||||
);
|
||||
return new MemoryCryptoStore();
|
||||
});
|
||||
return this._dbPromise;
|
||||
|
||||
return this._backendPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,6 +108,11 @@ export default class IndexedDBCryptoStore {
|
||||
*/
|
||||
deleteAllData() {
|
||||
return new q.Promise((resolve, reject) => {
|
||||
if (!this._indexedDB) {
|
||||
reject(new Error('no indexeddb support available'));
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Removing indexeddb instance: ${this._dbName}`);
|
||||
const req = this._indexedDB.deleteDatabase(this._dbName);
|
||||
|
||||
@@ -119,17 +123,18 @@ export default class IndexedDBCryptoStore {
|
||||
};
|
||||
|
||||
req.onerror = (ev) => {
|
||||
// in firefox, with indexedDB disabled, this fails with a
|
||||
// DOMError. We treat this as non-fatal, so that people can
|
||||
// still use the app.
|
||||
console.warn(`unable to delete IndexedDBCryptoStore: ${ev.target.error}`);
|
||||
resolve();
|
||||
reject(ev.target.error);
|
||||
};
|
||||
|
||||
req.onsuccess = () => {
|
||||
console.log(`Removed indexeddb instance: ${this._dbName}`);
|
||||
resolve();
|
||||
};
|
||||
}).catch((e) => {
|
||||
// in firefox, with indexedDB disabled, this fails with a
|
||||
// DOMError. We treat this as non-fatal, so that people can
|
||||
// still use the app.
|
||||
console.warn(`unable to delete IndexedDBCryptoStore: ${e}`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -144,38 +149,8 @@ export default class IndexedDBCryptoStore {
|
||||
* same instance as passed in, or the existing one.
|
||||
*/
|
||||
getOrAddOutgoingRoomKeyRequest(request) {
|
||||
const requestBody = request.requestBody;
|
||||
|
||||
return this.connect().then((db) => {
|
||||
const deferred = q.defer();
|
||||
const txn = db.transaction("outgoingRoomKeyRequests", "readwrite");
|
||||
txn.onerror = deferred.reject;
|
||||
|
||||
// first see if we already have an entry for this request.
|
||||
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
|
||||
if (existing) {
|
||||
// this entry matches the request - return it.
|
||||
console.log(
|
||||
`already have key request outstanding for ` +
|
||||
`${requestBody.room_id} / ${requestBody.session_id}: ` +
|
||||
`not sending another`,
|
||||
);
|
||||
deferred.resolve(existing);
|
||||
return;
|
||||
}
|
||||
|
||||
// we got to the end of the list without finding a match
|
||||
// - add the new request.
|
||||
console.log(
|
||||
`enqueueing key request for ${requestBody.room_id} / ` +
|
||||
requestBody.session_id,
|
||||
);
|
||||
const store = txn.objectStore("outgoingRoomKeyRequests");
|
||||
store.add(request);
|
||||
txn.onsuccess = () => { deferred.resolve(request); };
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
return this._connect().then((backend) => {
|
||||
return backend.getOrAddOutgoingRoomKeyRequest(request);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -190,61 +165,11 @@ export default class IndexedDBCryptoStore {
|
||||
* not found
|
||||
*/
|
||||
getOutgoingRoomKeyRequest(requestBody) {
|
||||
return this.connect().then((db) => {
|
||||
const deferred = q.defer();
|
||||
|
||||
const txn = db.transaction("outgoingRoomKeyRequests", "readonly");
|
||||
txn.onerror = deferred.reject;
|
||||
|
||||
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
|
||||
deferred.resolve(existing);
|
||||
});
|
||||
return deferred.promise;
|
||||
return this._connect().then((backend) => {
|
||||
return backend.getOutgoingRoomKeyRequest(requestBody);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* look for an existing room key request in the db
|
||||
*
|
||||
* @private
|
||||
* @param {IDBTransaction} txn database transaction
|
||||
* @param {module:crypto~RoomKeyRequestBody} requestBody
|
||||
* existing request to look for
|
||||
* @param {Function} callback function to call with the results of the
|
||||
* search. Either passed a matching
|
||||
* {@link module:crypto/store/base~OutgoingRoomKeyRequest}, or null if
|
||||
* not found.
|
||||
*/
|
||||
_getOutgoingRoomKeyRequest(txn, requestBody, callback) {
|
||||
const store = txn.objectStore("outgoingRoomKeyRequests");
|
||||
|
||||
const idx = store.index("session");
|
||||
const cursorReq = idx.openCursor([
|
||||
requestBody.room_id,
|
||||
requestBody.session_id,
|
||||
]);
|
||||
|
||||
cursorReq.onsuccess = (ev) => {
|
||||
const cursor = ev.target.result;
|
||||
if(!cursor) {
|
||||
// no match found
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const existing = cursor.value;
|
||||
|
||||
if (utils.deepCompare(existing.requestBody, requestBody)) {
|
||||
// got a match
|
||||
callback(existing);
|
||||
return;
|
||||
}
|
||||
|
||||
// look at the next entry in the index
|
||||
cursor.continue();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for room key requests by state
|
||||
*
|
||||
@@ -256,47 +181,8 @@ export default class IndexedDBCryptoStore {
|
||||
* requests in those states, an arbitrary one is chosen.
|
||||
*/
|
||||
getOutgoingRoomKeyRequestByState(wantedStates) {
|
||||
if (wantedStates.length === 0) {
|
||||
return q(null);
|
||||
}
|
||||
|
||||
// this is a bit tortuous because we need to make sure we do the lookup
|
||||
// in a single transaction, to avoid having a race with the insertion
|
||||
// code.
|
||||
|
||||
// index into the wantedStates array
|
||||
let stateIndex = 0;
|
||||
let result;
|
||||
|
||||
function onsuccess(ev) {
|
||||
const cursor = ev.target.result;
|
||||
if (cursor) {
|
||||
// got a match
|
||||
result = cursor.value;
|
||||
return;
|
||||
}
|
||||
|
||||
// try the next state in the list
|
||||
stateIndex++;
|
||||
if (stateIndex >= wantedStates.length) {
|
||||
// no matches
|
||||
return;
|
||||
}
|
||||
|
||||
const wantedState = wantedStates[stateIndex];
|
||||
const cursorReq = ev.target.source.openCursor(wantedState);
|
||||
cursorReq.onsuccess = onsuccess;
|
||||
}
|
||||
|
||||
return this.connect().then((db) => {
|
||||
const txn = db.transaction("outgoingRoomKeyRequests", "readonly");
|
||||
const store = txn.objectStore("outgoingRoomKeyRequests");
|
||||
|
||||
const wantedState = wantedStates[stateIndex];
|
||||
const cursorReq = store.index("state").openCursor(wantedState);
|
||||
cursorReq.onsuccess = onsuccess;
|
||||
|
||||
return promiseifyTxn(txn).then(() => result);
|
||||
return this._connect().then((backend) => {
|
||||
return backend.getOutgoingRoomKeyRequestByState(wantedStates);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -313,32 +199,10 @@ export default class IndexedDBCryptoStore {
|
||||
* updated request, or null if no matching row was found
|
||||
*/
|
||||
updateOutgoingRoomKeyRequest(requestId, expectedState, updates) {
|
||||
let result = null;
|
||||
|
||||
function onsuccess(ev) {
|
||||
const cursor = ev.target.result;
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
const data = cursor.value;
|
||||
if (data.state != expectedState) {
|
||||
console.warn(
|
||||
`Cannot update room key request from ${expectedState} ` +
|
||||
`as it was already updated to ${data.state}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
Object.assign(data, updates);
|
||||
cursor.update(data);
|
||||
result = data;
|
||||
}
|
||||
|
||||
return this.connect().then((db) => {
|
||||
const txn = db.transaction("outgoingRoomKeyRequests", "readwrite");
|
||||
const cursorReq = txn.objectStore("outgoingRoomKeyRequests")
|
||||
.openCursor(requestId);
|
||||
cursorReq.onsuccess = onsuccess;
|
||||
return promiseifyTxn(txn).then(() => result);
|
||||
return this._connect().then((backend) => {
|
||||
return backend.updateOutgoingRoomKeyRequest(
|
||||
requestId, expectedState, updates,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -352,46 +216,8 @@ export default class IndexedDBCryptoStore {
|
||||
* @returns {Promise} resolves once the operation is completed
|
||||
*/
|
||||
deleteOutgoingRoomKeyRequest(requestId, expectedState) {
|
||||
return this.connect().then((db) => {
|
||||
const txn = db.transaction("outgoingRoomKeyRequests", "readwrite");
|
||||
const cursorReq = txn.objectStore("outgoingRoomKeyRequests")
|
||||
.openCursor(requestId);
|
||||
cursorReq.onsuccess = (ev) => {
|
||||
const cursor = ev.target.result;
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
const data = cursor.value;
|
||||
if (data.state != expectedState) {
|
||||
console.warn(
|
||||
`Cannot delete room key request in state ${data.state} `
|
||||
+ `(expected ${expectedState})`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
cursor.delete();
|
||||
};
|
||||
return promiseifyTxn(txn);
|
||||
return this._connect().then((backend) => {
|
||||
return backend.deleteOutgoingRoomKeyRequest(requestId, expectedState);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createDatabase(db) {
|
||||
const outgoingRoomKeyRequestsStore =
|
||||
db.createObjectStore("outgoingRoomKeyRequests", { keyPath: "requestId" });
|
||||
|
||||
// we assume that the RoomKeyRequestBody will have room_id and session_id
|
||||
// properties, to make the index efficient.
|
||||
outgoingRoomKeyRequestsStore.createIndex("session",
|
||||
["requestBody.room_id", "requestBody.session_id"],
|
||||
);
|
||||
|
||||
outgoingRoomKeyRequestsStore.createIndex("state", "state");
|
||||
}
|
||||
|
||||
function promiseifyTxn(txn) {
|
||||
return new q.Promise((resolve, reject) => {
|
||||
txn.oncomplete = resolve;
|
||||
txn.onerror = reject;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user