From fc741272ba9ec0fb43872f6ea77e7d54e28e510f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Sat, 14 Mar 2020 20:45:36 +0100 Subject: [PATCH] only apply sync changes in session once txn is committed --- src/matrix/session.js | 64 ++++++++++++++++++++++++++++++++++++++++--- src/matrix/sync.js | 4 ++- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/matrix/session.js b/src/matrix/session.js index b86a8c69..63b2b03c 100644 --- a/src/matrix/session.js +++ b/src/matrix/session.js @@ -77,11 +77,19 @@ export default class Session { return room; } - persistSync(syncToken, syncFilterId, accountData, txn) { + writeSync(syncToken, syncFilterId, accountData, txn) { if (syncToken !== this._session.syncToken) { - this._session.syncToken = syncToken; - this._session.syncFilterId = syncFilterId; - txn.session.set(this._session); + // don't modify this._session because transaction might still fail + const newSessionData = Object.assign({}, this._session, {syncToken, syncFilterId}); + txn.session.set(newSessionData); + return newSessionData; + } + } + + afterSync(newSessionData) { + if (newSessionData) { + // sync transaction succeeded, modify object state now + this._session = newSessionData; } } @@ -97,3 +105,51 @@ export default class Session { return this._user; } } + +export function tests() { + function createStorageMock(session, pendingEvents) { + return { + readTxn() { + return Promise.resolve({ + session: { + get() { + return Promise.resolve(Object.assign({}, session)); + } + }, + pendingEvents: { + getAll() { + return Promise.resolve(pendingEvents); + } + } + }); + } + }; + } + + return { + "session data is not modified until after sync": async (assert) => { + const session = new Session({storage: createStorageMock({ + syncToken: "a", + syncFilterId: 5, + })}); + await session.load(); + let txnSetCalled = false; + const syncTxn = { + session: { + set({syncToken, syncFilterId}) { + txnSetCalled = true; + assert.equals(syncToken, "b"); + assert.equals(syncFilterId, 6); + } + } + }; + const newSessionData = session.writeSync("b", 6, {}, syncTxn); + assert(txnSetCalled); + assert.equals(session.syncToken, "a"); + assert.equals(session.syncFilterId, 5); + session.afterSync(newSessionData); + assert.equals(session.syncToken, "b"); + assert.equals(session.syncFilterId, 6); + } + } +} diff --git a/src/matrix/sync.js b/src/matrix/sync.js index beac1799..52726f01 100644 --- a/src/matrix/sync.js +++ b/src/matrix/sync.js @@ -85,8 +85,9 @@ export default class Sync extends EventEmitter { storeNames.pendingEvents, ]); const roomChanges = []; + let sessionChanges; try { - this._session.persistSync(syncToken, syncFilterId, response.account_data, syncTxn); + sessionChanges = this._session.writeSync(syncToken, syncFilterId, response.account_data, syncTxn); // to_device // presence if (response.rooms) { @@ -116,6 +117,7 @@ export default class Sync extends EventEmitter { console.error("unable to commit sync tranaction"); throw err; } + this._session.afterSync(sessionChanges); // emit room related events after txn has been closed for(let {room, changes} of roomChanges) { room.emitSync(changes);