"use strict";
[Link](exports, "__esModule", { value: true });
[Link] = [Link] = [Link] = void 0;
const exponential_1 = require("./backoff/exponential");
const host_1 = require("./host");
const http = require("http");
const https = require("https");
const querystring = require("querystring");
/**
* Status codes that will cause a host to be marked as 'failed' if we get
* them from a request to Influx.
* @type {Array}
*/
const resubmitErrorCodes = [
"ETIMEDOUT",
"ESOCKETTIMEDOUT",
"ECONNRESET",
"ECONNREFUSED",
"EHOSTUNREACH",
];
/**
* An ServiceNotAvailableError is returned as an error from requests that
* result in a > 500 error code.
*/
class ServiceNotAvailableError extends Error {
constructor(message) {
super();
[Link] = message;
[Link](this, [Link]);
}
}
[Link] = ServiceNotAvailableError;
/**
* An RequestError is returned as an error from requests that
* result in a 300 <= error code <= 500.
*/
class RequestError extends Error {
constructor(req, res, body) {
super();
[Link] = req;
[Link] = res;
[Link] = `A ${[Link]} ${[Link]} error occurred: $
{body}`;
[Link](this, [Link]);
}
static Create(req, res, callback) {
let body = "";
[Link]("data", (str) => {
body += [Link]();
});
[Link]("end", () => callback(new RequestError(req, res, body)));
}
}
[Link] = RequestError;
/**
* Creates a function generation that returns a wrapper which only allows
* through the first call of any function that it generated.
*/
function doOnce() {
let handled = false;
return (fn) => {
return (arg) => {
if (handled) {
return;
}
handled = true;
fn(arg);
};
};
}
function setToArray(itemSet) {
const output = [];
[Link]((value) => {
[Link](value);
});
return output;
}
const request = (options, callback) => {
if ([Link] === "https:") {
return [Link](options, callback);
}
return [Link](options, callback);
};
/**
*
* The Pool maintains a list available Influx hosts and dispatches requests
* to them. If there are errors connecting to hosts, it will disable that
* host for a period of time.
*/
class Pool {
/**
* Creates a new Pool instance.
* @param {IPoolOptions} options
*/
constructor(options) {
this._options = [Link]({ backoff: new
exponential_1.ExponentialBackoff({
initial: 300,
max: 10 * 1000,
random: 1,
}), maxRetries: 2, requestTimeout: 30 * 1000 }, options);
this._index = 0;
this._hostsAvailable = new Set();
this._hostsDisabled = new Set();
this._timeout = this._options.requestTimeout;
}
/**
* Returns a list of currently active hosts.
* @return {Host[]}
*/
getHostsAvailable() {
return setToArray(this._hostsAvailable);
}
/**
* Returns a list of hosts that are currently disabled due to network
* errors.
* @return {Host[]}
*/
getHostsDisabled() {
return setToArray(this._hostsDisabled);
}
/**
* Inserts a new host to the pool.
*/
addHost(url, options = {}) {
const host = new host_1.Host(url, this._options.[Link](), options);
this._hostsAvailable.add(host);
return host;
}
/**
* Returns true if there's any host available to by queried.
* @return {Boolean}
*/
hostIsAvailable() {
return this._hostsAvailable.size > 0;
}
/**
* Makes a request and calls back with the response, parsed as JSON.
* An error is returned on a non-2xx status code or on a parsing exception.
*/
json(options) {
return [Link](options).then((res) => [Link](res));
}
/**
* Makes a request and resolves with the plain text response,
* if possible. An error is raised on a non-2xx status code.
*/
text(options) {
return new Promise((resolve, reject) => {
[Link](options, (err, res) => {
if (err) {
return reject(err);
}
let output = "";
[Link]("data", (str) => {
output += [Link]();
});
[Link]("end", () => resolve(output));
});
});
}
/**
* Makes a request and discards any response body it receives.
* An error is returned on a non-2xx status code.
*/
discard(options) {
return new Promise((resolve, reject) => {
[Link](options, (err, res) => {
if (err) {
return reject(err);
}
[Link]("data", () => {
/* ignore */
});
[Link]("end", () => resolve());
});
});
}
/**
* Ping sends out a request to all available Influx servers, reporting on
* their response time and version number.
*/
ping(timeout, path = "/ping", auth = undefined) {
const todo = [];
setToArray(this._hostsAvailable)
.concat(setToArray(this._hostsDisabled))
.forEach((host) => {
const start = [Link]();
const url = [Link];
const once = doOnce();
return [Link](new Promise((resolve) => {
const headers = {};
if (typeof auth !== "undefined") {
const encodedAuth = [Link](auth).toString("base64");
headers["Authorization"] = `Basic ${encodedAuth}`;
}
const req = request([Link]({ hostname: [Link], method:
"GET", path, port: Number([Link]), protocol: [Link], timeout, headers:
headers }, [Link]), once((res) => {
resolve({
url,
res: [Link](),
online: [Link] < 300,
rtt: [Link]() - start,
version: [Link]["x-influxdb-version"],
});
}));
const fail = once(() => {
[Link]();
resolve({
online: false,
res: null,
rtt: Infinity,
url,
version: null,
});
});
// Support older Nodes and polyfills which don't allow .timeout()
in
// the request options, wrapped in a conditional for even worse
// polyfills. See:
[Link]
if (typeof [Link] === "function") {
[Link](timeout, () => {
[Link](fail, arguments);
}); // Tslint:disable-line
}
[Link]("timeout", fail);
[Link]("error", fail);
[Link]();
}));
});
return [Link](todo);
}
/**
* Makes a request and calls back with the IncomingMessage stream,
* if possible. An error is returned on a non-2xx status code.
*/
stream(options, callback) {
if (![Link]()) {
return callback(new ServiceNotAvailableError("No host available"),
null);
}
const once = doOnce();
const host = this._getHost();
let path = [Link] === "/" ? "" : [Link];
path += [Link];
if ([Link]) {
path += "?" + [Link]([Link]);
}
const req = request([Link]({ headers: {
"content-length": [Link] ? [Link]([Link]).length :
0,
}, hostname: [Link], method: [Link], path, port:
Number([Link]), protocol: [Link], timeout: this._timeout },
[Link]), once((res) => {
[Link]("utf8");
if ([Link] >= 500) {
[Link]("data", () => {
/* ignore */
});
[Link]("end", () => {
return this._handleRequestError(new
ServiceNotAvailableError([Link]), host, options, callback);
});
return;
}
if ([Link] >= 300) {
return [Link](req, res, (err) => callback(err, res));
}
[Link]();
return callback(undefined, res);
}));
// Handle network or HTTP parsing errors:
[Link]("error", once((err) => {
this._handleRequestError(err, host, options, callback);
}));
// Handle timeouts:
[Link]("timeout", once(() => {
[Link]();
this._handleRequestError(new ServiceNotAvailableError("Request timed
out"), host, options, callback);
}));
// Support older Nodes and polyfills which don't allow .timeout() in the
// request options, wrapped in a conditional for even worse polyfills. See:
// [Link]
if (typeof [Link] === "function") {
[Link]([Link] || this._timeout); //
Tslint:disable-line
}
// Write out the body:
if ([Link]) {
[Link]([Link]);
}
[Link]();
}
/**
* Returns the next available host for querying.
* @return {Host}
*/
_getHost() {
const available = setToArray(this._hostsAvailable);
const host = available[this._index];
this._index = (this._index + 1) % [Link];
return host;
}
/**
* Re-enables the provided host, returning it to the pool to query.
* @param {Host} host
*/
_enableHost(host) {
this._hostsDisabled.delete(host);
this._hostsAvailable.add(host);
}
/**
* Disables the provided host, removing it from the query pool. It will be
* re-enabled after a backoff interval
*/
_disableHost(host) {
const delay = [Link]();
if (delay > 0) {
this._hostsAvailable.delete(host);
this._hostsDisabled.add(host);
this._index %= [Link](1, this._hostsAvailable.size);
setTimeout(() => this._enableHost(host), delay);
}
}
_handleRequestError(err, host, options, callback) {
if (!(err instanceof ServiceNotAvailableError) &&
) {
return callback(err, null);
}
this._disableHost(host);
const retries = [Link] || 0;
if (retries < this._options.maxRetries && [Link]()) {
[Link] = retries + 1;
return [Link](options, callback);
}
callback(err, null);
}
}
[Link] = Pool;