diff --git a/config.js b/config.js index 8bbba58..64b6a50 100644 --- a/config.js +++ b/config.js @@ -14,7 +14,7 @@ let dbConnect = { //Пароль пользователя БД sPassword: "parus", //Строка подключения к БД - sConnectString: "DEMOP_CITKSERV_WAN", + sConnectString: "DEMOP_CITKSERV", //Наименование модуля (для сессии БД) sSessionModuleName: "PARUS$ExchangeServer", //Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД) diff --git a/core/constants.js b/core/constants.js index a87a041..9bd5bf9 100644 --- a/core/constants.js +++ b/core/constants.js @@ -17,8 +17,3 @@ exports.SERR_MODULES_BAD_INTERFACE = "ERR_MODULES_BAD_INTERFACE"; //Ошибоч //Типовые коды ошибок работы с объектами exports.SERR_OBJECT_BAD_INTERFACE = "ERR_OBJECT_BAD_INTERFACE"; //Ошибочный интерфейс объекта - -//Типовые коды ошибок работы с БД -exports.SERR_DB_CONNECT = "ERR_DB_CONNECT"; //Ошибка подключения к БД -exports.SERR_DB_DISCONNECT = "ERR_DB_DISCONNECT"; //Ошибка отключения от БД -exports.SERR_DB_EXECUTE = "ERR_DB_EXECUTE"; //Ошибка исполнения функции в БД diff --git a/core/db_connector.js b/core/db_connector.js index f92726d..ffb5d3e 100644 --- a/core/db_connector.js +++ b/core/db_connector.js @@ -8,6 +8,7 @@ //---------------------- const _ = require("lodash"); //Работа с массивами и объектами +const EventEmitter = require("events"); //Обработчик пользовательских событий const glConst = require("../core/constants.js"); //Глобальные константы const { ServerError } = require("../core/server_errors.js"); //Типовая ошибка const { checkModuleInterface, makeModuleFullPath, checkObject } = require("../core/utils.js"); //Вспомогательные функции @@ -21,13 +22,24 @@ const NLOG_STATE_INF = 0; //Информация const NLOG_STATE_WRN = 1; //Предупреждение const NLOG_STATE_ERR = 2; //Ошибка +//Типовые коды ошибок работы с БД +const SERR_DB_CONNECT = "ERR_DB_CONNECT"; //Ошибка подключения к БД +const SERR_DB_DISCONNECT = "ERR_DB_DISCONNECT"; //Ошибка отключения от БД +const SERR_DB_EXECUTE = "ERR_DB_EXECUTE"; //Ошибка исполнения функции в БД + +//События модуля +const SEVT_DB_CONNECTOR_CONNECTED = "DB_CONNECTOR_CONNECTED"; //Подключено к БД +const SEVT_DB_CONNECTOR_DISCONNECTED = "DB_CONNECTOR_DISCONNECTED"; //Отключено от БД + //------------ // Тело модуля //------------ -class DBConnector { +class DBConnector extends EventEmitter { //Конструктор constructor(prms) { + //создадим экземпляр родительского класса + super(); //Проверяем структуру переданного объекта для подключения let sCheckResult = checkObject(prms, { fields: [ @@ -88,9 +100,10 @@ class DBConnector { try { this.connection = await this.connector.connect(this.connectSettings); this.bConnected = true; + this.emit(SEVT_DB_CONNECTOR_CONNECTED, this.connection); return this.connection; } catch (e) { - throw new ServerError(glConst.SERR_DB_CONNECT, e.message); + throw new ServerError(SERR_DB_CONNECT, e.message); } } //Отключиться от БД @@ -100,9 +113,10 @@ class DBConnector { await this.connector.disconnect({ connection: this.connection }); this.connection = {}; this.bConnected = false; + this.emit(SEVT_DB_CONNECTOR_DISCONNECTED, this.connection); return; } catch (e) { - throw new ServerError(glConst.SERR_DB_DISCONNECT, e.message); + throw new ServerError(SERR_DB_DISCONNECT, e.message); } } } @@ -126,10 +140,10 @@ class DBConnector { let res = await Promise.all(srvsFuncs); return res; } catch (e) { - throw new ServerError(glConst.SERR_DB_EXECUTE, e.message); + throw new ServerError(SERR_DB_EXECUTE, e.message); } } else { - throw new ServerError(glConst.SERR_DB_EXECUTE, "Нет подключения к БД"); + throw new ServerError(SERR_DB_EXECUTE, "Нет подключения к БД"); } } //Запись в журнал работы @@ -153,7 +167,7 @@ class DBConnector { let res = await this.connector.log(logData); return res; } catch (e) { - throw new ServerError(glConst.SERR_DB_EXECUTE, e.message); + throw new ServerError(SERR_DB_EXECUTE, e.message); } } else { throw new ServerError( @@ -162,7 +176,7 @@ class DBConnector { ); } } else { - throw new ServerError(glConst.SERR_DB_EXECUTE, "Нет подключения к БД"); + throw new ServerError(SERR_DB_EXECUTE, "Нет подключения к БД"); } } //Запись информации в журнал работы @@ -175,7 +189,7 @@ class DBConnector { let res = await this.putLog(logData); return res; } catch (e) { - throw new ServerError(glConst.SERR_DB_EXECUTE, e.message); + throw new ServerError(SERR_DB_EXECUTE, e.message); } } //Запись предупреждения в журнал работы @@ -188,7 +202,7 @@ class DBConnector { let res = await this.putLog(logData); return res; } catch (e) { - throw new ServerError(glConst.SERR_DB_EXECUTE, e.message); + throw new ServerError(SERR_DB_EXECUTE, e.message); } } //Запись ошибки в журнал работы @@ -201,7 +215,7 @@ class DBConnector { let res = await this.putLog(logData); return res; } catch (e) { - throw new ServerError(glConst.SERR_DB_EXECUTE, e.message); + throw new ServerError(SERR_DB_EXECUTE, e.message); } } //Считать очередную порцию исходящих сообщений @@ -220,7 +234,7 @@ class DBConnector { }); return res; } catch (e) { - throw new ServerError(glConst.SERR_DB_EXECUTE, e.message); + throw new ServerError(SERR_DB_EXECUTE, e.message); } } else { throw new ServerError( @@ -229,7 +243,7 @@ class DBConnector { ); } } else { - throw new ServerError(glConst.SERR_DB_EXECUTE, "Нет подключения к БД"); + throw new ServerError(SERR_DB_EXECUTE, "Нет подключения к БД"); } } } @@ -241,4 +255,9 @@ class DBConnector { exports.NLOG_STATE_INF = NLOG_STATE_INF; exports.NLOG_STATE_WRN = NLOG_STATE_WRN; exports.NLOG_STATE_ERR = NLOG_STATE_ERR; +exports.SERR_DB_CONNECT = SERR_DB_CONNECT; +exports.SERR_DB_DISCONNECT = SERR_DB_DISCONNECT; +exports.SERR_DB_EXECUTE = SERR_DB_EXECUTE; +exports.SEVT_DB_CONNECTOR_CONNECTED = SEVT_DB_CONNECTOR_CONNECTED; +exports.SEVT_DB_CONNECTOR_DISCONNECTED = SEVT_DB_CONNECTOR_DISCONNECTED; exports.DBConnector = DBConnector; diff --git a/core/logger.js b/core/logger.js index a757ae7..9cee641 100644 --- a/core/logger.js +++ b/core/logger.js @@ -51,11 +51,14 @@ class Logger { this.bLogDB = true; } } + //Удаление объекта для протоколирования в БД + removeDBConnector() { + this.dbConnector = ""; + this.bLogDB = false; + } //Протоколирование в БД async logToDB(loggerMessage) { //Если надо протоколировать и есть чем - console.log(this.dbConnector.bConnected); - console.log("DB LOGGER IN"); if (this.bLogDB && this.dbConnector && this.dbConnector.bConnected) { //Если протоколируем стандартное сообщение if (loggerMessage instanceof LoggerMessage) { @@ -85,7 +88,6 @@ class Logger { await this.dbConnector.putLogInf(loggerMessage); } } - console.log("DB LOGGER OUT"); } //Протоколирование async log(loggerMessage) { diff --git a/core/out_queue.js b/core/out_queue.js new file mode 100644 index 0000000..fb67d69 --- /dev/null +++ b/core/out_queue.js @@ -0,0 +1,110 @@ +/* + Сервис интеграции ПП Парус 8 с WEB API + Модуль ядра: отработка очереди исходящих сообщений +*/ + +//------------------------------ +// Подключение внешних библиотек +//------------------------------ + +const _ = require("lodash"); //Работа с массивами и коллекциями +const EventEmitter = require("events"); //Обработчик пользовательских событий +const { checkObject } = require("../core/utils.js"); //Вспомогательные функции + +//-------------------------- +// Глобальные идентификаторы +//-------------------------- + +//Типовые события +const SEVT_OUT_QUEUE_NEW = "OUT_QUEUE_NEW"; //Новое сообщение в очереди + +//------------ +// Тело модуля +//------------ + +//Класс очереди сообщений +class OutQueue extends EventEmitter { + //конструктор класса + constructor(prms, dbConn, logger) { + //Создадим экземпляр родительского класса + super(); + //Проверяем структуру переданного объекта с параметрами очереди + let sCheckResult = checkObject(prms, { + fields: [{ sName: "nPortionSize", bRequired: true }, { sName: "nCheckTimeout", bRequired: true }] + }); + //Если структура объекта в норме + if (!sCheckResult) { + //Хранилище очереди сообщений + this.queue = []; + //Признак функционирования обработчика + this.bWorking = false; + //Параметры очереди + _.extend(this, prms); + //Запомним подключение к БД + this.dbConn = dbConn; + //Запомним логгер + this.logger = logger; + } else { + throw new ServerError( + glConst.SERR_OBJECT_BAD_INTERFACE, + "Объект имеет недопустимый интерфейс: " + sCheckResult + ); + } + } + //Добавление нового исходящего сообщения в очередь для отработки + addMessage(message) { + //Cоздадим новый элемент очереди + let tmp = {}; + _.extend(tmp, message); + //добавим его в очередь + this.queue.push(tmp); + } + //Уведомление о получении нового сообщения + notifyNewOutMessage(message) { + //оповестим подписчиков о появлении нового отчета + this.emit(SEVT_OUT_QUEUE_NEW, message); + } + //Перезапуск опроса очереди исходящих сообщений + restartDetectingLoop() { + if (this.bWorking) + setTimeout(() => { + this.outDetectingLoop(); + }, this.nCheckTimeout); + } + //Опрос очереди исходящих сообщений + async outDetectingLoop() { + //Сходим на сервер за очередным исходящим сообщением + try { + let outMsgs = await this.dbConn.getOutgoing({ nPortionSize: this.nPortionSize }); + if (Array.isArray(outMsgs) && outMsgs.length > 0) { + await this.logger.info("Новое исходящее сообщение: " + outMsgs.toString()); + } else { + await this.logger.info("Нет новых сообщений"); + } + this.restartDetectingLoop(); + } catch (e) { + await this.logger.error("При получении исходящего сообщения: " + e.sCode + ": " + e.sMessage); + this.restartDetectingLoop(); + } + } + //Запуск обработки очереди печати + async startProcessing() { + await this.logger.info("Запуск обработчика очереди исходящих сообщений..."); + this.bWorking = true; + this.outDetectingLoop(); + await this.logger.info("Обработчик очереди исходящих сообщений запущен"); + } + //Остановка обработки очереди печати + async stopProcessing() { + await this.logger.info("Останов обработчика очереди исходящих сообщений..."); + this.bWorking = false; + await this.logger.info("Обработчик очереди исходящих сообщений остановлен"); + } +} + +//----------------- +// Интерфейс модуля +//----------------- + +exports.SEVT_OUT_QUEUE_NEW = SEVT_OUT_QUEUE_NEW; +exports.OutQueue = OutQueue; diff --git a/index.js b/index.js index 776a26b..ac4687a 100644 --- a/index.js +++ b/index.js @@ -2,3 +2,91 @@ Сервис интеграции ПП Парус 8 с WEB API Точка входа в сервер приложений */ + +//---------------------- +// Подключение библиотек +//---------------------- + +require("module-alias/register"); +const cfg = require("./config.js"); +const lg = require("./core/logger.js"); +const db = require("./core/db_connector.js"); +const oq = require("./core/out_queue.js"); + +//-------------------------- +// Глобальные идентификаторы +//-------------------------- + +let dbConn = new db.DBConnector(cfg.dbConnect); //Взаимодействие с БД +let logger = new lg.Logger(); //Протоколирование работы +let outQ = new oq.OutQueue(cfg.outgoing, dbConn, logger); //Отслеживание очереди исходящих + +//---------------------------------------- +// Управление процессом сервера приложений +//---------------------------------------- + +//При подключении к БД +const onDBConnected = async connection => { + logger.setDBConnector(dbConn); + await logger.info("Сервер приложений подключен к БД"); +}; + +//При отключении от БД +const onDBDisconnected = async () => { + logger.removeDBConnector(); + await logger.info("Сервер приложений отключен от БД"); +}; + +//Запуск сервера +const run = async () => { + await logger.info("Запуск сервера приложений..."); + dbConn.on(db.SEVT_DB_CONNECTOR_CONNECTED, onDBConnected); + dbConn.on(db.SEVT_DB_CONNECTOR_DISCONNECTED, onDBDisconnected); + await logger.info("Подключение сервера приложений к БД..."); + try { + await dbConn.connect(); + } catch (e) { + await logger.error("Ошибка подключения к БД: " + e.sCODE + ": " + e.sMessage); + stop(); + return; + } + await outQ.startProcessing(); + await logger.info("Сервер приложений запущен"); +}; + +//Останов сервера +const stop = async () => { + await logger.warn("Останов сервера приложений..."); + outQ.stopProcessing(); + if (dbConn.bConnected) { + await logger.warn("Отключение сервера приложений от БД..."); + try { + await dbConn.disconnect(); + process.exit(0); + } catch (e) { + await logger.error("Ошибка отключения от БД: " + e.sCODE + ": " + e.sMessage); + process.exit(1); + } + } else { + process.exit(0); + } +}; + +//Обработка события "выход" жизненного цикла процесса +process.on("exit", code => { + //Сообщим о завершении процесса + logger.warn("Сервер приложений остановлен (код: " + code + ") "); +}); + +//Перехват CTRL + C (останова процесса) +process.on("SIGINT", () => { + //Инициируем выход из процесса + stop(); +}); + +//------------ +// Точка входа +//------------ + +//Старутем +run(); diff --git a/test.js b/test.js index 4a6f11a..be524eb 100644 --- a/test.js +++ b/test.js @@ -25,9 +25,10 @@ const tests = async () => { try { //await l.warn("CONNECTING..."); await a.connect(); + for (i = 0; i <= 1000; i++) await l.info(i); //await l.info("CONNECTED!"); //await l.warn("READING SERVICES..."); - let srv = await a.getServices(); + //let srv = await a.getServices(); //await l.info(srv); console.log("1"); await l.warn("DISCONNECTING...");