port SessionPickerViewModel to SessionContainer

This commit is contained in:
Bruno Windels 2020-04-20 22:49:14 +02:00
parent a5965ad378
commit f4983b5ba6
3 changed files with 51 additions and 47 deletions

View File

@ -1,6 +1,7 @@
import {SortedArray} from "../observable/index.js"; import {SortedArray} from "../observable/index.js";
import {EventEmitter} from "../utils/EventEmitter.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 { class SessionItemViewModel extends EventEmitter {
constructor(sessionInfo, pickerVM) { constructor(sessionInfo, pickerVM) {
@ -99,22 +100,58 @@ class SessionItemViewModel extends EventEmitter {
} }
export class SessionPickerViewModel { export class SessionPickerViewModel {
constructor({storageFactory, sessionInfoStorage, sessionCallback}) { constructor({storageFactory, sessionInfoStorage, sessionCallback, createSessionContainer}) {
this._storageFactory = storageFactory; this._storageFactory = storageFactory;
this._sessionInfoStorage = sessionInfoStorage; this._sessionInfoStorage = sessionInfoStorage;
this._sessionCallback = sessionCallback; this._sessionCallback = sessionCallback;
this._createSessionContainer = createSessionContainer;
this._sessions = new SortedArray((s1, s2) => s1.id.localeCompare(s2.id)); this._sessions = new SortedArray((s1, s2) => s1.id.localeCompare(s2.id));
this._loading = false;
} }
// this loads all the sessions
async load() { async load() {
const sessions = await this._sessionInfoStorage.getAll(); const sessions = await this._sessionInfoStorage.getAll();
this._sessions.setManyUnsorted(sessions.map(s => new SessionItemViewModel(s, this))); 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); const sessionVM = this._sessions.array.find(s => s.id === id);
if (sessionVM) { 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 data = JSON.parse(json);
const {sessionInfo} = data; const {sessionInfo} = data;
sessionInfo.comment = `Imported on ${new Date().toLocaleString()} from id ${sessionInfo.id}.`; 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._storageFactory.import(sessionInfo.id, data.stores);
await this._sessionInfoStorage.add(sessionInfo); await this._sessionInfoStorage.add(sessionInfo);
this._sessions.set(new SessionItemViewModel(sessionInfo, this)); this._sessions.set(new SessionItemViewModel(sessionInfo, this));

View File

@ -23,19 +23,21 @@ export default async function main(container) {
const request = fetchRequest; const request = fetchRequest;
const sessionInfoStorage = new SessionInfoStorage("brawl_sessions_v1"); const sessionInfoStorage = new SessionInfoStorage("brawl_sessions_v1");
const clock = new Clock(); const clock = new Clock();
const storageFactory = new StorageFactory();
const vm = new BrawlViewModel({ const vm = new BrawlViewModel({
createSessionContainer: () => { createSessionContainer: () => {
return new SessionContainer({ return new SessionContainer({
random: Math.random, random: Math.random,
onlineStatus: new OnlineStatus(), onlineStatus: new OnlineStatus(),
storageFactory: new StorageFactory(), storageFactory,
sessionInfoStorage, sessionInfoStorage,
request, request,
clock, clock,
}); });
}, },
sessionInfoStorage, sessionInfoStorage,
storageFactory,
clock, clock,
}); });
await vm.load(); await vm.load();

View File

@ -43,7 +43,7 @@ export class SessionContainer {
this._storage = null; this._storage = null;
} }
_createNewSessionId() { createNewSessionId() {
return (Math.floor(this._random() * Number.MAX_SAFE_INTEGER)).toString(); return (Math.floor(this._random() * Number.MAX_SAFE_INTEGER)).toString();
} }
@ -54,6 +54,9 @@ export class SessionContainer {
this._status.set(LoadStatus.Loading); this._status.set(LoadStatus.Loading);
try { try {
const sessionInfo = await this._sessionInfoStorage.get(sessionId); const sessionInfo = await this._sessionInfoStorage.get(sessionId);
if (!sessionInfo) {
throw new Error("Invalid session id: " + sessionId);
}
await this._loadSessionInfo(sessionInfo); await this._loadSessionInfo(sessionInfo);
} catch (err) { } catch (err) {
this._error = err; this._error = err;
@ -70,7 +73,7 @@ export class SessionContainer {
try { try {
const hsApi = new HomeServerApi({homeServer, request: this._request}); const hsApi = new HomeServerApi({homeServer, request: this._request});
const loginData = await hsApi.passwordLogin(username, password).response(); const loginData = await hsApi.passwordLogin(username, password).response();
const sessionId = this._createNewSessionId(); const sessionId = this.createNewSessionId();
sessionInfo = { sessionInfo = {
id: sessionId, id: sessionId,
deviceId: loginData.device_id, deviceId: loginData.device_id,
@ -211,6 +214,7 @@ export class SessionContainer {
} }
if (this._storage) { if (this._storage) {
this._storage.close(); 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<LoadStatus>
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();
}
*/