From 18661e042d16ba3a4953f80ebf0215a5311e7013 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 4 Oct 2018 13:40:56 +0100 Subject: [PATCH] Fall back to another store if indexeddb start fails If we can't start indexeddb, fall back to a different store. Previously we just ignored the exception and ploughed on anyway, on the assumption that startup() was just for the indexeddb store to load data anyway, and if that failed it would just do an initial /sync instead (and also we'd keep trying to save the sync back which would fail...). Then, in the previous release we started pulling the settings out of the store on startup, making the assumpton that the store actually worked, so the read obviously failed and the app failed to start up. This makes Riot work in Tor browser / firefox in daft mode again. --- src/MatrixClientPeg.js | 41 ++++++++++++++++++++++----------- src/utils/createMatrixClient.js | 9 ++++++-- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 9865044717..f02c751a2c 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -18,6 +18,8 @@ limitations under the License. 'use strict'; +import Matrix from 'matrix-js-sdk'; + import utils from 'matrix-js-sdk/lib/utils'; import EventTimeline from 'matrix-js-sdk/lib/models/event-timeline'; import EventTimelineSet from 'matrix-js-sdk/lib/models/event-timeline-set'; @@ -51,6 +53,9 @@ class MatrixClientPeg { this.opts = { initialSyncLimit: 20, }; + // the credentials used to init the current client object. + // used if we tear it down & recreate it with a different store + this._currentClientCreds = null; } /** @@ -79,10 +84,30 @@ class MatrixClientPeg { * Home Server / Identity Server URLs and active credentials */ replaceUsingCreds(creds: MatrixClientCreds) { + this._currentClientCreds = creds; this._createClient(creds); } async start() { + for (const dbType of ['indexeddb', 'memory']) { + try { + const promise = this.matrixClient.store.startup(); + console.log("MatrixClientPeg: waiting for MatrixClient store to initialise"); + await promise; + break; + } catch (err) { + if (dbType === 'indexeddb') { + console.error('Error starting matrixclient store - falling back to memory store', err); + this.matrixClient.store = new Matrix.MatrixInMemoryStore({ + localStorage: global.localStorage, + }); + } else { + console.error('Failed to start memory store!', err); + throw err; + } + } + } + // try to initialise e2e on the new client try { // check that we have a version of the js-sdk which includes initCrypto @@ -103,18 +128,6 @@ class MatrixClientPeg { opts.lazyLoadMembers = true; } - try { - const promise = this.matrixClient.store.startup(); - console.log(`MatrixClientPeg: waiting for MatrixClient store to initialise`); - await promise; - } catch (err) { - // log any errors when starting up the database (if one exists) - console.error('Error starting matrixclient store', err); - } - - // regardless of errors, start the client. If we did error out, we'll - // just end up doing a full initial /sync. - // Connect the matrix client to the dispatcher MatrixActionCreators.start(this.matrixClient); @@ -147,7 +160,7 @@ class MatrixClientPeg { return matches[1]; } - _createClient(creds: MatrixClientCreds) { + _createClient(creds: MatrixClientCreds, useIndexedDb) { const opts = { baseUrl: creds.homeserverUrl, idBaseUrl: creds.identityServerUrl, @@ -158,7 +171,7 @@ class MatrixClientPeg { forceTURN: SettingsStore.getValue('webRtcForceTURN', false), }; - this.matrixClient = createMatrixClient(opts, this.indexedDbWorkerScript); + this.matrixClient = createMatrixClient(opts, useIndexedDb); // we're going to add eventlisteners for each matrix event tile, so the // potential number of event listeners is quite high. diff --git a/src/utils/createMatrixClient.js b/src/utils/createMatrixClient.js index 54312695b6..2acd1fae28 100644 --- a/src/utils/createMatrixClient.js +++ b/src/utils/createMatrixClient.js @@ -32,13 +32,18 @@ try { * @param {Object} opts options to pass to Matrix.createClient. This will be * extended with `sessionStore` and `store` members. * + * @param {bool} useIndexedDb True to attempt to use indexeddb, or false to force + * use of the memory store. Default: true. + * * @property {string} indexedDbWorkerScript Optional URL for a web worker script * for IndexedDB store operations. By default, indexeddb ops are done on * the main thread. * * @returns {MatrixClient} the newly-created MatrixClient */ -export default function createMatrixClient(opts) { +export default function createMatrixClient(opts, useIndexedDb) { + if (useIndexedDb === undefined) useIndexedDb = true; + const storeOpts = { useAuthorizationHeader: true, }; @@ -47,7 +52,7 @@ export default function createMatrixClient(opts) { storeOpts.sessionStore = new Matrix.WebStorageSessionStore(localStorage); } - if (indexedDB && localStorage) { + if (indexedDB && localStorage && useIndexedDb) { storeOpts.store = new Matrix.IndexedDBStore({ indexedDB: indexedDB, dbName: "riot-web-sync",