mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-23 03:25:12 +01:00
Move timeout to fetch, as XHR has native timeout support
This commit is contained in:
parent
bfcb23ee74
commit
b26bc69042
@ -1,5 +1,5 @@
|
|||||||
// import {RecordRequester, ReplayRequester} from "./matrix/net/request/replay.js";
|
// import {RecordRequester, ReplayRequester} from "./matrix/net/request/replay.js";
|
||||||
import {fetchRequest} from "./matrix/net/request/fetch.js";
|
import {createFetchRequest} from "./matrix/net/request/fetch.js";
|
||||||
import {SessionContainer} from "./matrix/SessionContainer.js";
|
import {SessionContainer} from "./matrix/SessionContainer.js";
|
||||||
import {StorageFactory} from "./matrix/storage/idb/StorageFactory.js";
|
import {StorageFactory} from "./matrix/storage/idb/StorageFactory.js";
|
||||||
import {SessionInfoStorage} from "./matrix/sessioninfo/localstorage/SessionInfoStorage.js";
|
import {SessionInfoStorage} from "./matrix/sessioninfo/localstorage/SessionInfoStorage.js";
|
||||||
@ -16,13 +16,13 @@ export default async function main(container) {
|
|||||||
// const request = replay.request;
|
// const request = replay.request;
|
||||||
|
|
||||||
// to record:
|
// to record:
|
||||||
// const recorder = new RecordRequester(fetchRequest);
|
// const recorder = new RecordRequester(createFetchRequest(clock.createTimeout));
|
||||||
// const request = recorder.request;
|
// const request = recorder.request;
|
||||||
// window.getBrawlFetchLog = () => recorder.log();
|
// window.getBrawlFetchLog = () => recorder.log();
|
||||||
// normal network:
|
// normal network:
|
||||||
const request = fetchRequest;
|
|
||||||
const sessionInfoStorage = new SessionInfoStorage("brawl_sessions_v1");
|
|
||||||
const clock = new Clock();
|
const clock = new Clock();
|
||||||
|
const request = createFetchRequest(clock.createTimeout);
|
||||||
|
const sessionInfoStorage = new SessionInfoStorage("brawl_sessions_v1");
|
||||||
const storageFactory = new StorageFactory();
|
const storageFactory = new StorageFactory();
|
||||||
|
|
||||||
const vm = new BrawlViewModel({
|
const vm = new BrawlViewModel({
|
||||||
|
@ -5,9 +5,9 @@ import {
|
|||||||
} from "../error.js";
|
} from "../error.js";
|
||||||
|
|
||||||
class RequestWrapper {
|
class RequestWrapper {
|
||||||
constructor(method, url, requestResult, responsePromise) {
|
constructor(method, url, requestResult) {
|
||||||
this._requestResult = requestResult;
|
this._requestResult = requestResult;
|
||||||
this._promise = responsePromise.then(response => {
|
this._promise = requestResult.response().then(response => {
|
||||||
// ok?
|
// ok?
|
||||||
if (response.status >= 200 && response.status < 300) {
|
if (response.status >= 200 && response.status < 300) {
|
||||||
return response.body;
|
return response.body;
|
||||||
@ -44,35 +44,6 @@ export class HomeServerApi {
|
|||||||
return `${this._homeserver}/_matrix/client/r0${csPath}`;
|
return `${this._homeserver}/_matrix/client/r0${csPath}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
_abortOnTimeout(timeoutAmount, requestResult, responsePromise) {
|
|
||||||
const timeout = this._createTimeout(timeoutAmount);
|
|
||||||
// abort request if timeout finishes first
|
|
||||||
let timedOut = false;
|
|
||||||
timeout.elapsed().then(
|
|
||||||
() => {
|
|
||||||
timedOut = true;
|
|
||||||
requestResult.abort();
|
|
||||||
},
|
|
||||||
() => {} // ignore AbortError
|
|
||||||
);
|
|
||||||
// abort timeout if request finishes first
|
|
||||||
return responsePromise.then(
|
|
||||||
response => {
|
|
||||||
timeout.abort();
|
|
||||||
return response;
|
|
||||||
},
|
|
||||||
err => {
|
|
||||||
timeout.abort();
|
|
||||||
// map error to TimeoutError
|
|
||||||
if (err instanceof AbortError && timedOut) {
|
|
||||||
throw new ConnectionError(`Request timed out after ${timeoutAmount}ms`, true);
|
|
||||||
} else {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_encodeQueryParams(queryParams) {
|
_encodeQueryParams(queryParams) {
|
||||||
return Object.entries(queryParams || {})
|
return Object.entries(queryParams || {})
|
||||||
.filter(([, value]) => value !== undefined)
|
.filter(([, value]) => value !== undefined)
|
||||||
@ -102,19 +73,10 @@ export class HomeServerApi {
|
|||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
body: bodyString,
|
body: bodyString,
|
||||||
|
timeout: options && options.timeout
|
||||||
});
|
});
|
||||||
|
|
||||||
let responsePromise = requestResult.response();
|
const wrapper = new RequestWrapper(method, url, requestResult);
|
||||||
|
|
||||||
if (options && options.timeout) {
|
|
||||||
responsePromise = this._abortOnTimeout(
|
|
||||||
options.timeout,
|
|
||||||
requestResult,
|
|
||||||
responsePromise
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const wrapper = new RequestWrapper(method, url, requestResult, responsePromise);
|
|
||||||
|
|
||||||
if (this._reconnector) {
|
if (this._reconnector) {
|
||||||
wrapper.response().catch(err => {
|
wrapper.response().catch(err => {
|
||||||
|
@ -2,6 +2,7 @@ import {
|
|||||||
AbortError,
|
AbortError,
|
||||||
ConnectionError
|
ConnectionError
|
||||||
} from "../../error.js";
|
} from "../../error.js";
|
||||||
|
import {abortOnTimeout} from "../timeout.js";
|
||||||
|
|
||||||
class RequestResult {
|
class RequestResult {
|
||||||
constructor(promise, controller) {
|
constructor(promise, controller) {
|
||||||
@ -15,9 +16,9 @@ class RequestResult {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
this._promise = Promise.race([promise, abortPromise]);
|
this.promise = Promise.race([promise, abortPromise]);
|
||||||
} else {
|
} else {
|
||||||
this._promise = promise;
|
this.promise = promise;
|
||||||
this._controller = controller;
|
this._controller = controller;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,47 +28,55 @@ class RequestResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response() {
|
response() {
|
||||||
return this._promise;
|
return this.promise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchRequest(url, options) {
|
export function createFetchRequest(createTimeout) {
|
||||||
const controller = typeof AbortController === "function" ? new AbortController() : null;
|
return function fetchRequest(url, options) {
|
||||||
if (controller) {
|
const controller = typeof AbortController === "function" ? new AbortController() : null;
|
||||||
|
if (controller) {
|
||||||
|
options = Object.assign(options, {
|
||||||
|
signal: controller.signal
|
||||||
|
});
|
||||||
|
}
|
||||||
options = Object.assign(options, {
|
options = Object.assign(options, {
|
||||||
signal: controller.signal
|
mode: "cors",
|
||||||
|
credentials: "omit",
|
||||||
|
referrer: "no-referrer",
|
||||||
|
cache: "no-cache",
|
||||||
});
|
});
|
||||||
}
|
if (options.headers) {
|
||||||
options = Object.assign(options, {
|
const headers = new Headers();
|
||||||
mode: "cors",
|
for(const [name, value] of options.headers.entries()) {
|
||||||
credentials: "omit",
|
headers.append(name, value);
|
||||||
referrer: "no-referrer",
|
}
|
||||||
cache: "no-cache",
|
options.headers = headers;
|
||||||
});
|
|
||||||
if (options.headers) {
|
|
||||||
const headers = new Headers();
|
|
||||||
for(const [name, value] of options.headers.entries()) {
|
|
||||||
headers.append(name, value);
|
|
||||||
}
|
}
|
||||||
options.headers = headers;
|
const promise = fetch(url, options).then(async response => {
|
||||||
}
|
const {status} = response;
|
||||||
const promise = fetch(url, options).then(async response => {
|
const body = await response.json();
|
||||||
const {status} = response;
|
return {status, body};
|
||||||
const body = await response.json();
|
}, err => {
|
||||||
return {status, body};
|
if (err.name === "AbortError") {
|
||||||
}, err => {
|
throw new AbortError();
|
||||||
if (err.name === "AbortError") {
|
} else if (err instanceof TypeError) {
|
||||||
throw new AbortError();
|
// Network errors are reported as TypeErrors, see
|
||||||
} else if (err instanceof TypeError) {
|
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
|
||||||
// Network errors are reported as TypeErrors, see
|
// this can either mean user is offline, server is offline, or a CORS error (server misconfiguration).
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
|
//
|
||||||
// this can either mean user is offline, server is offline, or a CORS error (server misconfiguration).
|
// One could check navigator.onLine to rule out the first
|
||||||
//
|
// but the 2 latter ones are indistinguishable from javascript.
|
||||||
// One could check navigator.onLine to rule out the first
|
throw new ConnectionError(`${options.method} ${url}: ${err.message}`);
|
||||||
// but the 2 latter ones are indistinguishable from javascript.
|
}
|
||||||
throw new ConnectionError(`${options.method} ${url}: ${err.message}`);
|
throw err;
|
||||||
|
});
|
||||||
|
const result = new RequestResult(promise, controller);
|
||||||
|
|
||||||
|
if (options.timeout) {
|
||||||
|
result.promise = abortOnTimeout(createTimeout, options.timeout, result, result.promise);
|
||||||
}
|
}
|
||||||
throw err;
|
|
||||||
});
|
return result;
|
||||||
return new RequestResult(promise, controller);
|
}
|
||||||
}
|
}
|
||||||
|
28
src/matrix/net/timeout.js
Normal file
28
src/matrix/net/timeout.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
export function abortOnTimeout(createTimeout, timeoutAmount, requestResult, responsePromise) {
|
||||||
|
const timeout = createTimeout(timeoutAmount);
|
||||||
|
// abort request if timeout finishes first
|
||||||
|
let timedOut = false;
|
||||||
|
timeout.elapsed().then(
|
||||||
|
() => {
|
||||||
|
timedOut = true;
|
||||||
|
requestResult.abort();
|
||||||
|
},
|
||||||
|
() => {} // ignore AbortError when timeout is aborted
|
||||||
|
);
|
||||||
|
// abort timeout if request finishes first
|
||||||
|
return responsePromise.then(
|
||||||
|
response => {
|
||||||
|
timeout.abort();
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
timeout.abort();
|
||||||
|
// map error to TimeoutError
|
||||||
|
if (err instanceof AbortError && timedOut) {
|
||||||
|
throw new ConnectionError(`Request timed out after ${timeoutAmount}ms`, true);
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user