UNPKG

@overseers/tch

Version:

Tedious Connection Handler

151 lines 7.5 kB
"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