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/matrix/sync.js

132 lines
4.4 KiB
JavaScript
Raw Normal View History

import {RequestAbortError} from "./error.js";
2019-02-21 04:18:16 +05:30
import EventEmitter from "../EventEmitter.js";
2018-12-21 19:05:24 +05:30
2019-02-11 01:55:29 +05:30
const INCREMENTAL_TIMEOUT = 30000;
const SYNC_EVENT_LIMIT = 10;
2018-12-21 19:05:24 +05:30
2019-02-11 01:55:29 +05:30
function parseRooms(roomsSection, roomCallback) {
if (roomsSection) {
const allMemberships = ["join", "invite", "leave"];
for(const membership of allMemberships) {
const membershipSection = roomsSection[membership];
if (membershipSection) {
return Object.entries(membershipSection).map(([roomId, roomResponse]) => {
return roomCallback(roomId, roomResponse, membership);
});
2019-05-12 23:56:46 +05:30
}
}
}
return [];
2019-02-05 03:56:45 +05:30
}
2019-02-11 01:55:29 +05:30
export default class Sync extends EventEmitter {
2019-05-12 23:56:46 +05:30
constructor(hsApi, session, storage) {
super();
this._hsApi = hsApi;
this._session = session;
this._storage = storage;
this._isSyncing = false;
this._currentRequest = null;
}
get isSyncing() {
return this._isSyncing;
}
2019-05-12 23:56:46 +05:30
// returns when initial sync is done
async start() {
if (this._isSyncing) {
return;
}
this._isSyncing = true;
this.emit("status", "started");
2019-05-12 23:56:46 +05:30
let syncToken = this._session.syncToken;
// do initial sync if needed
if (!syncToken) {
// need to create limit filter here
syncToken = await this._syncRequest();
}
this._syncLoop(syncToken);
}
2018-12-21 19:05:24 +05:30
2019-05-12 23:56:46 +05:30
async _syncLoop(syncToken) {
// if syncToken is falsy, it will first do an initial sync ...
while(this._isSyncing) {
try {
console.log(`starting sync request with since ${syncToken} ...`);
syncToken = await this._syncRequest(syncToken, INCREMENTAL_TIMEOUT);
} catch (err) {
this._isSyncing = false;
if (!(err instanceof RequestAbortError)) {
2019-06-16 19:19:00 +05:30
console.error("stopping sync because of error", err.stack);
this.emit("status", "error", err);
2019-05-12 23:56:46 +05:30
}
}
}
this.emit("status", "stopped");
2019-05-12 23:56:46 +05:30
}
2019-02-04 02:47:24 +05:30
2019-05-12 23:56:46 +05:30
async _syncRequest(syncToken, timeout) {
this._currentRequest = this._hsApi.sync(syncToken, undefined, timeout);
const response = await this._currentRequest.response();
syncToken = response.next_batch;
const storeNames = this._storage.storeNames;
const syncTxn = await this._storage.readWriteTxn([
storeNames.session,
storeNames.roomSummary,
storeNames.roomState,
2019-05-12 23:56:46 +05:30
storeNames.timelineEvents,
2019-05-20 00:19:46 +05:30
storeNames.timelineFragments,
2019-05-12 23:56:46 +05:30
]);
const roomChanges = [];
try {
2019-03-09 00:31:28 +05:30
this._session.persistSync(syncToken, response.account_data, syncTxn);
// to_device
// presence
2019-05-12 23:56:46 +05:30
if (response.rooms) {
const promises = parseRooms(response.rooms, async (roomId, roomResponse, membership) => {
2019-05-12 23:56:46 +05:30
let room = this._session.rooms.get(roomId);
if (!room) {
room = this._session.createRoom(roomId);
}
console.log(` * applying sync response to room ${roomId} ...`);
const changes = await room.persistSync(roomResponse, membership, syncTxn);
roomChanges.push({room, changes});
2019-05-12 23:56:46 +05:30
});
await Promise.all(promises);
2019-05-12 23:56:46 +05:30
}
} catch(err) {
2019-06-02 18:29:30 +05:30
console.warn("aborting syncTxn because of error");
2019-05-12 23:56:46 +05:30
// avoid corrupting state by only
// storing the sync up till the point
// the exception occurred
syncTxn.abort();
throw err;
}
try {
await syncTxn.complete();
console.info("syncTxn committed!!");
} catch (err) {
console.error("unable to commit sync tranaction", err.message);
throw err;
2019-05-12 23:56:46 +05:30
}
// emit room related events after txn has been closed
for(let {room, changes} of roomChanges) {
room.emitSync(changes);
}
2019-05-12 23:56:46 +05:30
return syncToken;
}
2018-12-21 19:05:24 +05:30
2019-05-12 23:56:46 +05:30
stop() {
if (!this._isSyncing) {
return;
}
this._isSyncing = false;
if (this._currentRequest) {
this._currentRequest.abort();
this._currentRequest = null;
}
}
2019-02-21 04:18:16 +05:30
}