diff --git a/src/matrix/Session.js b/src/matrix/Session.js index f6db9c97..90516c5f 100644 --- a/src/matrix/Session.js +++ b/src/matrix/Session.js @@ -24,7 +24,7 @@ export class Session { constructor({storage, hsApi, sessionInfo, olm}) { this._storage = storage; this._hsApi = hsApi; - this._session = null; + this._syncInfo = null; this._sessionInfo = sessionInfo; this._rooms = new ObservableMap(); this._sendScheduler = new SendScheduler({hsApi, backoff: new RateLimitingBackoff()}); @@ -43,11 +43,7 @@ export class Session { this._storage.storeNames.pendingEvents, ]); // restore session object - this._session = await txn.session.get(); - if (!this._session) { - this._session = {}; - return; - } + this._syncInfo = await txn.session.get("sync"); const pendingEventsByRoomId = await this._getPendingEventsByRoom(txn); // load rooms const rooms = await txn.roomSummary.getAll(); @@ -71,11 +67,9 @@ export class Session { const txn = await this._storage.readWriteTxn([ this._storage.storeNames.session ]); - const newSessionData = Object.assign({}, this._session, {serverVersions: lastVersionResponse}); - txn.session.set(newSessionData); + txn.session.set("serverVersions", lastVersionResponse); // TODO: what can we do if this throws? await txn.complete(); - this._session = newSessionData; } this._sendScheduler.start(); @@ -116,27 +110,27 @@ export class Session { } writeSync(syncToken, syncFilterId, accountData, txn) { - if (syncToken !== this._session.syncToken) { - // don't modify this._session because transaction might still fail - const newSessionData = Object.assign({}, this._session, {syncToken, syncFilterId}); - txn.session.set(newSessionData); - return newSessionData; + if (syncToken !== this.syncToken) { + const syncInfo = {token: syncToken, filterId: syncFilterId}; + // don't modify `this` because transaction might still fail + txn.session.set("sync", syncInfo); + return syncInfo; } } - afterSync(newSessionData) { - if (newSessionData) { + afterSync(syncInfo) { + if (syncInfo) { // sync transaction succeeded, modify object state now - this._session = newSessionData; + this._syncInfo = syncInfo; } } get syncToken() { - return this._session.syncToken; + return this._syncInfo?.token; } get syncFilterId() { - return this._session.syncFilterId; + return this._syncInfo?.filterId; } get user() { @@ -150,8 +144,8 @@ export function tests() { readTxn() { return Promise.resolve({ session: { - get() { - return Promise.resolve(Object.assign({}, session)); + get(key) { + return Promise.resolve(session[key]); } }, pendingEvents: { @@ -173,22 +167,23 @@ export function tests() { return { "session data is not modified until after sync": async (assert) => { const session = new Session({storage: createStorageMock({ - syncToken: "a", - syncFilterId: 5, + sync: {token: "a", filterId: 5} }), sessionInfo: {userId: ""}}); await session.load(); - let txnSetCalled = false; + let syncSet = false; const syncTxn = { session: { - set({syncToken, syncFilterId}) { - txnSetCalled = true; - assert.equal(syncToken, "b"); - assert.equal(syncFilterId, 6); + set(key, value) { + if (key === "sync") { + assert.equal(value.token, "b"); + assert.equal(value.filterId, 6); + syncSet = true; + } } } }; const newSessionData = session.writeSync("b", 6, {}, syncTxn); - assert(txnSetCalled); + assert(syncSet); assert.equal(session.syncToken, "a"); assert.equal(session.syncFilterId, 5); session.afterSync(newSessionData); diff --git a/src/matrix/room/RoomSummary.js b/src/matrix/room/RoomSummary.js index 36c7d203..b3758d23 100644 --- a/src/matrix/room/RoomSummary.js +++ b/src/matrix/room/RoomSummary.js @@ -263,7 +263,7 @@ export function tests() { "membership trigger change": function(assert) { const summary = new RoomSummary("id"); let written = false; - const changes = summary.writeSync({}, "join", {roomSummary: {set: () => { written = true; }}}); + const changes = summary.writeSync({}, "join", false, false, {roomSummary: {set: () => { written = true; }}}); assert(changes); assert(written); assert.equal(changes.membership, "join"); diff --git a/src/matrix/storage/idb/schema.js b/src/matrix/storage/idb/schema.js index 21a108c8..0ab5707a 100644 --- a/src/matrix/storage/idb/schema.js +++ b/src/matrix/storage/idb/schema.js @@ -1,12 +1,14 @@ -import {iterateCursor} from "./utils.js"; +import {iterateCursor, reqAsPromise} from "./utils.js"; import {RoomMember, EVENT_TYPE as MEMBER_EVENT_TYPE} from "../../room/members/RoomMember.js"; import {RoomMemberStore} from "./stores/RoomMemberStore.js"; +import {SessionStore} from "./stores/SessionStore.js"; // FUNCTIONS SHOULD ONLY BE APPENDED!! // the index in the array is the database version export const schema = [ createInitialStores, createMemberStore, + migrateSession, ]; // TODO: how to deal with git merge conflicts of this array? @@ -44,3 +46,21 @@ async function createMemberStore(db, txn) { } }); } + +async function migrateSession(db, txn) { + const session = txn.objectStore("session"); + try { + const PRE_MIGRATION_KEY = 1; + const entry = await reqAsPromise(session.get(PRE_MIGRATION_KEY)); + if (entry) { + session.delete(PRE_MIGRATION_KEY); + const {syncToken, syncFilterId, serverVersions} = entry.value; + const store = new SessionStore(session); + store.set("sync", {token: syncToken, filterId: syncFilterId}); + store.set("serverVersions", serverVersions); + } + } catch (err) { + txn.abort(); + console.error("could not migrate session", err.stack); + } +} diff --git a/src/matrix/storage/idb/stores/SessionStore.js b/src/matrix/storage/idb/stores/SessionStore.js index e26de3b4..2e74b9df 100644 --- a/src/matrix/storage/idb/stores/SessionStore.js +++ b/src/matrix/storage/idb/stores/SessionStore.js @@ -35,14 +35,14 @@ export class SessionStore { this._sessionStore = sessionStore; } - async get() { - const session = await this._sessionStore.selectFirst(IDBKeyRange.only(1)); - if (session) { - return session.value; + async get(key) { + const entry = await this._sessionStore.get(key); + if (entry) { + return entry.value; } } - set(session) { - return this._sessionStore.put({key: 1, value: session}); + set(key, value) { + return this._sessionStore.put({key, value}); } }