UNPKG

9.03 kBJavaScriptView Raw
1import { __assign } from "tslib";
2import { join, promiseTimeout, scopedLogger } from "@hpcc-js/util";
3var logger = scopedLogger("comms/connection.ts");
4export function instanceOfIOptions(object) {
5 return "baseUrl" in object;
6}
7var DefaultOptions = {
8 type: "post",
9 baseUrl: "",
10 userID: "",
11 password: "",
12 rejectUnauthorized: true,
13 timeoutSecs: 60
14};
15export function instanceOfIConnection(object) {
16 return typeof object.opts === "function" &&
17 typeof object.send === "function" &&
18 typeof object.clone === "function";
19}
20// comms ---
21function encode(uriComponent, encodeRequest) {
22 return (encodeRequest === undefined || encodeRequest === true) ? encodeURIComponent(uriComponent) : "" + uriComponent;
23}
24export function serializeRequest(obj, encodeRequest, prefix) {
25 if (encodeRequest === void 0) { encodeRequest = true; }
26 if (prefix === void 0) { prefix = ""; }
27 if (prefix) {
28 prefix += ".";
29 }
30 if (typeof obj !== "object") {
31 return encode(obj, encodeRequest);
32 }
33 var str = [];
34 var _loop_1 = function (key) {
35 if (obj.hasOwnProperty(key)) {
36 if (obj[key] instanceof Array) {
37 // Specific to ESP - but no REST standard exists...
38 var includeItemCount_1 = false;
39 obj[key].forEach(function (row, i) {
40 if (typeof row === "object") {
41 includeItemCount_1 = true;
42 str.push(serializeRequest(row, encodeRequest, prefix + encode(key + "." + i, encodeRequest)));
43 }
44 else {
45 str.push(prefix + encode(key + "_i" + i, encodeRequest) + "=" + serializeRequest(row, encodeRequest));
46 }
47 });
48 if (includeItemCount_1) {
49 str.push(prefix + encode(key + ".itemcount", encodeRequest) + "=" + obj[key].length);
50 }
51 }
52 else if (typeof obj[key] === "object") {
53 if (obj[key] && obj[key]["Item"] instanceof Array) { // Specific to ws_machine.GetTargetClusterInfo?
54 str.push(serializeRequest(obj[key]["Item"], encodeRequest, prefix + encode(key, encodeRequest)));
55 str.push(prefix + encode(key + ".itemcount", encodeRequest) + "=" + obj[key]["Item"].length);
56 }
57 else {
58 str.push(serializeRequest(obj[key], encodeRequest, prefix + encode(key, encodeRequest)));
59 }
60 }
61 else if (obj[key] !== undefined) {
62 str.push(prefix + encode(key, encodeRequest) + "=" + encode(obj[key], encodeRequest));
63 }
64 else {
65 str.push(prefix + encode(key, encodeRequest));
66 }
67 }
68 };
69 for (var key in obj) {
70 _loop_1(key);
71 }
72 return str.join("&");
73}
74export function deserializeResponse(body) {
75 return JSON.parse(body);
76}
77export function jsonp(opts, action, request, responseType, header) {
78 if (request === void 0) { request = {}; }
79 if (responseType === void 0) { responseType = "json"; }
80 if (header) {
81 console.warn("Header attributes ignored for JSONP connections");
82 }
83 return new Promise(function (resolve, reject) {
84 var respondedTimeout = opts.timeoutSecs * 1000;
85 var respondedTick = 5000;
86 var callbackName = "jsonp_callback_" + Math.round(Math.random() * 999999);
87 window[callbackName] = function (response) {
88 respondedTimeout = 0;
89 doCallback();
90 resolve(responseType === "json" && typeof response === "string" ? deserializeResponse(response) : response);
91 };
92 var script = document.createElement("script");
93 var url = join(opts.baseUrl, action);
94 url += url.indexOf("?") >= 0 ? "&" : "?";
95 script.src = url + "jsonp=" + callbackName + "&" + serializeRequest(request, opts.encodeRequest);
96 document.body.appendChild(script);
97 var progress = setInterval(function () {
98 if (respondedTimeout <= 0) {
99 clearInterval(progress);
100 }
101 else {
102 respondedTimeout -= respondedTick;
103 if (respondedTimeout <= 0) {
104 clearInterval(progress);
105 logger.error("Request timeout: " + script.src);
106 doCallback();
107 reject(Error("Request timeout: " + script.src));
108 }
109 else {
110 logger.debug("Request pending (" + respondedTimeout / 1000 + " sec): " + script.src);
111 }
112 }
113 }, respondedTick);
114 function doCallback() {
115 delete window[callbackName];
116 document.body.removeChild(script);
117 }
118 });
119}
120function authHeader(opts) {
121 return opts.userID ? { Authorization: "Basic " + btoa(opts.userID + ":" + opts.password) } : {};
122}
123// _omitMap is a workaround for older HPCC-Platform instances without credentials ---
124var _omitMap = {};
125function doFetch(opts, action, requestInit, headersInit, responseType) {
126 headersInit = __assign(__assign({}, authHeader(opts)), headersInit);
127 requestInit = __assign(__assign({ credentials: _omitMap[opts.baseUrl] ? "omit" : "include" }, requestInit), { headers: headersInit });
128 if (opts.rejectUnauthorized === false && fetch["__agent"] && opts.baseUrl.indexOf("https:") === 0) {
129 // NodeJS / node-fetch only ---
130 requestInit["agent"] = fetch["__agent"];
131 }
132 function handleResponse(response) {
133 if (response.ok) {
134 return responseType === "json" ? response.json() : response.text();
135 }
136 throw new Error(response.statusText);
137 }
138 return promiseTimeout(opts.timeoutSecs * 1000, fetch(join(opts.baseUrl, action), requestInit)
139 .then(handleResponse)
140 .catch(function (e) {
141 // Try again with the opposite credentials mode ---
142 requestInit.credentials = !_omitMap[opts.baseUrl] ? "omit" : "include";
143 return fetch(join(opts.baseUrl, action), requestInit)
144 .then(handleResponse)
145 .then(function (responseBody) {
146 _omitMap[opts.baseUrl] = !_omitMap[opts.baseUrl]; // The "opposite" credentials mode is known to work ---
147 return responseBody;
148 });
149 }));
150}
151export function post(opts, action, request, responseType, header) {
152 if (responseType === void 0) { responseType = "json"; }
153 return doFetch(opts, action, {
154 method: "post",
155 body: serializeRequest(request, opts.encodeRequest)
156 }, __assign({ "Content-Type": "application/x-www-form-urlencoded" }, header), responseType);
157}
158export function get(opts, action, request, responseType, header) {
159 if (responseType === void 0) { responseType = "json"; }
160 return doFetch(opts, action + "?" + serializeRequest(request, opts.encodeRequest), {
161 method: "get"
162 }, __assign({}, header), responseType);
163}
164export function send(opts, action, request, responseType, header) {
165 if (responseType === void 0) { responseType = "json"; }
166 var retVal;
167 switch (opts.type) {
168 case "jsonp":
169 retVal = jsonp(opts, action, request, responseType, header);
170 break;
171 case "get":
172 retVal = get(opts, action, request, responseType, header);
173 break;
174 case "post":
175 default:
176 retVal = post(opts, action, request, responseType, header);
177 break;
178 }
179 return retVal;
180}
181var hookedSend = send;
182export function hookSend(newSend) {
183 var retVal = hookedSend;
184 if (newSend) {
185 hookedSend = newSend;
186 }
187 return retVal;
188}
189var Connection = /** @class */ (function () {
190 function Connection(opts) {
191 this.opts(opts);
192 }
193 Object.defineProperty(Connection.prototype, "baseUrl", {
194 get: function () { return this._opts.baseUrl; },
195 enumerable: false,
196 configurable: true
197 });
198 Connection.prototype.opts = function (_) {
199 if (arguments.length === 0)
200 return this._opts;
201 this._opts = __assign(__assign({}, DefaultOptions), _);
202 return this;
203 };
204 Connection.prototype.send = function (action, request, responseType, header) {
205 if (responseType === void 0) { responseType = "json"; }
206 if (this._opts.hookSend) {
207 return this._opts.hookSend(this._opts, action, request, responseType, hookedSend, header);
208 }
209 return hookedSend(this._opts, action, request, responseType, header);
210 };
211 Connection.prototype.clone = function () {
212 return new Connection(this.opts());
213 };
214 return Connection;
215}());
216export { Connection };
217export var createConnection = function (opts) {
218 return new Connection(opts);
219};
220export function setTransportFactory(newFunc) {
221 var retVal = createConnection;
222 createConnection = newFunc;
223 return retVal;
224}
225//# sourceMappingURL=connection.js.map
\No newline at end of file