From f4983b5ba625d12e72d5433f72ef3242cb70b94a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 20 Apr 2020 22:49:14 +0200 Subject: [PATCH] port SessionPickerViewModel to SessionContainer --- src/domain/SessionPickerViewModel.js | 47 +++++++++++++++++++++++++--- src/main.js | 4 ++- src/matrix/SessionContainer.js | 47 ++++------------------------ 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src/domain/SessionPickerViewModel.js b/src/domain/SessionPickerViewModel.js index 66807e58..98fe89f4 100644 --- a/src/domain/SessionPickerViewModel.js +++ b/src/domain/SessionPickerViewModel.js @@ -1,6 +1,7 @@ import {SortedArray} from "../observable/index.js"; import {EventEmitter} from "../utils/EventEmitter.js"; -import {createNewSessionId} from "./BrawlViewModel.js" +import {LoadStatus} from "../matrix/SessionContainer.js"; +import {SyncStatus} from "../matrix/Sync.js"; class SessionItemViewModel extends EventEmitter { constructor(sessionInfo, pickerVM) { @@ -99,22 +100,58 @@ class SessionItemViewModel extends EventEmitter { } export class SessionPickerViewModel { - constructor({storageFactory, sessionInfoStorage, sessionCallback}) { + constructor({storageFactory, sessionInfoStorage, sessionCallback, createSessionContainer}) { this._storageFactory = storageFactory; this._sessionInfoStorage = sessionInfoStorage; this._sessionCallback = sessionCallback; + this._createSessionContainer = createSessionContainer; this._sessions = new SortedArray((s1, s2) => s1.id.localeCompare(s2.id)); + this._loading = false; } + // this loads all the sessions async load() { const sessions = await this._sessionInfoStorage.getAll(); this._sessions.setManyUnsorted(sessions.map(s => new SessionItemViewModel(s, this))); } - pick(id) { + // this is the loading of a single picked session + get loading() { + return this._loading; + } + + get loadStatus() { + return this._sessionContainer && this._sessionContainer.loadStatus; + } + + get loadError() { + if (this._sessionContainer) { + const error = this._sessionContainer.loadError; + if (error) { + return error.message; + } + } + return null; + } + + async pick(id) { const sessionVM = this._sessions.array.find(s => s.id === id); if (sessionVM) { - this._sessionCallback(sessionVM.sessionInfo); + this._loading = true; + this.emit("change", "loading"); + this._sessionContainer = this._createSessionContainer(); + this._sessionContainer.startWithExistingSession(sessionVM.sessionInfo.id); + // TODO: allow to cancel here + const waitHandle = this._sessionContainer.loadStatus.waitFor(s => { + this.emit("change", "loadStatus"); + // wait for initial sync, but not catchup sync + return ( + s === LoadStatus.FirstSync && + this._sessionContainer.sync.status === SyncStatus.CatchupSync + ) || s === LoadStatus.Ready; + }); + await waitHandle.promise; + this._sessionCallback(this._sessionContainer); } } @@ -129,7 +166,7 @@ export class SessionPickerViewModel { const data = JSON.parse(json); const {sessionInfo} = data; sessionInfo.comment = `Imported on ${new Date().toLocaleString()} from id ${sessionInfo.id}.`; - sessionInfo.id = createNewSessionId(); + sessionInfo.id = this._createSessionContainer().createNewSessionId(); await this._storageFactory.import(sessionInfo.id, data.stores); await this._sessionInfoStorage.add(sessionInfo); this._sessions.set(new SessionItemViewModel(sessionInfo, this)); diff --git a/src/main.js b/src/main.js index 7e0643bb..c9440927 100644 --- a/src/main.js +++ b/src/main.js @@ -23,19 +23,21 @@ export default async function main(container) { const request = fetchRequest; const sessionInfoStorage = new SessionInfoStorage("brawl_sessions_v1"); const clock = new Clock(); + const storageFactory = new StorageFactory(); const vm = new BrawlViewModel({ createSessionContainer: () => { return new SessionContainer({ random: Math.random, onlineStatus: new OnlineStatus(), - storageFactory: new StorageFactory(), + storageFactory, sessionInfoStorage, request, clock, }); }, sessionInfoStorage, + storageFactory, clock, }); await vm.load(); diff --git a/src/matrix/SessionContainer.js b/src/matrix/SessionContainer.js index 504d1034..f0445163 100644 --- a/src/matrix/SessionContainer.js +++ b/src/matrix/SessionContainer.js @@ -43,7 +43,7 @@ export class SessionContainer { this._storage = null; } - _createNewSessionId() { + createNewSessionId() { return (Math.floor(this._random() * Number.MAX_SAFE_INTEGER)).toString(); } @@ -54,6 +54,9 @@ export class SessionContainer { this._status.set(LoadStatus.Loading); try { const sessionInfo = await this._sessionInfoStorage.get(sessionId); + if (!sessionInfo) { + throw new Error("Invalid session id: " + sessionId); + } await this._loadSessionInfo(sessionInfo); } catch (err) { this._error = err; @@ -70,7 +73,7 @@ export class SessionContainer { try { const hsApi = new HomeServerApi({homeServer, request: this._request}); const loginData = await hsApi.passwordLogin(username, password).response(); - const sessionId = this._createNewSessionId(); + const sessionId = this.createNewSessionId(); sessionInfo = { id: sessionId, deviceId: loginData.device_id, @@ -211,6 +214,7 @@ export class SessionContainer { } if (this._storage) { this._storage.close(); + this._storage = null; } } @@ -226,42 +230,3 @@ export class SessionContainer { } } } - -/* -function main() { - // these are only required for external classes, - // SessionFactory has it's defaults for internal classes - const sessionFactory = new SessionFactory({ - Clock: DOMClock, - OnlineState: DOMOnlineState, - SessionInfoStorage: LocalStorageSessionStore, // should be called SessionInfoStore? - StorageFactory: window.indexedDB ? IDBStorageFactory : MemoryStorageFactory, // should be called StorageManager? - // should be moved to StorageFactory as `KeyBounds`?: minStorageKey, middleStorageKey, maxStorageKey - // would need to pass it into EventKey though - request, - }); - - // lets not do this in a first cut - // internally in the matrix lib - const room = new creator.ctor("Room", Room)({}); - - // or short - const sessionFactory = new SessionFactory(WebFactory); - // sessionFactory.sessionInfoStore - - // registration - // const registration = sessionFactory.registerUser(); - // registration.stage - - - const container = sessionFactory.startWithRegistration(registration); - const container = sessionFactory.startWithLogin(server, username, password); - const container = sessionFactory.startWithExistingSession(sessionId); - // container.loadStatus is an ObservableValue - await container.loadStatus.waitFor(s => s === LoadStatus.FirstSync && container.sync.status === SyncStatus.CatchupSync || s === LoadStatus.Ready); - - // loader isn't needed anymore from now on - const {session, sync, reconnector} = container; - container.stop(); -} -*/