UNPKG

@intuitionrobotics/thunderstorm

Version:
155 lines 5.9 kB
import { HttpMethod } from "../../../shared/types.js"; import { _keys, BadImplementationException, currentTimeMillies } from "@intuitionrobotics/ts-common"; import { gzipSync } from "zlib"; import { HttpException } from "../../../shared/request-types.js"; import { BaseHttpRequest } from "../../../shared/BaseHttpRequest.js"; import { BaseHttpModule_Class } from "../../../shared/BaseHttpModule.js"; export class XhrHttpModule_Class extends BaseHttpModule_Class { constructor(name) { super(name || "XhrHttpModule"); } init() { super.init(); this.origin = this.config.origin; } createRequest(method, key, data) { return new XhrHttpRequest(key, data, this.shouldCompress()) .setOrigin(this.origin) .setMethod(method) .setTimeout(this.timeout) .setDefaultHeaders(this.defaultHeaders) .setHandleRequestSuccess(this.handleRequestSuccess) .setHandleRequestFailure(this.handleRequestFailure) .setDefaultRequestHandler(this.processDefaultResponseHandlers); } } export const XhrHttpModule = new XhrHttpModule_Class(); class XhrHttpRequest extends BaseHttpRequest { xhr; startTime; elapsedMS; constructor(requestKey, requestData, shouldCompress) { super(requestKey, requestData); this.compress = shouldCompress === undefined ? true : shouldCompress; } getStatus() { const xhr = this.xhr; if (!xhr) throw new BadImplementationException("No xhr object!"); return xhr.status; } getResponse() { const xhr = this.xhr; if (!xhr) throw new BadImplementationException("No xhr object!"); return xhr.response; } abortImpl() { this.xhr?.abort(); } getErrorResponse() { const rawResponse = this.getResponse(); let response = undefined; if (rawResponse) { try { response = rawResponse && this.asJson(); } catch (_e) { response = { debugMessage: rawResponse }; } } return response; } prepareJsonBody(bodyObject) { return JSON.stringify(bodyObject); } executeImpl() { //loop through whatever preprocessor return new Promise((resolve, reject) => { if (this.aborted) return resolve(); const xhr = new XMLHttpRequest(); // @ts-expect-error TS struggles with this dynamic typing // noinspection JSConstantReassignment this.xhr = xhr; this.xhr.onreadystatechange = () => { if (xhr.readyState !== 4) return; if (this.startTime) this.elapsedMS = currentTimeMillies() - this.startTime; resolve(); }; this.xhr.onerror = (err) => { if (xhr.readyState === 4 && xhr.status === 0) { reject(new HttpException(404, this.url)); return; } reject(err); }; this.xhr.ontimeout = (err) => { reject(err); }; this.xhr.onload = (_err) => { // HttpModule.logVerbose("onload"); }; this.xhr.onloadstart = (_err) => { // HttpModule.logVerbose("onloadstart"); }; this.xhr.onloadend = (_err) => { // HttpModule.logVerbose("onloadend"); }; this.xhr.onabort = (_err) => { // HttpModule.logVerbose("onabort"); }; let nextOperator = this.url.indexOf("?") === -1 ? "?" : "&"; let fullUrl = this.url; const params = this.params; if (params) fullUrl = _keys(params).reduce((url, paramKey) => { const param = params[paramKey]; if (!param) return url; const toRet = `${url}${nextOperator}${String(paramKey)}=${encodeURIComponent(param)}`; nextOperator = "&"; return toRet; }, this.url); // TODO: investigate which one should work this.xhr.onprogress = this.onProgressListener; this.xhr.upload.onprogress = this.onProgressListener; this.xhr.open(this.method, fullUrl); this.xhr.timeout = this.timeout; Object.keys(this.headers).forEach((key) => { xhr.setRequestHeader(key, this.headers[key].join("; ")); }); let body = this.body; if (typeof body === 'string' && this.compress) try { body = gzipSync(body); } catch (error) { return reject(error); } this.startTime = currentTimeMillies(); return this.xhr.send(body); }); } getAllResponseHeaders() { return this.xhr?.getAllResponseHeaders(); } getResponseHeader(headerKey) { if (!this.xhr) throw new BadImplementationException("No xhr object!"); if (!this.xhr.response) throw new BadImplementationException(`xhr didn't return yet`); // Chrome bug, if the response header is not present then it throws an error (not really problematic but just annoying) // https://trackjs.com/blog/refused-unsafe-header/ if (this.xhr.getAllResponseHeaders().indexOf(headerKey) < 0) return undefined; const header = this.xhr.getResponseHeader(headerKey); if (!header) return undefined; return header; } getElapsedTime = () => this.elapsedMS; } //# sourceMappingURL=XhrHttpModule.js.map