@hpcc-js/comms
Version:
hpcc-js - Communications
200 lines • 7.84 kB
JavaScript
import * as tslib_1 from "tslib";
import { join, promiseTimeout, scopedLogger } from "@hpcc-js/util";
var logger = scopedLogger("comms/connection.ts");
var DefaultOptions = {
type: "post",
baseUrl: "",
userID: "",
password: "",
rejectUnauthorized: false,
timeoutSecs: 60
};
// comms ---
export function serializeRequest(obj, prefix) {
if (prefix === void 0) { prefix = ""; }
if (prefix) {
prefix += ".";
}
if (typeof obj !== "object") {
return encodeURIComponent(obj);
}
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, prefix + encodeURIComponent(key + "." + i)));
}
else {
str.push(prefix + encodeURIComponent(key + "_i" + i) + "=" + serializeRequest(row));
}
});
if (includeItemCount_1) {
str.push(prefix + encodeURIComponent(key + ".itemcount") + "=" + 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"], prefix + encodeURIComponent(key)));
str.push(prefix + encodeURIComponent(key + ".itemcount") + "=" + obj[key]["Item"].length);
}
else {
str.push(serializeRequest(obj[key], prefix + encodeURIComponent(key)));
}
}
else if (obj[key] !== undefined) {
str.push(prefix + encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]));
}
else {
str.push(prefix + encodeURIComponent(key));
}
}
};
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) {
if (request === void 0) { request = {}; }
if (responseType === void 0) { responseType = "json"; }
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);
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 " + btoa(opts.userID + ":" + opts.password) } : {};
}
// _omitMap is a workaround for older HPCC-Platform instances without credentials ---
var _omitMap = {};
function doFetch(opts, action, requestInit, headersInit, responseType) {
headersInit = tslib_1.__assign({}, authHeader(opts), headersInit);
requestInit = tslib_1.__assign({ credentials: _omitMap[opts.baseUrl] ? "omit" : "include" }, requestInit, { headers: headersInit });
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) {
if (responseType === void 0) { responseType = "json"; }
return doFetch(opts, action, {
method: "post",
body: serializeRequest(request)
}, {
"Content-Type": "application/x-www-form-urlencoded"
}, responseType);
}
export function get(opts, action, request, responseType) {
if (responseType === void 0) { responseType = "json"; }
return doFetch(opts, action + "?" + serializeRequest(request), {
method: "get"
}, {}, responseType);
}
export function send(opts, action, request, responseType) {
if (responseType === void 0) { responseType = "json"; }
var retVal;
switch (opts.type) {
case "jsonp":
retVal = jsonp(opts, action, request, responseType);
break;
case "get":
retVal = get(opts, action, request, responseType);
break;
case "post":
default:
retVal = post(opts, action, request, responseType);
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);
}
Connection.prototype.opts = function (_) {
if (arguments.length === 0)
return this._opts;
this._opts = tslib_1.__assign({}, DefaultOptions, _);
return this;
};
Connection.prototype.send = function (action, request, responseType) {
if (responseType === void 0) { responseType = "json"; }
return hookedSend(this._opts, action, request, responseType);
};
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