This repository has been archived on 2022-08-19. You can view files and clone it, but cannot push or open issues or pull requests.
hydrogen-web/src/sync.js

107 lines
2.7 KiB
JavaScript
Raw Normal View History

2019-02-05 03:56:45 +05:30
import {RequestAbortError} from "./network.js";
import {HomeServerError, StorageError} from "./error.js";
2018-12-21 19:05:24 +05:30
2019-02-04 02:47:24 +05:30
const INCREMENTAL_TIMEOUT = 30;
2018-12-21 19:05:24 +05:30
2019-02-05 03:56:45 +05:30
function parseRooms(responseSections, roomMapper) {
return ["join", "invite", "leave"].map(membership => {
const membershipSection = responseSections[membership];
const results = Object.entries(membershipSection).map(([roomId, roomResponse]) => {
const room = roomMapper(roomId, membership);
return room.processInitialSync(roomResponse);
});
return results;
}).reduce((allResults, sectionResults) => allResults.concat(sectionResults), []);
}
export class Sync {
2019-02-04 02:47:24 +05:30
constructor(network, session, storage) {
2018-12-21 19:05:24 +05:30
this._network = network;
this._session = session;
2019-02-04 02:47:24 +05:30
this._storage = storage;
2018-12-21 19:05:24 +05:30
this._isSyncing = false;
this._currentRequest = null;
}
2019-02-04 02:47:24 +05:30
// returns when initial sync is done
async start() {
2018-12-21 19:05:24 +05:30
if (this._isSyncing) {
return;
}
this._isSyncing = true;
try {
2019-02-04 02:47:24 +05:30
let syncToken = session.syncToken;
// do initial sync if needed
if (!syncToken) {
syncToken = await this._syncRequest();
}
2018-12-21 19:05:24 +05:30
} catch(err) {
//expected when stop is called
if (err instanceof RequestAbortError) {
} else if (err instanceof HomeServerError) {
} else {
// something threw something
}
}
2019-02-04 02:47:24 +05:30
this._syncLoop(syncToken);
2018-12-21 19:05:24 +05:30
}
async _syncLoop(syncToken) {
2019-02-04 02:47:24 +05:30
// if syncToken is falsy, it will first do an initial sync ...
2018-12-21 19:05:24 +05:30
while(this._isSyncing) {
2019-02-04 02:47:24 +05:30
try {
syncToken = await this._syncRequest(INCREMENTAL_TIMEOUT, syncToken);
} catch (err) {
this.emit("error", err);
}
}
}
async _syncRequest(timeout, syncToken) {
this._currentRequest = this._network.sync(timeout, syncToken);
const response = await this._currentRequest.response;
syncToken = response.next_batch;
2019-02-05 04:51:50 +05:30
const storeNames = this._storage.storeNames;
const txn = this._storage.startReadWriteTxn([
storeNames.timeline,
storeNames.sync,
storeNames.state
]);
2019-02-04 02:47:24 +05:30
try {
session.applySync(syncToken, response.account_data, txn);
2018-12-21 19:05:24 +05:30
// to_device
// presence
2019-02-04 02:47:24 +05:30
parseRooms(response.rooms, async (roomId, roomResponse, membership) => {
2018-12-21 19:05:24 +05:30
let room = session.getRoom(roomId);
if (!room) {
2019-02-04 02:47:24 +05:30
room = session.createRoom(roomId, txn);
2018-12-21 19:05:24 +05:30
}
2019-02-04 02:47:24 +05:30
room.applySync(roomResponse, membership, txn);
2018-12-21 19:05:24 +05:30
});
2019-02-04 02:47:24 +05:30
} catch(err) {
// avoid corrupting state by only
// storing the sync up till the point
// the exception occurred
txn.abort();
throw err;
}
try {
await txn.complete();
} catch (err) {
throw new StorageError("unable to commit sync tranaction", err);
2018-12-21 19:05:24 +05:30
}
2019-02-04 02:47:24 +05:30
return syncToken;
2018-12-21 19:05:24 +05:30
}
stop() {
if (!this._isSyncing) {
return;
}
this._isSyncing = false;
if (this._currentRequest) {
this._currentRequest.abort();
this._currentRequest = null;
}
}
}