@biorate/haproxy
Version:
Haproxy runner
170 lines (169 loc) • 7.02 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _HaproxyConnector_configs;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HaproxyConnector = void 0;
const haproxy_1 = __importDefault(require("haproxy"));
const tools_1 = require("@biorate/tools");
const inversion_1 = require("@biorate/inversion");
const connector_1 = require("@biorate/connector");
const tools_2 = require("@biorate/tools");
const os_1 = require("os");
const fs_1 = require("fs");
const util_1 = require("util");
const errors_1 = require("./errors");
__exportStar(require("./errors"), exports);
__exportStar(require("./interfaces"), exports);
let HaproxyConnector = class HaproxyConnector extends connector_1.Connector {
constructor() {
super(...arguments);
_HaproxyConnector_configs.set(this, new WeakMap());
this.namespace = 'Haproxy';
}
async connect(config) {
let connection;
try {
this.cleanup(config);
const cfgFile = this.createConfig(config);
connection = new haproxy_1.default(this.path(config, 'sock'), {
pidFile: this.path(config, 'pid'),
config: cfgFile,
});
for (const method of [
'start',
'stop',
'softstop',
'reload',
'verify',
'running',
'clear',
'disable',
'enable',
'pause',
'resume',
'errors',
'weight',
'maxconn',
'ratelimit',
'compression',
'info',
'session',
'stat',
])
connection[method] = (0, util_1.promisify)(connection[method].bind(connection));
await connection.start();
await this.readiness(connection, config);
__classPrivateFieldGet(this, _HaproxyConnector_configs, "f").set(connection, config);
}
catch (e) {
throw new errors_1.HaproxyCantConnectError(e);
}
return connection;
}
async readiness(connection, config) {
if (config?.readiness?.nodes?.length) {
let i = 0;
w: while (true) {
const stats = await connection.stat();
for (const stat of stats) {
if (!config.readiness.nodes.includes(stat.svname))
continue;
if (stat.status === 'UP')
break w;
}
console.debug(`Attempt to connect to Haproxy: [%s]`, config.name);
await tools_1.timer.wait(config?.readiness?.delay ?? 1000);
++i;
if (i > (config?.readiness?.retries ?? 1))
throw new errors_1.HaproxyConnectionTimeoutError(config.name);
}
}
}
path(config, ext) {
return tools_2.path.create((0, os_1.tmpdir)(), `${config.name}.haproxy.${ext}`);
}
cleanup(config) {
try {
(0, fs_1.unlinkSync)(this.path(config, 'sock'));
}
catch { }
try {
(0, fs_1.unlinkSync)(this.path(config, 'pid'));
}
catch { }
try {
(0, fs_1.unlinkSync)(this.path(config, 'config'));
}
catch { }
}
createConfig(config) {
let data = '';
const file = this.path(config, 'config');
for (const header in config.config) {
data += header + os_1.EOL;
if (Array.isArray(config.config[header]))
for (const field of config.config[header])
data += ' ' + field + os_1.EOL;
else
for (const field in config.config[header])
data += ' ' + field + ' ' + config.config[header][field] + os_1.EOL;
}
data = data.replace('{{stat_socket_path}}', this.path(config, 'sock'));
(0, fs_1.writeFileSync)(file, data, 'utf-8');
if (config.debug)
console.debug(`Haproxy [${config.name}] config:${os_1.EOL}`, data);
return file;
}
async destructor() {
for (const [, connection] of this.connections) {
try {
await connection.stop();
this.cleanup(__classPrivateFieldGet(this, _HaproxyConnector_configs, "f").get(connection));
}
catch (e) {
console.error(e);
}
}
}
};
exports.HaproxyConnector = HaproxyConnector;
_HaproxyConnector_configs = new WeakMap();
__decorate([
(0, inversion_1.kill)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], HaproxyConnector.prototype, "destructor", null);
exports.HaproxyConnector = HaproxyConnector = __decorate([
(0, inversion_1.injectable)()
], HaproxyConnector);