forked from mystiq/hydrogen-web
Merge pull request #325 from vector-im/bwindels/connectionerror-initial-sync
Fix handling connection error during initial sync
This commit is contained in:
commit
3cf86999a6
2 changed files with 17 additions and 21 deletions
|
@ -21,7 +21,6 @@ import {Reconnector, ConnectionStatus} from "./net/Reconnector.js";
|
||||||
import {ExponentialRetryDelay} from "./net/ExponentialRetryDelay.js";
|
import {ExponentialRetryDelay} from "./net/ExponentialRetryDelay.js";
|
||||||
import {MediaRepository} from "./net/MediaRepository.js";
|
import {MediaRepository} from "./net/MediaRepository.js";
|
||||||
import {RequestScheduler} from "./net/RequestScheduler.js";
|
import {RequestScheduler} from "./net/RequestScheduler.js";
|
||||||
import {HomeServerError, ConnectionError, AbortError} from "./error.js";
|
|
||||||
import {Sync, SyncStatus} from "./Sync.js";
|
import {Sync, SyncStatus} from "./Sync.js";
|
||||||
import {Session} from "./Session.js";
|
import {Session} from "./Session.js";
|
||||||
|
|
||||||
|
@ -109,7 +108,7 @@ export class SessionContainer {
|
||||||
let sessionInfo;
|
let sessionInfo;
|
||||||
try {
|
try {
|
||||||
const request = this._platform.request;
|
const request = this._platform.request;
|
||||||
const hsApi = new HomeServerApi({homeServer, request, createTimeout: clock.createTimeout});
|
const hsApi = new HomeServerApi({homeServer, request});
|
||||||
const loginData = await hsApi.passwordLogin(username, password, "Hydrogen", {log}).response();
|
const loginData = await hsApi.passwordLogin(username, password, "Hydrogen", {log}).response();
|
||||||
const sessionId = this.createNewSessionId();
|
const sessionId = this.createNewSessionId();
|
||||||
sessionInfo = {
|
sessionInfo = {
|
||||||
|
@ -124,7 +123,7 @@ export class SessionContainer {
|
||||||
await this._platform.sessionInfoStorage.add(sessionInfo);
|
await this._platform.sessionInfoStorage.add(sessionInfo);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = err;
|
this._error = err;
|
||||||
if (err instanceof HomeServerError) {
|
if (err.name === "HomeServerError") {
|
||||||
if (err.errcode === "M_FORBIDDEN") {
|
if (err.errcode === "M_FORBIDDEN") {
|
||||||
this._loginFailure = LoginFailure.Credentials;
|
this._loginFailure = LoginFailure.Credentials;
|
||||||
} else {
|
} else {
|
||||||
|
@ -132,7 +131,7 @@ export class SessionContainer {
|
||||||
}
|
}
|
||||||
log.set("loginFailure", this._loginFailure);
|
log.set("loginFailure", this._loginFailure);
|
||||||
this._status.set(LoadStatus.LoginFailed);
|
this._status.set(LoadStatus.LoginFailed);
|
||||||
} else if (err instanceof ConnectionError) {
|
} else if (err.name === "ConnectionError") {
|
||||||
this._loginFailure = LoginFailure.Connection;
|
this._loginFailure = LoginFailure.Connection;
|
||||||
this._status.set(LoadStatus.LoginFailed);
|
this._status.set(LoadStatus.LoginFailed);
|
||||||
} else {
|
} else {
|
||||||
|
@ -169,7 +168,6 @@ export class SessionContainer {
|
||||||
accessToken: sessionInfo.accessToken,
|
accessToken: sessionInfo.accessToken,
|
||||||
request: this._platform.request,
|
request: this._platform.request,
|
||||||
reconnector: this._reconnector,
|
reconnector: this._reconnector,
|
||||||
createTimeout: clock.createTimeout
|
|
||||||
});
|
});
|
||||||
this._sessionId = sessionInfo.id;
|
this._sessionId = sessionInfo.id;
|
||||||
this._storage = await this._platform.storageFactory.create(sessionInfo.id);
|
this._storage = await this._platform.storageFactory.create(sessionInfo.id);
|
||||||
|
@ -235,27 +233,26 @@ export class SessionContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _waitForFirstSync() {
|
async _waitForFirstSync() {
|
||||||
try {
|
this._sync.start();
|
||||||
this._sync.start();
|
this._status.set(LoadStatus.FirstSync);
|
||||||
this._status.set(LoadStatus.FirstSync);
|
|
||||||
} catch (err) {
|
|
||||||
// swallow ConnectionError here and continue,
|
|
||||||
// as the reconnector above will call
|
|
||||||
// sync.start again to retry in this case
|
|
||||||
if (!(err instanceof ConnectionError)) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// only transition into Ready once the first sync has succeeded
|
// only transition into Ready once the first sync has succeeded
|
||||||
this._waitForFirstSyncHandle = this._sync.status.waitFor(s => s === SyncStatus.Syncing || s === SyncStatus.Stopped);
|
this._waitForFirstSyncHandle = this._sync.status.waitFor(s => {
|
||||||
|
if (s === SyncStatus.Stopped) {
|
||||||
|
// keep waiting if there is a ConnectionError
|
||||||
|
// as the reconnector above will call
|
||||||
|
// sync.start again to retry in this case
|
||||||
|
return this._sync.error?.name !== "ConnectionError";
|
||||||
|
}
|
||||||
|
return s === SyncStatus.Syncing;
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
await this._waitForFirstSyncHandle.promise;
|
await this._waitForFirstSyncHandle.promise;
|
||||||
if (this._sync.status.get() === SyncStatus.Stopped) {
|
if (this._sync.status.get() === SyncStatus.Stopped && this._sync.error) {
|
||||||
throw this._sync.error;
|
throw this._sync.error;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// if dispose is called from stop, bail out
|
// if dispose is called from stop, bail out
|
||||||
if (err instanceof AbortError) {
|
if (err.name === "AbortError") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
|
|
|
@ -19,13 +19,12 @@ import {encodeQueryParams, encodeBody} from "./common.js";
|
||||||
import {HomeServerRequest} from "./HomeServerRequest.js";
|
import {HomeServerRequest} from "./HomeServerRequest.js";
|
||||||
|
|
||||||
export class HomeServerApi {
|
export class HomeServerApi {
|
||||||
constructor({homeServer, accessToken, request, createTimeout, reconnector}) {
|
constructor({homeServer, accessToken, request, reconnector}) {
|
||||||
// store these both in a closure somehow so it's harder to get at in case of XSS?
|
// store these both in a closure somehow so it's harder to get at in case of XSS?
|
||||||
// one could change the homeserver as well so the token gets sent there, so both must be protected from read/write
|
// one could change the homeserver as well so the token gets sent there, so both must be protected from read/write
|
||||||
this._homeserver = homeServer;
|
this._homeserver = homeServer;
|
||||||
this._accessToken = accessToken;
|
this._accessToken = accessToken;
|
||||||
this._requestFn = request;
|
this._requestFn = request;
|
||||||
this._createTimeout = createTimeout;
|
|
||||||
this._reconnector = reconnector;
|
this._reconnector = reconnector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue