UNPKG

@hpcc-js/comms

Version:
254 lines 10 kB
import { __assign } from "tslib"; import { join, promiseTimeout, scopedLogger } from "@hpcc-js/util"; var logger = scopedLogger("comms/connection.ts"); export function instanceOfIOptions(object) { return "baseUrl" in object; } var DefaultOptions = { type: "post", baseUrl: "", userID: "", password: "", rejectUnauthorized: true, timeoutSecs: 60 }; export function instanceOfIConnection(object) { return typeof object.opts === "function" && typeof object.send === "function" && typeof object.clone === "function"; } // comms --- function encode(uriComponent, encodeRequest) { return (encodeRequest === undefined || encodeRequest === true) ? encodeURIComponent(uriComponent) : "" + uriComponent; } export function serializeRequest(obj, encodeRequest, prefix) { if (encodeRequest === void 0) { encodeRequest = true; } if (prefix === void 0) { prefix = ""; } if (prefix) { prefix += "."; } if (typeof obj !== "object") { return encode(obj, encodeRequest); } var str = []; var _loop_1 = function (key) { if (obj.hasOwnProperty(key)) { if (obj[key] instanceof Array) { // Specific to ESP - but no REST standard exists... var includeItemCount_1 = false; obj[key].forEach(function (row, i) { if (typeof row === "object") { includeItemCount_1 = true; str.push(serializeRequest(row, encodeRequest, prefix + encode("".concat(key, ".").concat(i), encodeRequest))); } else { str.push(prefix + encode("".concat(key, "_i").concat(i), encodeRequest) + "=" + serializeRequest(row, encodeRequest)); } }); if (includeItemCount_1) { str.push(prefix + encode("".concat(key, ".itemcount"), encodeRequest) + "=" + obj[key].length); } } else if (typeof obj[key] === "object") { if (obj[key] && obj[key]["Item"] instanceof Array) { // Specific to ws_machine.GetTargetClusterInfo? str.push(serializeRequest(obj[key]["Item"], encodeRequest, prefix + encode(key, encodeRequest))); str.push(prefix + encode("".concat(key, ".itemcount"), encodeRequest) + "=" + obj[key]["Item"].length); } else { str.push(serializeRequest(obj[key], encodeRequest, prefix + encode(key, encodeRequest))); } } else if (obj[key] !== undefined) { str.push(prefix + encode(key, encodeRequest) + "=" + encode(obj[key], encodeRequest)); } else { str.push(prefix + encode(key, encodeRequest)); } } }; for (var key in obj) { _loop_1(key); } return str.join("&"); } export function deserializeResponse(body) { return JSON.parse(body); } export function jsonp(opts, action, request, responseType, header) { if (request === void 0) { request = {}; } if (responseType === void 0) { responseType = "json"; } if (header) { console.warn("Header attributes ignored for JSONP connections"); } return new Promise(function (resolve, reject) { var respondedTimeout = opts.timeoutSecs * 1000; var respondedTick = 5000; var callbackName = "jsonp_callback_" + Math.round(Math.random() * 999999); window[callbackName] = function (response) { respondedTimeout = 0; doCallback(); resolve(responseType === "json" && typeof response === "string" ? deserializeResponse(response) : response); }; var script = document.createElement("script"); var url = join(opts.baseUrl, action); url += url.indexOf("?") >= 0 ? "&" : "?"; script.src = url + "jsonp=" + callbackName + "&" + serializeRequest(request, opts.encodeRequest); document.body.appendChild(script); var progress = setInterval(function () { if (respondedTimeout <= 0) { clearInterval(progress); } else { respondedTimeout -= respondedTick; if (respondedTimeout <= 0) { clearInterval(progress); logger.error("Request timeout: " + script.src); doCallback(); reject(Error("Request timeout: " + script.src)); } else { logger.debug("Request pending (" + respondedTimeout / 1000 + " sec): " + script.src); } } }, respondedTick); function doCallback() { delete window[callbackName]; document.body.removeChild(script); } }); } function authHeader(opts) { return opts.userID ? { Authorization: "Basic ".concat(btoa("".concat(opts.userID, ":").concat(opts.password))) } : {}; } // _omitMap is a workaround for older HPCC-Platform instances without credentials --- var _omitMap = {}; function doFetch(opts, action, requestInit, headersInit, responseType) { headersInit = __assign(__assign({}, authHeader(opts)), headersInit); requestInit = __assign(__assign({ credentials: _omitMap[opts.baseUrl] ? "omit" : "include" }, requestInit), { headers: headersInit }); if (fetch["__setGlobalDispatcher"]) { fetch["__setGlobalDispatcher"](fetch["__defaultAgent"]); } if (opts.baseUrl.indexOf("https:") === 0) { // NodeJS / node-fetch only --- if (opts.rejectUnauthorized === false && fetch["__rejectUnauthorizedAgent"]) { if (fetch["__setGlobalDispatcher"]) { fetch["__setGlobalDispatcher"](fetch["__rejectUnauthorizedAgent"]); } else { requestInit["agent"] = fetch["__rejectUnauthorizedAgent"]; } } else if (fetch["__trustwaveAgent"]) { requestInit["agent"] = fetch["__trustwaveAgent"]; } } function handleResponse(response) { if (response.ok) { return responseType === "json" ? response.json() : response.text(); } throw new Error(response.statusText); } return promiseTimeout(opts.timeoutSecs * 1000, fetch(join(opts.baseUrl, action), requestInit) .then(handleResponse) .catch(function (e) { // Try again with the opposite credentials mode --- requestInit.credentials = !_omitMap[opts.baseUrl] ? "omit" : "include"; return fetch(join(opts.baseUrl, action), requestInit) .then(handleResponse) .then(function (responseBody) { _omitMap[opts.baseUrl] = !_omitMap[opts.baseUrl]; // The "opposite" credentials mode is known to work --- return responseBody; }); })); } export function post(opts, action, request, responseType, header) { if (responseType === void 0) { responseType = "json"; } if (request.upload_) { delete request.upload_; action += "?upload_"; } var abortSignal; if (request.abortSignal_) { abortSignal = request.abortSignal_; delete request.abortSignal_; } return doFetch(opts, action, { method: "post", body: serializeRequest(request, opts.encodeRequest), signal: abortSignal }, __assign({ "Content-Type": "application/x-www-form-urlencoded" }, header), responseType); } export function get(opts, action, request, responseType, header) { if (responseType === void 0) { responseType = "json"; } var abortSignal; if (request.abortSignal_) { abortSignal = request.abortSignal_; delete request.abortSignal_; } return doFetch(opts, "".concat(action, "?").concat(serializeRequest(request, opts.encodeRequest)), { method: "get", signal: abortSignal }, __assign({}, header), responseType); } export function send(opts, action, request, responseType, header) { if (responseType === void 0) { responseType = "json"; } var retVal; switch (opts.type) { case "jsonp": retVal = jsonp(opts, action, request, responseType, header); break; case "get": retVal = get(opts, action, request, responseType, header); break; case "post": default: retVal = post(opts, action, request, responseType, header); break; } return retVal; } var hookedSend = send; export function hookSend(newSend) { var retVal = hookedSend; if (newSend) { hookedSend = newSend; } return retVal; } var Connection = /** @class */ (function () { function Connection(opts) { this.opts(opts); } Object.defineProperty(Connection.prototype, "baseUrl", { get: function () { return this._opts.baseUrl; }, enumerable: false, configurable: true }); Connection.prototype.opts = function (_) { if (arguments.length === 0) return this._opts; this._opts = __assign(__assign({}, DefaultOptions), _); return this; }; Connection.prototype.send = function (action, request, responseType, header) { if (responseType === void 0) { responseType = "json"; } if (this._opts.hookSend) { return this._opts.hookSend(this._opts, action, request, responseType, hookedSend, header); } return hookedSend(this._opts, action, request, responseType, header); }; Connection.prototype.clone = function () { return new Connection(this.opts()); }; return Connection; }()); export { Connection }; export var createConnection = function (opts) { return new Connection(opts); }; export function setTransportFactory(newFunc) { var retVal = createConnection; createConnection = newFunc; return retVal; } //# sourceMappingURL=connection.js.map