From fe26f48c47479383f34e2e86c9163a4838b8d7bb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 22 Dec 2021 17:09:52 +0100 Subject: [PATCH 1/5] rename SessionContainer to Client --- src/domain/RootViewModel.js | 40 ++++++++-------- src/domain/SessionLoadViewModel.js | 48 +++++++++---------- src/domain/login/CompleteSSOLoginViewModel.js | 8 ++-- src/domain/login/LoginViewModel.js | 30 ++++++------ src/domain/login/PasswordLoginViewModel.js | 2 +- src/domain/session/RoomViewModelObservable.js | 2 +- src/domain/session/SessionViewModel.js | 30 ++++++------ .../session/settings/SettingsViewModel.js | 8 ++-- src/lib.ts | 4 +- src/matrix/{SessionContainer.js => Client.js} | 2 +- src/matrix/Session.js | 2 +- src/platform/web/main.js | 6 +-- 12 files changed, 91 insertions(+), 91 deletions(-) rename src/matrix/{SessionContainer.js => Client.js} (99%) diff --git a/src/domain/RootViewModel.js b/src/domain/RootViewModel.js index d9949c77..4541ee22 100644 --- a/src/domain/RootViewModel.js +++ b/src/domain/RootViewModel.js @@ -23,13 +23,13 @@ import {ViewModel} from "./ViewModel.js"; export class RootViewModel extends ViewModel { constructor(options) { super(options); - this._createSessionContainer = options.createSessionContainer; + this._createClient = options.createClient; this._error = null; this._sessionPickerViewModel = null; this._sessionLoadViewModel = null; this._loginViewModel = null; this._sessionViewModel = null; - this._pendingSessionContainer = null; + this._pendingClient = null; } async load() { @@ -53,16 +53,16 @@ export class RootViewModel extends ViewModel { } } else if (sessionId) { if (!this._sessionViewModel || this._sessionViewModel.id !== sessionId) { - // see _showLogin for where _pendingSessionContainer comes from - if (this._pendingSessionContainer && this._pendingSessionContainer.sessionId === sessionId) { - const sessionContainer = this._pendingSessionContainer; - this._pendingSessionContainer = null; - this._showSession(sessionContainer); + // see _showLogin for where _pendingClient comes from + if (this._pendingClient && this._pendingClient.sessionId === sessionId) { + const client = this._pendingClient; + this._pendingClient = null; + this._showSession(client); } else { // this should never happen, but we want to be sure not to leak it - if (this._pendingSessionContainer) { - this._pendingSessionContainer.dispose(); - this._pendingSessionContainer = null; + if (this._pendingClient) { + this._pendingClient.dispose(); + this._pendingClient = null; } this._showSessionLoader(sessionId); } @@ -106,8 +106,8 @@ export class RootViewModel extends ViewModel { this._setSection(() => { this._loginViewModel = new LoginViewModel(this.childOptions({ defaultHomeserver: this.platform.config["defaultHomeServer"], - createSessionContainer: this._createSessionContainer, - ready: sessionContainer => { + createClient: this._createClient, + ready: client => { // we don't want to load the session container again, // but we also want the change of screen to go through the navigation // so we store the session container in a temporary variable that will be @@ -116,28 +116,28 @@ export class RootViewModel extends ViewModel { // Also, we should not call _setSection before the navigation is in the correct state, // as url creation (e.g. in RoomTileViewModel) // won't be using the correct navigation base path. - this._pendingSessionContainer = sessionContainer; - this.navigation.push("session", sessionContainer.sessionId); + this._pendingClient = client; + this.navigation.push("session", client.sessionId); }, loginToken })); }); } - _showSession(sessionContainer) { + _showSession(client) { this._setSection(() => { - this._sessionViewModel = new SessionViewModel(this.childOptions({sessionContainer})); + this._sessionViewModel = new SessionViewModel(this.childOptions({client})); this._sessionViewModel.start(); }); } _showSessionLoader(sessionId) { - const sessionContainer = this._createSessionContainer(); - sessionContainer.startWithExistingSession(sessionId); + const client = this._createClient(); + client.startWithExistingSession(sessionId); this._setSection(() => { this._sessionLoadViewModel = new SessionLoadViewModel(this.childOptions({ - sessionContainer, - ready: sessionContainer => this._showSession(sessionContainer) + client, + ready: client => this._showSession(client) })); this._sessionLoadViewModel.start(); }); diff --git a/src/domain/SessionLoadViewModel.js b/src/domain/SessionLoadViewModel.js index c798bc67..24df2546 100644 --- a/src/domain/SessionLoadViewModel.js +++ b/src/domain/SessionLoadViewModel.js @@ -15,15 +15,15 @@ limitations under the License. */ import {AccountSetupViewModel} from "./AccountSetupViewModel.js"; -import {LoadStatus} from "../matrix/SessionContainer.js"; +import {LoadStatus} from "../matrix/Client.js"; import {SyncStatus} from "../matrix/Sync.js"; import {ViewModel} from "./ViewModel.js"; export class SessionLoadViewModel extends ViewModel { constructor(options) { super(options); - const {sessionContainer, ready, homeserver, deleteSessionOnCancel} = options; - this._sessionContainer = sessionContainer; + const {client, ready, homeserver, deleteSessionOnCancel} = options; + this._client = client; this._ready = ready; this._homeserver = homeserver; this._deleteSessionOnCancel = deleteSessionOnCancel; @@ -41,16 +41,16 @@ export class SessionLoadViewModel extends ViewModel { try { this._loading = true; this.emitChange("loading"); - this._waitHandle = this._sessionContainer.loadStatus.waitFor(s => { + this._waitHandle = this._client.loadStatus.waitFor(s => { if (s === LoadStatus.AccountSetup) { - this._accountSetupViewModel = new AccountSetupViewModel(this._sessionContainer.accountSetup); + this._accountSetupViewModel = new AccountSetupViewModel(this._client.accountSetup); } else { this._accountSetupViewModel = undefined; } this.emitChange("loadLabel"); // wait for initial sync, but not catchup sync const isCatchupSync = s === LoadStatus.FirstSync && - this._sessionContainer.sync.status.get() === SyncStatus.CatchupSync; + this._client.sync.status.get() === SyncStatus.CatchupSync; return isCatchupSync || s === LoadStatus.LoginFailed || s === LoadStatus.Error || @@ -67,15 +67,15 @@ export class SessionLoadViewModel extends ViewModel { // much like we will once you are in the app. Probably a good idea // did it finish or get stuck at LoginFailed or Error? - const loadStatus = this._sessionContainer.loadStatus.get(); - const loadError = this._sessionContainer.loadError; + const loadStatus = this._client.loadStatus.get(); + const loadError = this._client.loadError; if (loadStatus === LoadStatus.FirstSync || loadStatus === LoadStatus.Ready) { - const sessionContainer = this._sessionContainer; + const client = this._client; // session container is ready, // don't dispose it anymore when // we get disposed - this._sessionContainer = null; - this._ready(sessionContainer); + this._client = null; + this._ready(client); } if (loadError) { console.error("session load error", loadError); @@ -85,16 +85,16 @@ export class SessionLoadViewModel extends ViewModel { console.error("error thrown during session load", err.stack); } finally { this._loading = false; - // loadLabel in case of sc.loadError also gets updated through this + // loadLabel in case of client.loadError also gets updated through this this.emitChange("loading"); } } dispose() { - if (this._sessionContainer) { - this._sessionContainer.dispose(); - this._sessionContainer = null; + if (this._client) { + this._client.dispose(); + this._client = null; } if (this._waitHandle) { // rejects with AbortError @@ -105,23 +105,23 @@ export class SessionLoadViewModel extends ViewModel { // to show a spinner or not get loading() { - const sc = this._sessionContainer; - if (sc && sc.loadStatus.get() === LoadStatus.AccountSetup) { + const client = this._client; + if (client && client.loadStatus.get() === LoadStatus.AccountSetup) { return false; } return this._loading; } get loadLabel() { - const sc = this._sessionContainer; + const client = this._client; const error = this._getError(); - if (error || (sc && sc.loadStatus.get() === LoadStatus.Error)) { + if (error || (client && client.loadStatus.get() === LoadStatus.Error)) { return `Something went wrong: ${error && error.message}.`; } // Statuses related to login are handled by respective login view models - if (sc) { - switch (sc.loadStatus.get()) { + if (client) { + switch (client.loadStatus.get()) { case LoadStatus.QueryAccount: return `Querying account encryption setup…`; case LoadStatus.AccountSetup: @@ -133,7 +133,7 @@ export class SessionLoadViewModel extends ViewModel { case LoadStatus.FirstSync: return `Getting your conversations from the server…`; default: - return this._sessionContainer.loadStatus.get(); + return this._client.loadStatus.get(); } } @@ -141,7 +141,7 @@ export class SessionLoadViewModel extends ViewModel { } _getError() { - return this._error || this._sessionContainer?.loadError; + return this._error || this._client?.loadError; } get hasError() { @@ -154,7 +154,7 @@ export class SessionLoadViewModel extends ViewModel { } async logout() { - await this._sessionContainer.logout(); + await this._client.logout(); this.navigation.push("session", true); } diff --git a/src/domain/login/CompleteSSOLoginViewModel.js b/src/domain/login/CompleteSSOLoginViewModel.js index 7821313a..daa2aa9f 100644 --- a/src/domain/login/CompleteSSOLoginViewModel.js +++ b/src/domain/login/CompleteSSOLoginViewModel.js @@ -15,18 +15,18 @@ limitations under the License. */ import {ViewModel} from "../ViewModel.js"; -import {LoginFailure} from "../../matrix/SessionContainer.js"; +import {LoginFailure} from "../../matrix/Client.js"; export class CompleteSSOLoginViewModel extends ViewModel { constructor(options) { super(options); const { loginToken, - sessionContainer, + client, attemptLogin, } = options; this._loginToken = loginToken; - this._sessionContainer = sessionContainer; + this._client = client; this._attemptLogin = attemptLogin; this._errorMessage = ""; this.performSSOLoginCompletion(); @@ -46,7 +46,7 @@ export class CompleteSSOLoginViewModel extends ViewModel { const homeserver = await this.platform.settingsStorage.getString("sso_ongoing_login_homeserver"); let loginOptions; try { - loginOptions = await this._sessionContainer.queryLogin(homeserver).result; + loginOptions = await this._client.queryLogin(homeserver).result; } catch (err) { this._showError(err.message); diff --git a/src/domain/login/LoginViewModel.js b/src/domain/login/LoginViewModel.js index 6314f347..c44b34f3 100644 --- a/src/domain/login/LoginViewModel.js +++ b/src/domain/login/LoginViewModel.js @@ -18,17 +18,17 @@ import {ViewModel} from "../ViewModel.js"; import {PasswordLoginViewModel} from "./PasswordLoginViewModel.js"; import {StartSSOLoginViewModel} from "./StartSSOLoginViewModel.js"; import {CompleteSSOLoginViewModel} from "./CompleteSSOLoginViewModel.js"; -import {LoadStatus} from "../../matrix/SessionContainer.js"; +import {LoadStatus} from "../../matrix/Client.js"; import {SessionLoadViewModel} from "../SessionLoadViewModel.js"; export class LoginViewModel extends ViewModel { constructor(options) { super(options); - const {ready, defaultHomeserver, createSessionContainer, loginToken} = options; - this._createSessionContainer = createSessionContainer; + const {ready, defaultHomeserver, createClient, loginToken} = options; + this._createClient = createClient; this._ready = ready; this._loginToken = loginToken; - this._sessionContainer = this._createSessionContainer(); + this._client = this._createClient(); this._loginOptions = null; this._passwordLoginViewModel = null; this._startSSOLoginViewModel = null; @@ -66,7 +66,7 @@ export class LoginViewModel extends ViewModel { this._completeSSOLoginViewModel = this.track(new CompleteSSOLoginViewModel( this.childOptions( { - sessionContainer: this._sessionContainer, + client: this._client, attemptLogin: loginMethod => this.attemptLogin(loginMethod), loginToken: this._loginToken }))); @@ -107,14 +107,14 @@ export class LoginViewModel extends ViewModel { async attemptLogin(loginMethod) { this._setBusy(true); - this._sessionContainer.startWithLogin(loginMethod, {inspectAccountSetup: true}); - const loadStatus = this._sessionContainer.loadStatus; + this._client.startWithLogin(loginMethod, {inspectAccountSetup: true}); + const loadStatus = this._client.loadStatus; const handle = loadStatus.waitFor(status => status !== LoadStatus.Login); await handle.promise; this._setBusy(false); const status = loadStatus.get(); if (status === LoadStatus.LoginFailed) { - return this._sessionContainer.loginFailure; + return this._client.loginFailure; } this._hideHomeserver = true; this.emitChange("hideHomeserver"); @@ -129,12 +129,12 @@ export class LoginViewModel extends ViewModel { this._loadViewModel = this.track( new SessionLoadViewModel( this.childOptions({ - ready: (sessionContainer) => { + ready: (client) => { // make sure we don't delete the session in dispose when navigating away - this._sessionContainer = null; - this._ready(sessionContainer); + this._client = null; + this._ready(client); }, - sessionContainer: this._sessionContainer, + client: this._client, homeserver: this._homeserver }) ) @@ -200,7 +200,7 @@ export class LoginViewModel extends ViewModel { // cancel ongoing query operation, if any this._abortQueryOperation = this.disposeTracked(this._abortQueryOperation); try { - const queryOperation = this._sessionContainer.queryLogin(this._homeserver); + const queryOperation = this._client.queryLogin(this._homeserver); this._abortQueryOperation = this.track(() => queryOperation.abort()); this.emitChange("isFetchingLoginOptions"); this._loginOptions = await queryOperation.result; @@ -230,10 +230,10 @@ export class LoginViewModel extends ViewModel { dispose() { super.dispose(); - if (this._sessionContainer) { + if (this._client) { // if we move away before we're done with initial sync // delete the session - this._sessionContainer.deleteSession(); + this._client.deleteSession(); } } } diff --git a/src/domain/login/PasswordLoginViewModel.js b/src/domain/login/PasswordLoginViewModel.js index 7ea239e6..5fd8271f 100644 --- a/src/domain/login/PasswordLoginViewModel.js +++ b/src/domain/login/PasswordLoginViewModel.js @@ -15,7 +15,7 @@ limitations under the License. */ import {ViewModel} from "../ViewModel.js"; -import {LoginFailure} from "../../matrix/SessionContainer.js"; +import {LoginFailure} from "../../matrix/Client.js"; export class PasswordLoginViewModel extends ViewModel { constructor(options) { diff --git a/src/domain/session/RoomViewModelObservable.js b/src/domain/session/RoomViewModelObservable.js index 2a706045..8d576a98 100644 --- a/src/domain/session/RoomViewModelObservable.js +++ b/src/domain/session/RoomViewModelObservable.js @@ -48,7 +48,7 @@ export class RoomViewModelObservable extends ObservableValue { are called in that case. */ async initialize() { - const {session} = this._sessionViewModel._sessionContainer; + const {session} = this._sessionViewModel._client; const statusObservable = await session.observeRoomStatus(this.id); this.set(await this._statusToViewModel(statusObservable.get())); this._statusSubscription = statusObservable.subscribe(async status => { diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index 6aee0d8d..822a4d31 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -30,16 +30,16 @@ import {RightPanelViewModel} from "./rightpanel/RightPanelViewModel.js"; export class SessionViewModel extends ViewModel { constructor(options) { super(options); - const {sessionContainer} = options; - this._sessionContainer = this.track(sessionContainer); + const {client} = options; + this._client = this.track(client); this._sessionStatusViewModel = this.track(new SessionStatusViewModel(this.childOptions({ - sync: sessionContainer.sync, - reconnector: sessionContainer.reconnector, - session: sessionContainer.session, + sync: client.sync, + reconnector: client.reconnector, + session: client.session, }))); this._leftPanelViewModel = this.track(new LeftPanelViewModel(this.childOptions({ - invites: this._sessionContainer.session.invites, - rooms: this._sessionContainer.session.rooms + invites: this._client.session.invites, + rooms: this._client.session.rooms }))); this._settingsViewModel = null; this._roomViewModelObservable = null; @@ -88,7 +88,7 @@ export class SessionViewModel extends ViewModel { } get id() { - return this._sessionContainer.sessionId; + return this._client.sessionId; } start() { @@ -163,7 +163,7 @@ export class SessionViewModel extends ViewModel { } _createRoomViewModel(roomId) { - const room = this._sessionContainer.session.rooms.get(roomId); + const room = this._client.session.rooms.get(roomId); if (room) { const roomVM = new RoomViewModel(this.childOptions({room})); roomVM.load(); @@ -175,12 +175,12 @@ export class SessionViewModel extends ViewModel { _createUnknownRoomViewModel(roomIdOrAlias) { return new UnknownRoomViewModel(this.childOptions({ roomIdOrAlias, - session: this._sessionContainer.session, + session: this._client.session, })); } async _createArchivedRoomViewModel(roomId) { - const room = await this._sessionContainer.session.loadArchivedRoom(roomId); + const room = await this._client.session.loadArchivedRoom(roomId); if (room) { const roomVM = new RoomViewModel(this.childOptions({room})); roomVM.load(); @@ -190,11 +190,11 @@ export class SessionViewModel extends ViewModel { } _createInviteViewModel(roomId) { - const invite = this._sessionContainer.session.invites.get(roomId); + const invite = this._client.session.invites.get(roomId); if (invite) { return new InviteViewModel(this.childOptions({ invite, - mediaRepository: this._sessionContainer.session.mediaRepository, + mediaRepository: this._client.session.mediaRepository, })); } return null; @@ -230,7 +230,7 @@ export class SessionViewModel extends ViewModel { } if (settingsOpen) { this._settingsViewModel = this.track(new SettingsViewModel(this.childOptions({ - sessionContainer: this._sessionContainer, + client: this._client, }))); this._settingsViewModel.load(); } @@ -254,7 +254,7 @@ export class SessionViewModel extends ViewModel { _roomFromNavigation() { const roomId = this.navigation.path.get("room")?.value; - const room = this._sessionContainer.session.rooms.get(roomId); + const room = this._client.session.rooms.get(roomId); return room; } diff --git a/src/domain/session/settings/SettingsViewModel.js b/src/domain/session/settings/SettingsViewModel.js index 9ce340f1..979409b3 100644 --- a/src/domain/session/settings/SettingsViewModel.js +++ b/src/domain/session/settings/SettingsViewModel.js @@ -41,8 +41,8 @@ export class SettingsViewModel extends ViewModel { constructor(options) { super(options); this._updateService = options.updateService; - const {sessionContainer} = options; - this._sessionContainer = sessionContainer; + const {client} = options; + this._client = client; this._sessionBackupViewModel = this.track(new SessionBackupViewModel(this.childOptions({session: this._session}))); this._closeUrl = this.urlCreator.urlUntilSegment("session"); this._estimate = null; @@ -54,12 +54,12 @@ export class SettingsViewModel extends ViewModel { } get _session() { - return this._sessionContainer.session; + return this._client.session; } async logout() { this._isLoggingOut = true; - await this._sessionContainer.logout(); + await this._client.logout(); this.emitChange("isLoggingOut"); this.navigation.push("session", true); } diff --git a/src/lib.ts b/src/lib.ts index 27290fb5..6924bf15 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -// types need to bootstrap a SessionContainer -export {SessionContainer, LoadStatus} from "./matrix/SessionContainer.js"; +// types need to bootstrap a Client +export {Client, LoadStatus} from "./matrix/Client.js"; export {Session} from "./matrix/Session.js"; export {Sync} from "./matrix/Sync.js"; export {Room} from "./matrix/room/Room.js"; diff --git a/src/matrix/SessionContainer.js b/src/matrix/Client.js similarity index 99% rename from src/matrix/SessionContainer.js rename to src/matrix/Client.js index 677cde34..ec4e041f 100644 --- a/src/matrix/SessionContainer.js +++ b/src/matrix/Client.js @@ -51,7 +51,7 @@ export const LoginFailure = createEnum( "Unknown", ); -export class SessionContainer { +export class Client { constructor({platform, olmPromise, workerPromise}) { this._platform = platform; this._sessionStartedByReconnector = false; diff --git a/src/matrix/Session.js b/src/matrix/Session.js index 49151252..ddb3fdb5 100644 --- a/src/matrix/Session.js +++ b/src/matrix/Session.js @@ -109,7 +109,7 @@ export class Session { return this._sessionInfo.userId; } - /** @internal call SessionContainer.logout instead */ + /** @internal call Client.logout instead */ async logout(log = undefined) { await this._hsApi.logout({log}).response(); } diff --git a/src/platform/web/main.js b/src/platform/web/main.js index 21cc3986..63e9a650 100644 --- a/src/platform/web/main.js +++ b/src/platform/web/main.js @@ -16,7 +16,7 @@ limitations under the License. */ // import {RecordRequester, ReplayRequester} from "./matrix/net/request/replay"; -import {SessionContainer} from "../../matrix/SessionContainer.js"; +import {Client} from "../../matrix/Client.js"; import {RootViewModel} from "../../domain/RootViewModel.js"; import {createNavigation, createRouter} from "../../domain/navigation/index.js"; // Don't use a default export here, as we use multiple entries during legacy build, @@ -41,8 +41,8 @@ export async function main(platform) { const workerPromise = platform.loadOlmWorker(); const vm = new RootViewModel({ - createSessionContainer: () => { - return new SessionContainer({platform, olmPromise, workerPromise}); + createClient: () => { + return new Client({platform, olmPromise, workerPromise}); }, platform, // the only public interface of the router is to create urls, From 9238961992fa1dd5af91cef959b98ea967c139ad Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 22 Dec 2021 17:19:10 +0100 Subject: [PATCH 2/5] cache olm and olm worker promise inside Platform as prep to call them every time a Client is created --- src/platform/web/Platform.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 4f0446ce..7c73e66f 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -157,6 +157,8 @@ export class Platform { const isIOS = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) && !window.MSStream; this.isIOS = isIOS; this._disposables = new Disposables(); + this._olmPromise = undefined; + this._workerPromise = undefined; } _createLogger(isDevelopment) { @@ -179,7 +181,10 @@ export class Platform { } loadOlm() { - return loadOlm(this._config.olm); + if (!this._olmPromise) { + this._olmPromise = loadOlm(this._config.olm); + } + return this._olmPromise; } get config() { @@ -188,7 +193,10 @@ export class Platform { async loadOlmWorker() { if (!window.WebAssembly) { - return await loadOlmWorker(this._config); + if (!this._workerPromise) { + this._workerPromise = loadOlmWorker(this._config); + } + return this._workerPromise; } } From ba27d20b24bd3e6bf39461cac8490c3bad1d9cc8 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 22 Dec 2021 17:19:37 +0100 Subject: [PATCH 3/5] only pass platform into Client simplifying the API for SDK --- src/domain/RootViewModel.js | 5 ++--- src/domain/login/LoginViewModel.js | 6 +++--- src/matrix/Client.js | 6 +++--- src/platform/web/main.js | 6 ------ 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/domain/RootViewModel.js b/src/domain/RootViewModel.js index 4541ee22..b754f0ce 100644 --- a/src/domain/RootViewModel.js +++ b/src/domain/RootViewModel.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import {Client} from "../matrix/Client.js"; import {SessionViewModel} from "./session/SessionViewModel.js"; import {SessionLoadViewModel} from "./SessionLoadViewModel.js"; import {LoginViewModel} from "./login/LoginViewModel.js"; @@ -23,7 +24,6 @@ import {ViewModel} from "./ViewModel.js"; export class RootViewModel extends ViewModel { constructor(options) { super(options); - this._createClient = options.createClient; this._error = null; this._sessionPickerViewModel = null; this._sessionLoadViewModel = null; @@ -106,7 +106,6 @@ export class RootViewModel extends ViewModel { this._setSection(() => { this._loginViewModel = new LoginViewModel(this.childOptions({ defaultHomeserver: this.platform.config["defaultHomeServer"], - createClient: this._createClient, ready: client => { // we don't want to load the session container again, // but we also want the change of screen to go through the navigation @@ -132,7 +131,7 @@ export class RootViewModel extends ViewModel { } _showSessionLoader(sessionId) { - const client = this._createClient(); + const client = new Client(this.platform); client.startWithExistingSession(sessionId); this._setSection(() => { this._sessionLoadViewModel = new SessionLoadViewModel(this.childOptions({ diff --git a/src/domain/login/LoginViewModel.js b/src/domain/login/LoginViewModel.js index c44b34f3..b91df4cc 100644 --- a/src/domain/login/LoginViewModel.js +++ b/src/domain/login/LoginViewModel.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import {Client} from "../../matrix/Client.js"; import {ViewModel} from "../ViewModel.js"; import {PasswordLoginViewModel} from "./PasswordLoginViewModel.js"; import {StartSSOLoginViewModel} from "./StartSSOLoginViewModel.js"; @@ -24,11 +25,10 @@ import {SessionLoadViewModel} from "../SessionLoadViewModel.js"; export class LoginViewModel extends ViewModel { constructor(options) { super(options); - const {ready, defaultHomeserver, createClient, loginToken} = options; - this._createClient = createClient; + const {ready, defaultHomeserver, loginToken} = options; this._ready = ready; this._loginToken = loginToken; - this._client = this._createClient(); + this._client = new Client(this.platform); this._loginOptions = null; this._passwordLoginViewModel = null; this._startSSOLoginViewModel = null; diff --git a/src/matrix/Client.js b/src/matrix/Client.js index ec4e041f..5f6d5ea1 100644 --- a/src/matrix/Client.js +++ b/src/matrix/Client.js @@ -52,7 +52,7 @@ export const LoginFailure = createEnum( ); export class Client { - constructor({platform, olmPromise, workerPromise}) { + constructor(platform) { this._platform = platform; this._sessionStartedByReconnector = false; this._status = new ObservableValue(LoadStatus.NotLoading); @@ -64,8 +64,8 @@ export class Client { this._sessionId = null; this._storage = null; this._requestScheduler = null; - this._olmPromise = olmPromise; - this._workerPromise = workerPromise; + this._olmPromise = platform.loadOlm(); + this._workerPromise = platform.loadOlmWorker(); this._accountSetup = undefined; } diff --git a/src/platform/web/main.js b/src/platform/web/main.js index 63e9a650..eb71244a 100644 --- a/src/platform/web/main.js +++ b/src/platform/web/main.js @@ -37,13 +37,7 @@ export async function main(platform) { platform.setNavigation(navigation); const urlRouter = createRouter({navigation, history: platform.history}); urlRouter.attach(); - const olmPromise = platform.loadOlm(); - const workerPromise = platform.loadOlmWorker(); - const vm = new RootViewModel({ - createClient: () => { - return new Client({platform, olmPromise, workerPromise}); - }, platform, // the only public interface of the router is to create urls, // so we call it that in the view models From 6247ced7b78dae48ec29bfffd9b9fecc0e5675e3 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 22 Dec 2021 17:23:36 +0100 Subject: [PATCH 4/5] dont export, the ctor of these classes is not a public API --- src/lib.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/lib.ts b/src/lib.ts index 6924bf15..0aa1bb44 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -14,15 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -// types need to bootstrap a Client -export {Client, LoadStatus} from "./matrix/Client.js"; -export {Session} from "./matrix/Session.js"; -export {Sync} from "./matrix/Sync.js"; -export {Room} from "./matrix/room/Room.js"; -export {Timeline} from "./matrix/room/timeline/Timeline.js"; -export {createNavigation, createRouter} from "./domain/navigation/index.js"; export {Platform} from "./platform/web/Platform.js"; +export {Client, LoadStatus} from "./matrix/Client.js"; // export main view & view models +export {createNavigation, createRouter} from "./domain/navigation/index.js"; export {RootViewModel} from "./domain/RootViewModel.js"; export {RootView} from "./platform/web/ui/RootView.js"; export {SessionViewModel} from "./domain/session/SessionViewModel.js"; From 13e77636a960bb1af05428e9d13a37f21ac0c6b9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 22 Dec 2021 17:48:08 +0100 Subject: [PATCH 5/5] export paths from vite.js as required by Platform, reorder ctor params make it easier for SDK users --- doc/SDK.md | 3 ++- src/platform/web/LegacyPlatform.js | 4 ++-- src/platform/web/Platform.js | 21 +++++++++++---------- src/platform/web/index.html | 14 ++++---------- src/platform/web/sdk/paths/vite.js | 15 ++++++++------- 5 files changed, 27 insertions(+), 30 deletions(-) diff --git a/doc/SDK.md b/doc/SDK.md index 87e7c897..d92b99c6 100644 --- a/doc/SDK.md +++ b/doc/SDK.md @@ -38,7 +38,8 @@ import "hydrogen-view-sdk/style.css"; async function main() { const app = document.querySelector('#app')! - const platform = new Platform(app, assetPaths, { development: import.meta.env.DEV }); + const config = {}; + const platform = new Platform(app, assetPaths, config, { development: import.meta.env.DEV }); const navigation = createNavigation(); platform.setNavigation(navigation); const urlRouter = createRouter({ diff --git a/src/platform/web/LegacyPlatform.js b/src/platform/web/LegacyPlatform.js index fbf74b81..85632bf2 100644 --- a/src/platform/web/LegacyPlatform.js +++ b/src/platform/web/LegacyPlatform.js @@ -19,6 +19,6 @@ import {hkdf} from "../../utils/crypto/hkdf"; import {Platform as ModernPlatform} from "./Platform.js"; -export function Platform(container, paths) { - return new ModernPlatform(container, paths, {aesjs, hkdf}); +export function Platform(container, assetPaths, config, options = null) { + return new ModernPlatform(container, assetPaths, config, options, {aesjs, hkdf}); } diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 7c73e66f..9de3d4ce 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -76,12 +76,12 @@ function assetAbsPath(assetPath) { return assetPath; } -async function loadOlmWorker(config) { - const workerPool = new WorkerPool(config.worker, 4); +async function loadOlmWorker(assetPaths) { + const workerPool = new WorkerPool(assetPaths.worker, 4); await workerPool.init(); await workerPool.sendAll({ type: "load_olm", - path: assetAbsPath(config.olm.legacyBundle) + path: assetAbsPath(assetPaths.olm.legacyBundle) }); const olmWorker = new OlmWorker(workerPool); return olmWorker; @@ -126,9 +126,10 @@ function adaptUIOnVisualViewportResize(container) { } export class Platform { - constructor(container, config, cryptoExtras = null, options = null) { - this._config = config; + constructor(container, assetPaths, config, options = null, cryptoExtras = null) { this._container = container; + this._assetPaths = assetPaths; + this._config = config; this.settingsStorage = new SettingsStorage("hydrogen_setting_v1_"); this.clock = new Clock(); this.encoding = new Encoding(); @@ -137,9 +138,9 @@ export class Platform { this.history = new History(); this.onlineStatus = new OnlineStatus(); this._serviceWorkerHandler = null; - if (config.serviceWorker && "serviceWorker" in navigator) { + if (assetPaths.serviceWorker && "serviceWorker" in navigator) { this._serviceWorkerHandler = new ServiceWorkerHandler(); - this._serviceWorkerHandler.registerAndStart(config.serviceWorker); + this._serviceWorkerHandler.registerAndStart(assetPaths.serviceWorker); } this.notificationService = new NotificationService(this._serviceWorkerHandler, config.push); this.crypto = new Crypto(cryptoExtras); @@ -182,7 +183,7 @@ export class Platform { loadOlm() { if (!this._olmPromise) { - this._olmPromise = loadOlm(this._config.olm); + this._olmPromise = loadOlm(this._assetPaths.olm); } return this._olmPromise; } @@ -194,7 +195,7 @@ export class Platform { async loadOlmWorker() { if (!window.WebAssembly) { if (!this._workerPromise) { - this._workerPromise = loadOlmWorker(this._config); + this._workerPromise = loadOlmWorker(this._assetPaths); } return this._workerPromise; } @@ -230,7 +231,7 @@ export class Platform { if (navigator.msSaveBlob) { navigator.msSaveBlob(blobHandle.nativeBlob, filename); } else { - downloadInIframe(this._container, this._config.downloadSandbox, blobHandle, filename, this.isIOS); + downloadInIframe(this._container, this._assetPaths.downloadSandbox, blobHandle, filename, this.isIOS); } } diff --git a/src/platform/web/index.html b/src/platform/web/index.html index f7aeeed7..0e993992 100644 --- a/src/platform/web/index.html +++ b/src/platform/web/index.html @@ -19,20 +19,14 @@ import {main} from "./main"; import {Platform} from "./Platform"; import configJSON from "./assets/config.json?raw"; - import {olmPaths, downloadSandboxPath, workerPath} from "./sdk/paths/vite"; - const paths = { - olm: olmPaths, - downloadSandbox: downloadSandboxPath, - worker: workerPath, - ...JSON.parse(configJSON) - }; + import assetPaths from "./sdk/paths/vite"; if (import.meta.env.PROD) { - paths.serviceWorker = "sw.js"; + assetPaths.serviceWorker = "sw.js"; } const platform = new Platform( document.body, - paths, - null, + assetPaths, + JSON.parse(configJSON), {development: import.meta.env.DEV} ); main(platform); diff --git a/src/platform/web/sdk/paths/vite.js b/src/platform/web/sdk/paths/vite.js index 6739f8d8..48a17da4 100644 --- a/src/platform/web/sdk/paths/vite.js +++ b/src/platform/web/sdk/paths/vite.js @@ -9,11 +9,12 @@ import olmJsPath from "@matrix-org/olm/olm.js?url"; // @ts-ignore import olmLegacyJsPath from "@matrix-org/olm/olm_legacy.js?url"; -export const olmPaths = { - wasm: olmWasmPath, - legacyBundle: olmLegacyJsPath, - wasmBundle: olmJsPath, +export default { + downloadSandbox: _downloadSandboxPath, + worker: _workerPath, + olm: { + wasm: olmWasmPath, + legacyBundle: olmLegacyJsPath, + wasmBundle: olmJsPath, + } }; - -export const downloadSandboxPath = _downloadSandboxPath; -export const workerPath = _workerPath;