@overseers/tch
Version:
Tedious Connection Handler
151 lines • 7.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TCH = void 0;
const index_1 = require("../index");
class TCH {
constructor() {
this.connections = [];
this.createConnections = (poolConfig, connectionConfig) => {
// console.log('creating connections')
this.connectionConfig = connectionConfig;
this.poolConfig = poolConfig;
if (this.connections.length < poolConfig.min) {
for (let i = 0; i < this.poolConfig.min - this.connections.length; i++) {
this.createConnection();
}
}
this.cleanup = setInterval(() => {
let currentTS = Date.now();
// console.log('connections to close:', this.connections.filter(conn => conn.ttl).length, 'Connections left:', this.connections.length, 'Connections busy:', this.connections.filter(conn => conn.busy).length)
for (let i = 0; i < this.connections.length; i++) {
if (this.connections[i].isTimed && this.connections[i].ttl < currentTS) {
this.cleanUp(i);
}
else if (this.connections[i].isTimed && !this.connections[i].ttl && !this.connections[i].busy) {
this.cleanUp(i);
}
}
}, 5000);
return this;
};
this.cleanUp = (i) => {
// console.log('Closing connection with the id:', this.connections[i].id)
this.connections[i].busy = true;
this.connections[i].ready = false;
this.connections[i].connection.close();
this.removeConnection(i);
};
this.removeConnection = (index) => {
this.connections[index].connection.removeAllListeners();
this.connections.splice(index, 1);
};
this.createConnection = () => {
let index = this.connections.push({
busy: false,
ready: false,
isTimed: false,
id: 0,
connection: new index_1.Connection(this.connectionConfig)
}) - 1;
let id = this.connections[Math.min(this.connections.length - 1, Math.max(0, index - 1))].id + 1;
this.connections[index].id = id;
this.connections[index].connection.on('end', () => this.handleMinConnectionClose(id));
this.connections[index].connection.on('errorMessage', error => this.handleErrorECONNECT(id, error));
this.connections[index].connection.on('error', error => this.handleErrorECONNECT(id, error));
this.connections[index].connection.on('debug', (msg) => {
let updatedIndex = this.connections.findIndex(connection => connection.id === id);
if (msg.includes('State change')) {
let splitMsg = msg.split(': ')[1].split(' -> ');
if (splitMsg[1] === index_1.TediousStates.LOGGED_IN) {
this.connections[updatedIndex].ready = true;
this.connections[updatedIndex].connection.removeAllListeners('debug');
}
}
});
return index;
};
this.handleErrorECONNECT = (id, error) => {
if (error.message.includes('ECONNRESET') || error.name.includes('ECONNRESET')) {
let updatedIndex = this.connections.findIndex(connection => connection.id === id);
this.handleMinConnectionClose(updatedIndex);
}
};
this.handleMinConnectionClose = (id) => {
let updatedIndex = this.connections.findIndex(connection => connection.id === id);
if (updatedIndex > -1) {
let shouldCreateNew = this.connections[updatedIndex].isTimed;
this.removeConnection(updatedIndex);
if (shouldCreateNew) {
this.createConnection();
}
}
};
this.createTimedConnection = () => {
let index = this.createConnection();
this.connections[index].isTimed = true;
};
this.getConnection = () => {
return new Promise((resolve) => {
(function waitForActiveConnection() {
let index = this.connections.findIndex(connection => connection.ready && !connection.busy);
if (index > -1) {
this.connections[index].busy = true;
let id = this.connections[index].id;
this.connections[index].ttl = undefined;
resolve({
connection: this.connections[index].connection, release: () => {
let updatedIndex = this.connections.findIndex(conn => conn.id === id);
this.connections[updatedIndex].busy = false;
if (this.connections[updatedIndex].isTimed) {
this.connections[updatedIndex].ttl = Date.now() + this.poolConfig.timeout;
}
}
});
}
else {
if (this.connections.length < this.poolConfig.max) {
this.createTimedConnection();
}
setImmediate(waitForActiveConnection.bind(this));
}
}).bind(this)();
});
};
this.getHandledRequest = (sql, inputParams = [], outputParams = []) => {
return new Promise(async (resolve, reject) => {
let { connection, release } = await this.getConnection();
let data = [];
let request = new index_1.Request(sql, (error, rowCount, rows) => {
release();
if (error) {
reject(error);
}
else {
resolve(data);
}
});
inputParams.forEach(param => {
request.addParameter(param.name, param.type, param.value);
});
outputParams.forEach(param => {
request.addOutputParameter(param.name, param.type, param.value);
});
request.on('row', (columns) => {
let emptyColumnNames = columns.filter(column => column.metadata.colName === '');
emptyColumnNames.forEach(column => data.push(column.value));
let filledColumnNames = columns.filter(column => column.metadata.colName !== '');
if (filledColumnNames.length > 0) {
data.push(filledColumnNames.reduce((acc, next) => {
acc[next.metadata.colName] = next.value;
return acc;
}, {}));
}
});
connection.execSql(request);
});
};
}
}
exports.TCH = TCH;
exports.default = new TCH();
//# sourceMappingURL=ConnectionHandler.js.map