diff --git a/config.js b/config.js index 2ee0e4b..8bbba58 100644 --- a/config.js +++ b/config.js @@ -10,23 +10,23 @@ //Параметры подключения к БД let dbConnect = { //Пользователь БД - user: "parus", + sUser: "parus", //Пароль пользователя БД - password: "parus", + sPassword: "parus", //Строка подключения к БД - connectString: "DEMOP_CITKSERV_WAN", + sConnectString: "DEMOP_CITKSERV_WAN", //Наименование модуля (для сессии БД) - sessionModuleName: "PARUS$ExchangeServer", + sSessionModuleName: "PARUS$ExchangeServer", //Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД) - connectorModule: "parus_oracle_db.js" + sConnectorModule: "parus_oracle_db.js" }; //Параметры обработки очереди исходящих сообщений let outgoing = { //Размер блока одновременно обрабатываемых исходящих сообщений - portionSize: 1, + nPortionSize: 1, //Скорость проверки наличия исходящих сообщений (мс) - checkTimeout: 500 + nCheckTimeout: 500 }; //----------------- diff --git a/core/db_connector.js b/core/db_connector.js index cc4d01d..62c51f5 100644 --- a/core/db_connector.js +++ b/core/db_connector.js @@ -17,9 +17,9 @@ const { ServerError } = require("@core/server_errors.js"); //Типовая ош //---------- //Состояния записей журнала работы сервиса -const MSG_TYPE_INF = 0; //Информация -const MSG_TYPE_WRN = 1; //Предупреждение -const MSG_TYPE_ERR = 2; //Ошибка +const NLOG_STATE_INF = 0; //Информация +const NLOG_STATE_WRN = 1; //Предупреждение +const NLOG_STATE_ERR = 2; //Ошибка //------------ // Тело модуля @@ -27,23 +27,23 @@ const MSG_TYPE_ERR = 2; //Ошибка class DBConnector { //Конструктор - constructor(dbConnect) { + constructor(prms) { //Проверяем структуру переданного объекта для подключения - let checkResult = checkObject(dbConnect, { + let checkResult = checkObject(prms, { fields: [ - { name: "user", required: true }, - { name: "password", required: true }, - { name: "connectString", required: true }, - { name: "sessionModuleName", required: true }, - { name: "connectorModule", required: false } + { name: "sUser", required: true }, + { name: "sPassword", required: true }, + { name: "sConnectString", required: true }, + { name: "sSessionModuleName", required: true }, + { name: "sConnectorModule", required: false } ] }); //Если структура объекта в норме if (!checkResult) { //Проверяем наличие модуля для работы с БД в настройках подключения - if (dbConnect.connectorModule) { + if (prms.sConnectorModule) { //Подключим модуль - this.connector = require(makeModuleFullPath(dbConnect.connectorModule)); + this.connector = require(makeModuleFullPath(prms.sConnectorModule)); //Проверим его интерфейс if ( !checkModuleInterface(this.connector, { @@ -61,12 +61,12 @@ class DBConnector { ) { throw new ServerError( glConst.ERR_MODULES_BAD_INTERFACE, - "Модуль " + dbConnect.module + " реализует неверный интерфейс!" + "Модуль " + prms.sConnectorModule + " реализует неверный интерфейс!" ); } //Всё успешно - сохраним настройки подключения this.connectSettings = {}; - _.extend(this.connectSettings, dbConnect); + _.extend(this.connectSettings, prms); //Инициализируем остальные свойства this.connection = {}; } else { @@ -85,12 +85,12 @@ class DBConnector { //Подключиться к БД async connect() { try { - this.connection = await this.connector.connect( - this.connectSettings.user, - this.connectSettings.password, - this.connectSettings.connectString, - this.connectSettings.sessionModuleName - ); + this.connection = await this.connector.connect({ + sUser: this.connectSettings.sUser, + sPassword: this.connectSettings.sPassword, + sConnectString: this.connectSettings.sConnectString, + sSessionModuleName: this.connectSettings.sSessionModuleName + }); return this.connection; } catch (e) { throw new ServerError(glConst.ERR_DB_CONNECT, e.message); @@ -99,7 +99,7 @@ class DBConnector { //Отключиться от БД async disconnect() { try { - await this.connector.disconnect(this.connection); + await this.connector.disconnect({ connection: this.connection }); this.connection = {}; return; } catch (e) { @@ -109,9 +109,12 @@ class DBConnector { //Получить список сервисов async getServices() { try { - let srvs = await this.connector.getServices(this.connection); + let srvs = await this.connector.getServices({ connection: this.connection }); let srvsFuncs = srvs.map(async srv => { - const response = await this.connector.getServiceFunctions(this.connection, srv.NRN); + const response = await this.connector.getServiceFunctions({ + connection: this.connection, + ddd: srv.NRN + }); let tmp = {}; _.extend(tmp, srv, { FN: [] }); response.map(f => { @@ -126,21 +129,61 @@ class DBConnector { } } //Запись в журнал работы - async putLog(msgType, msg, queueID) { - try { - let res = await this.connector.log(this.connection, msgType, msg, queueID); - return res; - } catch (e) { - throw new ServerError(glConst.ERR_DB_EXECUTE, e.message); + async putLog(prms) { + //Проверяем структуру переданного объекта для подключения + let checkResult = checkObject(prms, { + fields: [ + { name: "nLogState", required: true }, + { name: "sMsg", required: false }, + { name: "nServiceId", required: false }, + { name: "nServiceFnId", required: false }, + { name: "nQueueId", required: false } + ] + }); + //Если структура объекта в норме + if (!checkResult) { + try { + let res = await this.connector.log({ + connection: this.connection, + nLogState: prms.nLogState, + sMsg: prms.sMsg, + nServiceId: prms.nServiceId, + nServiceFnId: prms.nServiceFnId, + nQueueId: prms.nQueueId + }); + return res; + } catch (e) { + throw new ServerError(glConst.ERR_DB_EXECUTE, e.message); + } + } else { + throw new ServerError( + glConst.ERR_OBJECT_BAD_INTERFACE, + "qqqОбъект имеет недопустимый интерфейс: " + checkResult + ); } } //Считать очередную порцию исходящих сообщений - async getOutgoing(portionSize) { - try { - let res = await this.connector.getQueueOutgoing(this.connection, portionSize); - return res; - } catch (e) { - throw new ServerError(glConst.ERR_DB_EXECUTE, e.message); + async getOutgoing(prms) { + //Проверяем структуру переданного объекта для подключения + let checkResult = checkObject(prms, { + fields: [{ name: "nPortionSize", required: true }] + }); + //Если структура объекта в норме + if (!checkResult) { + try { + let res = await this.connector.getQueueOutgoing({ + connection: this.connection, + nPortionSize: prms.nPortionSize + }); + return res; + } catch (e) { + throw new ServerError(glConst.ERR_DB_EXECUTE, e.message); + } + } else { + throw new ServerError( + glConst.ERR_OBJECT_BAD_INTERFACE, + "Объект имеет недопустимый интерфейс: " + checkResult + ); } } } @@ -149,7 +192,7 @@ class DBConnector { // Интерфейс модуля //----------------- -exports.MSG_TYPE_INF = MSG_TYPE_INF; -exports.MSG_TYPE_WRN = MSG_TYPE_WRN; -exports.MSG_TYPE_ERR = MSG_TYPE_ERR; +exports.NLOG_STATE_INF = NLOG_STATE_INF; +exports.NLOG_STATE_WRN = NLOG_STATE_WRN; +exports.NLOG_STATE_ERR = NLOG_STATE_ERR; exports.DBConnector = DBConnector; diff --git a/core/utils.js b/core/utils.js index 92750f0..9b1c10b 100644 --- a/core/utils.js +++ b/core/utils.js @@ -73,13 +73,16 @@ const checkObject = (obj, interface) => { let noValues = []; //Обходим проверяемые поля interface.fields.forEach(fld => { - //Проверим наличие поля в объекте - if (!(fld.name in obj)) { + //Проверим наличие поля в объекте (только для обязательных) + if (fld.required && !(fld.name in obj)) { //Поля нет noFields.push(fld.name); } else { //Поле есть, проверим наличие значения - if (fld.required && !obj[fld.name]) + if ( + fld.required && + (obj[fld.name] === "undefined" || obj[fld.name] === null || obj[fld.name] === "") + ) //Обязательное поле не содержит значения noValues.push(fld.name); } diff --git a/modules/parus_oracle_db.js b/modules/parus_oracle_db.js index 4719405..5779319 100644 --- a/modules/parus_oracle_db.js +++ b/modules/parus_oracle_db.js @@ -38,39 +38,45 @@ const SLOG_STATE_ERR = "ERR"; //Ошибка (строковый код) //------------ //Подключение к БД -const connect = async (user, password, connectString, moduleName) => { +const connect = async prms => { try { - const conn = await oracledb.getConnection({ - user, - password, - connectString - }); - conn.module = moduleName; - return conn; + if (prms && prms.sUser && prms.sPassword && prms.sConnectString) { + const conn = await oracledb.getConnection({ + user: prms.sUser, + password: prms.sPassword, + connectString: prms.sConnectString + }); + if (prms.sSessionModuleName) conn.module = prms.sSessionModuleName; + return conn; + } else { + throw new Error( + "Не указаны параметры подключения (отсутствует одно из полей: sUser, sPassword, sConnectString)" + ); + } } catch (e) { throw new Error(e.message); } }; //Отключение от БД -const disconnect = async connection => { - if (connection) { +const disconnect = async prms => { + if (prms && prms.connection) { try { - const conn = await connection.close(); + const conn = await prms.connection.close(); return; } catch (e) { throw new Error(e.message); } } else { - throw new Error("Не указано подключение"); + throw new Error("Не указано подключение (отсутствует поле: connection)"); } }; //Получение списка сервисов -const getServices = async connection => { +const getServices = prms => { return new Promise((resolve, reject) => { - if (connection) { - connection.execute( + if (prms && prms.connection) { + prms.connection.execute( "BEGIN PKG_EXS.SERVICE_GET(RCSERVICES => :RCSERVICES); END;", { RCSERVICES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, { outFormat: oracledb.OBJECT }, @@ -94,115 +100,129 @@ const getServices = async connection => { } ); } else { - reject(new Error("Не указано подключение")); + reject(new Error("Не указано подключение (отсутствует поле: connection)")); } }); }; //Получение списка функций сервиса -const getServiceFunctions = (connection, serviceID) => { +const getServiceFunctions = prms => { return new Promise((resolve, reject) => { - if (connection) { - connection.execute( - "BEGIN PKG_EXS.SERVICEFN_GET(NSERVICE => :NSERVICE, RCSERVICEFNS => :RCSERVICEFNS); END;", - { NSERVICE: serviceID, RCSERVICEFNS: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, - { outFormat: oracledb.OBJECT }, - (err, result) => { - if (err) { - reject(new Error(err.message)); - } else { - let cursor = result.outBinds.RCSERVICEFNS; - let queryStream = cursor.toQueryStream(); - let rows = []; - queryStream.on("data", row => { - rows.push(row); - }); - queryStream.on("error", err => { + if (prms && prms.connection) { + if (prms.nServiceId) { + prms.connection.execute( + "BEGIN PKG_EXS.SERVICEFN_GET(NSERVICE => :NSERVICE, RCSERVICEFNS => :RCSERVICEFNS); END;", + { NSERVICE: prms.nServiceId, RCSERVICEFNS: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, + { outFormat: oracledb.OBJECT }, + (err, result) => { + if (err) { reject(new Error(err.message)); - }); - queryStream.on("close", () => { - resolve(rows); - }); + } else { + let cursor = result.outBinds.RCSERVICEFNS; + let queryStream = cursor.toQueryStream(); + let rows = []; + queryStream.on("data", row => { + rows.push(row); + }); + queryStream.on("error", err => { + reject(new Error(err.message)); + }); + queryStream.on("close", () => { + resolve(rows); + }); + } } - } - ); + ); + } else { + reject(new Error("Не указан идентификатор сервиса")); + } } else { - reject(new Error("Не указано подключение")); + reject(new Error("Не указано подключение (отсутствует поле: connection)")); } }); }; //Запись в протокол работы -const log = (connection, logState, msg, queueID) => { +const log = prms => { return new Promise((resolve, reject) => { - if (connection) { - connection.execute( - "BEGIN PKG_EXS.LOG_PUT(NLOG_STATE => :NLOG_STATE, SMSG => :SMSG, NEXSQUEUE => :NEXSQUEUE, RCLOG => :RCLOG); END;", - { - NLOG_STATE: logState, - SMSG: msg, - NEXSQUEUE: queueID, - RCLOG: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true }, - (err, result) => { - if (err) { - reject(new Error(err.message)); - } else { - let cursor = result.outBinds.RCLOG; - let queryStream = cursor.toQueryStream(); - let rows = []; - queryStream.on("data", row => { - rows.push(row); - }); - queryStream.on("error", err => { + if (prms && prms.connection) { + if (!(prms.nLogState === "undefined")) { + prms.connection.execute( + "BEGIN PKG_EXS.LOG_PUT(NLOG_STATE => :NLOG_STATE, SMSG => :SMSG, NEXSSERVICE => :NEXSSERVICE, NEXSSERVICEFN => :NEXSSERVICEFN, NEXSQUEUE => :NEXSQUEUE, RCLOG => :RCLOG); END;", + { + NLOG_STATE: prms.nLogState, + SMSG: prms.sMsg, + NEXSSERVICE: prms.nServiceId, + NEXSSERVICEFN: prms.nServiceFnId, + NEXSQUEUE: prms.nQueueId, + RCLOG: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }, + { outFormat: oracledb.OBJECT, autoCommit: true }, + (err, result) => { + if (err) { reject(new Error(err.message)); - }); - queryStream.on("close", () => { - resolve(rows[0]); - }); + } else { + let cursor = result.outBinds.RCLOG; + let queryStream = cursor.toQueryStream(); + let rows = []; + queryStream.on("data", row => { + rows.push(row); + }); + queryStream.on("error", err => { + reject(new Error(err.message)); + }); + queryStream.on("close", () => { + resolve(rows[0]); + }); + } } - } - ); + ); + } else { + reject(new Error("Не указан тип сообщения журнала (отсутствует поле: nLogState)")); + } } else { - reject(new Error("Не указано подключение")); + reject(new Error("Не указано подключение (отсутствует поле: connection)")); } }); }; //Считывание очередной порции исходящих сообщений из очереди -const getQueueOutgoing = (connection, portionSize) => { +const getQueueOutgoing = prms => { return new Promise((resolve, reject) => { - if (connection) { - connection.execute( - "BEGIN PKG_EXS.QUEUE_NEXT_GET(NPORTION => :NPORTION, NSRV_TYPE => :NSRV_TYPE, RCQUEUES => :RCQUEUES); END;", - { - NPORTION: portionSize, - NSRV_TYPE: NSRV_TYPE_SEND, - RCQUEUES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true, fetchInfo: { BMSG: { type: oracledb.BUFFER } } }, - (err, result) => { - if (err) { - reject(new Error(err.message)); - } else { - let cursor = result.outBinds.RCQUEUES; - let queryStream = cursor.toQueryStream(); - let rows = []; - queryStream.on("data", row => { - rows.push(row); - }); - queryStream.on("error", err => { + if (prms && prms.connection) { + if (prms.nPortionSize) { + prms.connection.execute( + "BEGIN PKG_EXS.QUEUE_NEXT_GET(NPORTION_SIZE => :NPORTION_SIZE, NSRV_TYPE => :NSRV_TYPE, RCQUEUES => :RCQUEUES); END;", + { + NPORTION_SIZE: prms.nPortionSize, + NSRV_TYPE: NSRV_TYPE_SEND, + RCQUEUES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } + }, + { outFormat: oracledb.OBJECT, autoCommit: true, fetchInfo: { bMsg: { type: oracledb.BUFFER } } }, + (err, result) => { + if (err) { reject(new Error(err.message)); - }); - queryStream.on("close", () => { - resolve(rows); - }); + } else { + let cursor = result.outBinds.RCQUEUES; + let queryStream = cursor.toQueryStream(); + let rows = []; + queryStream.on("data", row => { + rows.push(row); + }); + queryStream.on("error", err => { + reject(new Error(err.message)); + }); + queryStream.on("close", () => { + resolve(rows); + }); + } } - } - ); + ); + } else { + reject(new Error("Не указан размер извлекаемой порции сообщений (отсутствует поле: nPortionSize)")); + } } else { - reject(new Error("Не указано подключение")); + reject(new Error("Не указано подключение (отсутствует поле: connection)")); } }); }; diff --git a/package.json b/package.json index 339564d..59ac2b2 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "start": "node index.js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "node test.js" }, "repository": { "type": "git", diff --git a/index.js b/test.js similarity index 95% rename from index.js rename to test.js index 43e89fa..a7ce4c0 100644 --- a/index.js +++ b/test.js @@ -23,7 +23,7 @@ try { a.connect() .then(res => { console.log("CONNECTED"); - a.getOutgoing(cfg.outgoing.portionSize) + a.getOutgoing({ nPortionSize: cfg.outgoing.nPortionSize }) .then(res => { if (res.length > 0) { res.map(r => { @@ -32,7 +32,7 @@ try { } else { console.log("NO MESSAGES IN QUEUE!!!"); } - a.putLog(db.MSG_TYPE_INF, "Сервер приложений подключен") + a.putLog({ nLogState: db.NLOG_STATE_INF, sMsg: "Сервер приложений подключен" }) .then(res => { console.log(res); setTimeout(() => {