UNPKG

vitis-engine-lib

Version:

Lib used on Vitis engines

262 lines (226 loc) 7.44 kB
import { Client, Connection } from 'pg'; import Logger from './logger'; import fs from 'fs'; /** * Classe Db */ export default class Db { // Properties private properties_: any; // Paramètres de connexion private connexionParams_: any; // Client base de données private client_: any; // Définit si la connexion est en cours private connected_: boolean = false; // Définit si l'on doit tenter de se connecter en ssl si possible private preferMode_: boolean = false; // Timeout avant déconnexion private connectionTimeout_: number = 10000; // Date de la dernière requête private lastQueryDate_: number = 0; // fonction timeout de déconnexion private disconnectFncTimeout_: any; // Logger private logger_: Logger; /** * Constructeur */ constructor(properties: any, connexionParams: any, logger: Logger) { this.properties_ = properties; this.connexionParams_ = connexionParams; this.logger_ = logger; if (this.connexionParams_.autoSslConfig === true) { this.connexionParams_.ssl = this.loadSslConfigFromProperties(); } } /** * * @returns {boolean} */ public isConnected(): boolean { return this.connected_; } /** * Connexion à la base */ public connect(): Promise<void> { return new Promise<void>((resolve, reject) => { this.client_ = new Client(this.connexionParams_); this.client_.connect().then(() => { this.logger_.log('Connected to the database', null, 'DEBUG'); this.connected_ = true; }).catch((err: any) => { this.connected_ = false; this.logger_.log('DB ERROR : Cannot connect to the database', err, 'ERROR'); }).finally(() => { resolve(); }) }); } /** * Connexion à la base */ public connectWithSslCheck() { return new Promise<void>((resolve, reject) => { const self = this; const tmp_con_: any = new Connection(); tmp_con_.stream.once('data', function (buffer: any) { const responseCode = buffer.toString('utf8'); switch (responseCode) { case 'S': // Server supports SSL connections, continue with a secure connection break; case 'N': // Server does not support SSL connections // si l'appli est en mode prefer et que le SSL n'est pas actif // on désactive le ssl if (self.preferMode_ && self.connexionParams_.ssl !== false) { self.logger_.log('SSL is disabled for this database', null, 'DEBUG'); delete self.connexionParams_.autoSslConfig; delete self.connexionParams_.ssl; } break; default: // Any other response byte, including 'E' (ErrorResponse) indicating a server error self.logger_.log('DB ERROR : Cannot get SSL informations', null, 'ERROR'); return; } tmp_con_.end() tmp_con_.stream.destroy() self.connect().then(() => { resolve(); }); }); tmp_con_.stream.on('error', function (error: Error) { self.logger_.log('DB ERROR : Cannot get SSL informations', error, 'ERROR'); reject(); }); tmp_con_.stream.once('ready', function () { setTimeout(() => { tmp_con_.requestSsl(); }, 0) }); tmp_con_.stream.connect(this.connexionParams_.port, this.connexionParams_.host) }); } /** * Surcharge la configuration SSL pour la connection postgres */ private loadSslConfigFromProperties() { // require, prefer et allow ne nécéssite pas la vérification des certificats const oOptions: any = { rejectUnauthorized: false }; // on active le mode pour se reconnecter en non ssl en cas d'echec if (['prefer', 'allow'].indexOf(this.properties_.db_ssl_mode) > -1) { this.preferMode_ = true; return oOptions; } if (this.properties_.db_ssl_mode === 'require') { return oOptions; } if (['verify-ca', 'verify-full'].indexOf(this.properties_.db_ssl_mode) > -1) { // active la vérification des certificats serveurs oOptions.rejectUnauthorized = true; // Cert Authority if (fs.existsSync(this.properties_.db_ssl_root_cert)) { oOptions.ca = fs.readFileSync(this.properties_.db_ssl_root_cert).toString(); } // Key if (fs.existsSync(this.properties_.db_ssl_key)) { oOptions.key = fs.readFileSync(this.properties_.db_ssl_key).toString(); } // Certificat if (fs.existsSync(this.properties_.db_ssl_cert)) { oOptions.cert = fs.readFileSync(this.properties_.db_ssl_cert).toString(); } return oOptions; } // si le ssl n'est pas requis on le désactive // disabled return false; } /** * Change la durée maximale d'une connexion à la base * @param iDuration Durée en millisecond */ public setMaxConnectionTime(iDuration: number) { if (iDuration > 0) { this.connectionTimeout_ = iDuration; } else { this.logger_.log('DB ERROR : you are trying to set a max connection time negative or null (value unchanged)', null, 'ERROR'); } } /** * Désactive la déconnexion automatique à la base */ public disableTimeOut() { this.connectionTimeout_ = 0; } /** * Déconnexion de la base */ public disconnect() { this.client_.end(); this.connected_ = false; if (this.disconnectFncTimeout_) { clearTimeout(this.disconnectFncTimeout_); } } /** * Lance une requette * @param {string} sQuery Requette, pour utiliser des paramêtres utiliser $1, $2... * @param {Array | undefined} aParams Paramètres sous forme de tableau */ private execQuery_(sQuery: string, aParams: any[] = []) { return new Promise((resolve, reject) => { // Date de dernière requête this.lastQueryDate_ = Date.now(); // Lancement de la requête this.client_.query(sQuery, aParams, (err: any, res: any) => { // Retour if (err) { this.logger_.log('DB ERROR : ', err.stack); reject(err.stack); } else { resolve(res.rows); } // Déconnexion de la base après 10 secondes d'innactivité if (this.disconnectFncTimeout_) { clearTimeout(this.disconnectFncTimeout_); } if (this.connectionTimeout_ > 0) { this.disconnectFncTimeout_ = setTimeout(() => { if (Date.now() > (this.lastQueryDate_ - this.connectionTimeout_)) { if (this.connected_) { this.disconnect(); } } }, this.connectionTimeout_ + 10); } }); }); } public query(sQuery: string, aParams: any[] = [], bAutoConnect = true) { // si la connection est déjà faite if (this.connected_ && this.client_) { return this.execQuery_(sQuery, aParams); } if (!this.connected_ && bAutoConnect) { return new Promise((resolve, reject) => { // Connexion à la base this.connectWithSslCheck().then(() => { this.execQuery_(sQuery, aParams).then((rows) => { resolve(rows); }).catch((err) => { reject(err); }); }).catch((err) => { reject(err); }) }); } return new Promise((resolve, reject) => { reject(); }) } }