mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-23 03:25:12 +01:00
finish implemenation of SessionContainer
This commit is contained in:
parent
87b23d062c
commit
164d9d594f
@ -42,7 +42,8 @@ rooms should report how many messages they have queued up, and each time they se
|
|||||||
- decide whether we want to inherit (no?)
|
- decide whether we want to inherit (no?)
|
||||||
- DONE: cleanup Reconnector with recent changes, move generic code, make imports work
|
- DONE: cleanup Reconnector with recent changes, move generic code, make imports work
|
||||||
- DONE: add SyncStatus as ObservableValue of enum in Sync
|
- DONE: add SyncStatus as ObservableValue of enum in Sync
|
||||||
- cleanup SessionContainer
|
- DONE: cleanup SessionContainer
|
||||||
|
- move all imports to non-default
|
||||||
- change main.js to pass in a creation function of a SessionContainer instead of everything it is replacing
|
- change main.js to pass in a creation function of a SessionContainer instead of everything it is replacing
|
||||||
- show load progress in LoginView/SessionPickView and do away with loading screen
|
- show load progress in LoginView/SessionPickView and do away with loading screen
|
||||||
- adjust BrawlViewModel, SessionPickViewModel and LoginViewModel to use a SessionContainer
|
- adjust BrawlViewModel, SessionPickViewModel and LoginViewModel to use a SessionContainer
|
||||||
|
@ -48,7 +48,7 @@ export class SendScheduler {
|
|||||||
this._hsApi = hsApi;
|
this._hsApi = hsApi;
|
||||||
this._sendRequests = [];
|
this._sendRequests = [];
|
||||||
this._sendScheduled = false;
|
this._sendScheduled = false;
|
||||||
this._offline = false;
|
this._stopped = false;
|
||||||
this._waitTime = 0;
|
this._waitTime = 0;
|
||||||
this._backoff = backoff;
|
this._backoff = backoff;
|
||||||
/*
|
/*
|
||||||
@ -66,6 +66,14 @@ export class SendScheduler {
|
|||||||
// TODO: abort current requests and set offline
|
// TODO: abort current requests and set offline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this._stopped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isStarted() {
|
||||||
|
return !this._stopped;
|
||||||
|
}
|
||||||
|
|
||||||
// this should really be per roomId to avoid head-of-line blocking
|
// this should really be per roomId to avoid head-of-line blocking
|
||||||
//
|
//
|
||||||
// takes a callback instead of returning a promise with the slot
|
// takes a callback instead of returning a promise with the slot
|
||||||
@ -74,7 +82,7 @@ export class SendScheduler {
|
|||||||
let request;
|
let request;
|
||||||
const promise = new Promise((resolve, reject) => request = {resolve, reject, sendCallback});
|
const promise = new Promise((resolve, reject) => request = {resolve, reject, sendCallback});
|
||||||
this._sendRequests.push(request);
|
this._sendRequests.push(request);
|
||||||
if (!this._sendScheduled && !this._offline) {
|
if (!this._sendScheduled && !this._stopped) {
|
||||||
this._sendLoop();
|
this._sendLoop();
|
||||||
}
|
}
|
||||||
return promise;
|
return promise;
|
||||||
@ -91,7 +99,7 @@ export class SendScheduler {
|
|||||||
if (err instanceof ConnectionError) {
|
if (err instanceof ConnectionError) {
|
||||||
// we're offline, everybody will have
|
// we're offline, everybody will have
|
||||||
// to re-request slots when we come back online
|
// to re-request slots when we come back online
|
||||||
this._offline = true;
|
this._stopped = true;
|
||||||
for (const r of this._sendRequests) {
|
for (const r of this._sendRequests) {
|
||||||
r.reject(err);
|
r.reject(err);
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,28 @@ export default class Session {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isStarted() {
|
||||||
|
return this._sendScheduler.isStarted;
|
||||||
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
this._sendScheduler.stop();
|
this._sendScheduler.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
start(lastVersionResponse) {
|
async start(lastVersionResponse) {
|
||||||
|
if (lastVersionResponse) {
|
||||||
|
// store /versions response
|
||||||
|
const txn = await this._storage.readWriteTxn([
|
||||||
|
this._storage.storeNames.session
|
||||||
|
]);
|
||||||
|
const newSessionData = Object.assign({}, this._session, {serverVersions: lastVersionResponse});
|
||||||
|
txn.session.set(newSessionData);
|
||||||
|
// TODO: what can we do if this throws?
|
||||||
|
await txn.complete();
|
||||||
|
this._session = newSessionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sendScheduler.start();
|
||||||
for (const [, room] of this._rooms) {
|
for (const [, room] of this._rooms) {
|
||||||
room.resumeSending();
|
room.resumeSending();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
|
import createEnum from "../utils/enum.js";
|
||||||
|
import ObservableValue from "../observable/ObservableValue.js";
|
||||||
import HomeServerApi from "./net/HomeServerApi.js";
|
import HomeServerApi from "./net/HomeServerApi.js";
|
||||||
|
import {Reconnector, ConnectionStatus} from "./net/Reconnector.js";
|
||||||
|
import ExponentialRetryDelay from "./net/ExponentialRetryDelay.js";
|
||||||
|
import {HomeServerError, ConnectionError, AbortError} from "./error.js";
|
||||||
|
import {Sync, SyncStatus} from "./Sync.js";
|
||||||
|
import Session from "./Session.js";
|
||||||
|
|
||||||
export const LoadStatus = createEnum(
|
export const LoadStatus = createEnum(
|
||||||
"NotLoading",
|
"NotLoading",
|
||||||
@ -12,19 +19,19 @@ export const LoadStatus = createEnum(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const LoginFailure = createEnum(
|
export const LoginFailure = createEnum(
|
||||||
"Network",
|
"Connection",
|
||||||
"Credentials",
|
"Credentials",
|
||||||
"Unknown",
|
"Unknown",
|
||||||
);
|
);
|
||||||
|
|
||||||
export class SessionContainer {
|
export class SessionContainer {
|
||||||
constructor({clock, random, onlineStatus, request, storageFactory, sessionsStore}) {
|
constructor({clock, random, onlineStatus, request, storageFactory, sessionInfoStorage}) {
|
||||||
this._random = random;
|
this._random = random;
|
||||||
this._clock = clock;
|
this._clock = clock;
|
||||||
this._onlineStatus = onlineStatus;
|
this._onlineStatus = onlineStatus;
|
||||||
this._request = request;
|
this._request = request;
|
||||||
this._storageFactory = storageFactory;
|
this._storageFactory = storageFactory;
|
||||||
this._sessionsStore = sessionsStore;
|
this._sessionInfoStorage = sessionInfoStorage;
|
||||||
|
|
||||||
this._status = new ObservableValue(LoadStatus.NotLoading);
|
this._status = new ObservableValue(LoadStatus.NotLoading);
|
||||||
this._error = null;
|
this._error = null;
|
||||||
@ -44,7 +51,7 @@ export class SessionContainer {
|
|||||||
}
|
}
|
||||||
this._status.set(LoadStatus.Loading);
|
this._status.set(LoadStatus.Loading);
|
||||||
try {
|
try {
|
||||||
const sessionInfo = await this._sessionsStore.get(sessionId);
|
const sessionInfo = await this._sessionInfoStorage.get(sessionId);
|
||||||
await this._loadSessionInfo(sessionInfo);
|
await this._loadSessionInfo(sessionInfo);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = err;
|
this._error = err;
|
||||||
@ -70,7 +77,7 @@ export class SessionContainer {
|
|||||||
accessToken: loginData.access_token,
|
accessToken: loginData.access_token,
|
||||||
lastUsed: this._clock.now()
|
lastUsed: this._clock.now()
|
||||||
};
|
};
|
||||||
await this._sessionsStore.add(sessionInfo);
|
await this._sessionInfoStorage.add(sessionInfo);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = err;
|
this._error = err;
|
||||||
if (err instanceof HomeServerError) {
|
if (err instanceof HomeServerError) {
|
||||||
@ -81,7 +88,7 @@ export class SessionContainer {
|
|||||||
}
|
}
|
||||||
this._status.set(LoadStatus.LoginFailure);
|
this._status.set(LoadStatus.LoginFailure);
|
||||||
} else if (err instanceof ConnectionError) {
|
} else if (err instanceof ConnectionError) {
|
||||||
this._loginFailure = LoginFailure.Network;
|
this._loginFailure = LoginFailure.Connection;
|
||||||
this._status.set(LoadStatus.LoginFailure);
|
this._status.set(LoadStatus.LoginFailure);
|
||||||
} else {
|
} else {
|
||||||
this._status.set(LoadStatus.Error);
|
this._status.set(LoadStatus.Error);
|
||||||
@ -122,12 +129,6 @@ export class SessionContainer {
|
|||||||
this._session = new Session({storage, sessionInfo: filteredSessionInfo, hsApi});
|
this._session = new Session({storage, sessionInfo: filteredSessionInfo, hsApi});
|
||||||
await this._session.load();
|
await this._session.load();
|
||||||
|
|
||||||
const needsInitialSync = !this._session.syncToken;
|
|
||||||
if (!needsInitialSync) {
|
|
||||||
this._status.set(LoadStatus.CatchupSync);
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
|
|
||||||
this._sync = new Sync({hsApi, storage, session: this._session});
|
this._sync = new Sync({hsApi, storage, session: this._session});
|
||||||
// notify sync and session when back online
|
// notify sync and session when back online
|
||||||
this._reconnectSubscription = this._reconnector.connectionStatus.subscribe(state => {
|
this._reconnectSubscription = this._reconnector.connectionStatus.subscribe(state => {
|
||||||
@ -137,17 +138,23 @@ export class SessionContainer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
await this._waitForFirstSync();
|
await this._waitForFirstSync();
|
||||||
|
|
||||||
this._status.set(LoadStatus.Ready);
|
this._status.set(LoadStatus.Ready);
|
||||||
|
|
||||||
// if this fails, the reconnector will start polling versions to reconnect
|
// if the sync failed, and then the reconnector
|
||||||
|
// restored the connection, it would have already
|
||||||
|
// started to session, so check first
|
||||||
|
// to prevent an extra /versions request
|
||||||
|
if (!this._session.isStarted) {
|
||||||
const lastVersionsResponse = await hsApi.versions({timeout: 10000}).response();
|
const lastVersionsResponse = await hsApi.versions({timeout: 10000}).response();
|
||||||
this._session.start(lastVersionsResponse);
|
this._session.start(lastVersionsResponse);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async _waitForFirstSync() {
|
async _waitForFirstSync() {
|
||||||
try {
|
try {
|
||||||
this._sync.start();
|
|
||||||
this._status.set(LoadStatus.FirstSync);
|
this._status.set(LoadStatus.FirstSync);
|
||||||
|
this._sync.start();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// swallow ConnectionError here and continue,
|
// swallow ConnectionError here and continue,
|
||||||
// as the reconnector above will call
|
// as the reconnector above will call
|
||||||
@ -209,7 +216,7 @@ function main() {
|
|||||||
const sessionFactory = new SessionFactory({
|
const sessionFactory = new SessionFactory({
|
||||||
Clock: DOMClock,
|
Clock: DOMClock,
|
||||||
OnlineState: DOMOnlineState,
|
OnlineState: DOMOnlineState,
|
||||||
SessionsStore: LocalStorageSessionStore, // should be called SessionInfoStore?
|
SessionInfoStorage: LocalStorageSessionStore, // should be called SessionInfoStore?
|
||||||
StorageFactory: window.indexedDB ? IDBStorageFactory : MemoryStorageFactory, // should be called StorageManager?
|
StorageFactory: window.indexedDB ? IDBStorageFactory : MemoryStorageFactory, // should be called StorageManager?
|
||||||
// should be moved to StorageFactory as `KeyBounds`?: minStorageKey, middleStorageKey, maxStorageKey
|
// should be moved to StorageFactory as `KeyBounds`?: minStorageKey, middleStorageKey, maxStorageKey
|
||||||
// would need to pass it into EventKey though
|
// would need to pass it into EventKey though
|
||||||
@ -233,7 +240,7 @@ function main() {
|
|||||||
const container = sessionFactory.startWithLogin(server, username, password);
|
const container = sessionFactory.startWithLogin(server, username, password);
|
||||||
const container = sessionFactory.startWithExistingSession(sessionId);
|
const container = sessionFactory.startWithExistingSession(sessionId);
|
||||||
// container.loadStatus is an ObservableValue<LoadStatus>
|
// container.loadStatus is an ObservableValue<LoadStatus>
|
||||||
await container.loadStatus.waitFor(s => s === LoadStatus.Loaded || s === LoadStatus.CatchupSync);
|
await container.loadStatus.waitFor(s => s === LoadStatus.FirstSync && container.sync.status === SyncStatus.CatchupSync || s === LoadStatus.Ready);
|
||||||
|
|
||||||
// loader isn't needed anymore from now on
|
// loader isn't needed anymore from now on
|
||||||
const {session, sync, reconnector} = container;
|
const {session, sync, reconnector} = container;
|
||||||
|
Loading…
Reference in New Issue
Block a user