diff --git a/config.js b/config.js index 501858c..c6a2740 100644 --- a/config.js +++ b/config.js @@ -12,7 +12,7 @@ let common = { //Версия сервера приложений sVersion: "8.5.6.1", //Релиз сервера приложений - sRelease: "2024.10.30", + sRelease: "2025.02.04", //Таймаут останова сервера (мс) nTerminateTimeout: 60000, //Контролировать версию Системы @@ -28,7 +28,7 @@ let dbConnect = { //Схема размещения используемых объектов БД sSchema: "PARUS", //Строка подключения к БД - sConnectString: "DEMOP_CITKSERV_WAN", + sConnectString: "", //Наименование сервера приложений в сессии БД sSessionAppName: "PARUS$ExchangeServer", //Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД) @@ -40,9 +40,9 @@ let outGoing = { //Проверять SSL-сертификаты адресов отправки сообщений (самоподписанные сертификаты будут отвергнуты) bValidateSSL: true, //Количество одновременно обрабатываемых исходящих сообщений - nMaxWorkers: 3, + nMaxWorkers: 1, //Интервал проверки наличия исходящих сообщений (мс) - nCheckTimeout: 1000, + nCheckTimeout: 500, //Минимальный размер пула подключений к БД для обработчика исходящих сообщений nPoolMin: 4, //Максимальный размер пула подключений к БД для обработчика исходящих сообщений @@ -96,7 +96,7 @@ const kafka = [ ssl: { //Запрещать использование самоподписанных сертификатов (true - запретить, false - разрешить) bRejectUnauthorized: true, - //Путь к центру сертификации + //Путь к корневому сертификату с информацией об удостоверяющем центре sPathCa: "", //Путь к закрытому ключу sPathKey: "", @@ -125,19 +125,19 @@ const mqtt = [ //Параметры отправки E-Mail уведомлений let mail = { //Адреc сервера SMTP - sHost: "smtp.mail.ru", + sHost: "", //Порт сервера SMTP nPort: 465, //Использовать безопасное соединение SMTP (true - использование TLS/SSL, false - использование только в случае наличия STARTTLS) bSecure: true, //Имя пользователя SMTP-сервера - sUser: "appserver@citk-parus.ru", + sUser: "", //Пароль пользователя SMTP-сервера sPass: "", //Запрещать использование самоподписанных сертификатов (true - запретить, false - разрешить) bRejectUnauthorized: true, //Наименование отправителя для исходящих сообщений - sFrom: "'Сервис интеграции с WEB-API' " + sFrom: "" }; //----------------- diff --git a/config_default.js b/config_default.js deleted file mode 100644 index f6d36cc..0000000 --- a/config_default.js +++ /dev/null @@ -1,155 +0,0 @@ -/* - Сервис интеграции ПП Парус 8 с WEB API - Конфигурация сервера приложений -*/ - -//------------ -// Тело модуля -//------------ - -//Общие параметры -let common = { - //Версия сервера приложений - sVersion: "8.5.6.1", - //Релиз сервера приложений - sRelease: "2024.10.30", - //Таймаут останова сервера (мс) - nTerminateTimeout: 60000, - //Контролировать версию Системы - bControlSystemVersion: true -}; - -//Параметры подключения к БД -let dbConnect = { - //Пользователь БД - sUser: "exs", - //Пароль пользователя БД - sPassword: "exs", - //Схема размещения используемых объектов БД - sSchema: "PARUS", - //Строка подключения к БД - sConnectString: "", - //Наименование сервера приложений в сессии БД - sSessionAppName: "PARUS$ExchangeServer", - //Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД) - sConnectorModule: "parus_oracle_db.js" -}; - -//Параметры обработки очереди исходящих сообщений -let outGoing = { - //Проверять SSL-сертификаты адресов отправки сообщений (самоподписанные сертификаты будут отвергнуты) - bValidateSSL: true, - //Количество одновременно обрабатываемых исходящих сообщений - nMaxWorkers: 1, - //Интервал проверки наличия исходящих сообщений (мс) - nCheckTimeout: 500, - //Минимальный размер пула подключений к БД для обработчика исходящих сообщений - nPoolMin: 4, - //Максимальный размер пула подключений к БД для обработчика исходящих сообщений - nPoolMax: 4, - //Шаг инкремента подключений к БД в пуле обработчика исходящих сообщений - nPoolIncrement: 0, - //Глобальный адрес прокси-сервера - sProxy: null -}; - -//Параметры обработки очереди входящих сообщений -let inComing = { - //Порт сервера входящих сообщений - nPort: 8080, - //IP-адрес сервера приложений (0.0.0.0 - все доступные) - sHost: "0.0.0.0", - //Максимальный размер входящего сообщения (мб) - nMsgMaxSize: 10, - //Каталог размещения статических ресурсов - sStaticDir: "static", - //Минимальный размер пула подключений к БД для обработчика входящих сообщений - nPoolMin: 10, - //Максимальный размер пула подключений к БД для обработчика входящих сообщений - nPoolMax: 10, - //Шаг инкремента подключений к БД в пуле обработчика входящих сообщений - nPoolIncrement: 0 -}; - -//Параметры подключения к Kafka -const kafka = [ - { - //Мнемокод сервиса обмена (пусто - использовать по умолчанию) - sService: "", - //ID клиента-отправителя - sClientIdSender: "Parus", - //ID клиента-получателя - sClientIdRecipient: "Parus", - //Группа получателя - sGroupId: "Parus", - //Время ожидания успешного подключения (мс) - nConnectionTimeout: 5000, - //Необходимость попытки переподключения при потере соединения - bRestartOnFailure: true, - //Время максимального ожидания между попытками переподключения (мс) - nMaxRetryTime: 20000, - //Время ожидания между попытками переподключения (мс) - nInitialRetryTime: 10000, - //Использовать аутентификацию по SSL-сертификату - bAuthSSL: false, - //Параметры аутентификации по SSL-сертификату - ssl: { - //Запрещать использование самоподписанных сертификатов (true - запретить, false - разрешить) - bRejectUnauthorized: true, - //Путь к центру сертификации - sPathCa: "", - //Путь к закрытому ключу - sPathKey: "", - //Путь к сертификату - sPathCert: "" - } - } -]; - -//Параметры подключения к MQTT -const mqtt = [ - { - //Мнемокод сервиса обмена (пусто - использовать по умолчанию) - sService: "", - //ID клиента-отправителя - sClientIdSender: "Parus", - //ID клиента-получателя (если равен sClientIdSender, то отправленные сообщения будут игнорироваться) - sClientIdRecipient: "ParusRecipient", - //Время ожидания успешного подключения (мс) - nConnectTimeout: 5000, - //Время ожидания между попытками переподключения (мс) - nReconnectPeriod: 10000 - } -]; - -//Параметры отправки E-Mail уведомлений -let mail = { - //Адреc сервера SMTP - sHost: "", - //Порт сервера SMTP - nPort: 465, - //Использовать безопасное соединение SMTP (true - использование TLS/SSL, false - использование только в случае наличия STARTTLS) - bSecure: true, - //Имя пользователя SMTP-сервера - sUser: "", - //Пароль пользователя SMTP-сервера - sPass: "", - //Запрещать использование самоподписанных сертификатов (true - запретить, false - разрешить) - bRejectUnauthorized: true, - //Наименование отправителя для исходящих сообщений - sFrom: "" -}; - -//----------------- -// Интерфейс модуля -//----------------- - -module.exports = { - common, - dbConnect, - outGoing, - inComing, - kafka, - mqtt, - mail -}; diff --git a/core/db_connector.js b/core/db_connector.js index b41596c..0f1e444 100644 --- a/core/db_connector.js +++ b/core/db_connector.js @@ -19,11 +19,7 @@ const objServiceFunctionsSchema = require("../models/obj_service_functions"); // const objQueueSchema = require("../models/obj_queue"); //Схема валидации сообщения очереди обмена const objQueuesSchema = require("../models/obj_queues"); //Схема валидации списка сообщений очереди обмена const objLogSchema = require("../models/obj_log"); //Схема валидации записи журнала -const { - SERR_MODULES_BAD_INTERFACE, - SERR_OBJECT_BAD_INTERFACE, - SERR_MODULES_NO_MODULE_SPECIFIED -} = require("./constants"); //Глобальные константы +const { SERR_MODULES_BAD_INTERFACE, SERR_OBJECT_BAD_INTERFACE, SERR_MODULES_NO_MODULE_SPECIFIED } = require("./constants"); //Глобальные константы //---------- // Константы @@ -49,11 +45,7 @@ class DBConnector extends EventEmitter { //создадим экземпляр родительского класса super(); //Проверяем структуру переданного объекта для подключения - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.DBConnector, - "Параметры конструктора класса DBConnector" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.DBConnector, "Параметры конструктора класса DBConnector"); //Если структура объекта в норме if (!sCheckResult) { //Проверяем наличие модуля для работы с БД в настройках подключения @@ -82,15 +74,25 @@ class DBConnector extends EventEmitter { this.connection = null; this.bConnected = false; } else { - throw new ServerError( - SERR_MODULES_NO_MODULE_SPECIFIED, - "Не указано имя подключаемого модуля-коннектора!" - ); + throw new ServerError(SERR_MODULES_NO_MODULE_SPECIFIED, "Не указано имя подключаемого модуля-коннектора!"); } } else { throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult); } } + //Исполнение хранимого объекта БД + async executeStored(prms) { + //Работаем только при наличии подключения + if (this.bConnected) { + return await this.connector.executeStored({ + connection: this.connection, + sName: prms.sName, + inPrms: prms.inPrms, + outPrms: prms.outPrms, + isFunction: prms.isFunction + }); + } + } //Подключиться к БД async connect() { //Подключаемся только если ещё не подключены @@ -175,11 +177,7 @@ class DBConnector extends EventEmitter { //Работаем только при наличии подключения if (this.bConnected) { //Проверяем структуру переданного объекта с параметрами для считывания функций сервиса - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.getServiceFunctions, - "Параметры функции считывания функций сервиса" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.getServiceFunctions, "Параметры функции считывания функций сервиса"); //Если структура объекта в норме if (!sCheckResult) { try { @@ -189,11 +187,7 @@ class DBConnector extends EventEmitter { //И выполним считывание функций сервиса let res = await this.connector.getServiceFunctions(getServiceFunctionsData); //Валидируем полученный ответ - sCheckResult = validateObject( - { functions: res }, - objServiceFunctionsSchema.ServiceFunctions, - "Список функций сервиса" - ); + sCheckResult = validateObject({ functions: res }, objServiceFunctionsSchema.ServiceFunctions, "Список функций сервиса"); if (sCheckResult) throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult); //Успешно - отдаём список функций сервиса return res; @@ -212,11 +206,7 @@ class DBConnector extends EventEmitter { //Работаем только при наличии подключения if (this.bConnected) { //Проверяем структуру переданного объекта с параметрами для получения контекста сервиса - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.getServiceContext, - "Параметры функции считывания контекста сервиса" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.getServiceContext, "Параметры функции считывания контекста сервиса"); //Если структура объекта в норме if (!sCheckResult) { try { @@ -245,11 +235,7 @@ class DBConnector extends EventEmitter { //Работаем только при наличии подключения if (this.bConnected) { //Проверяем структуру переданного объекта с параметрами для установки контекста сервиса - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.setServiceContext, - "Параметры функции установки контекста сервиса" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.setServiceContext, "Параметры функции установки контекста сервиса"); //Если структура объекта в норме if (!sCheckResult) { try { @@ -275,11 +261,7 @@ class DBConnector extends EventEmitter { //Работаем только при наличии подключения if (this.bConnected) { //Проверяем структуру переданного объекта с параметрами для очистки контекста сервиса - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.clearServiceContext, - "Параметры функции очистки контекста сервиса" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.clearServiceContext, "Параметры функции очистки контекста сервиса"); //Если структура объекта в норме if (!sCheckResult) { try { @@ -305,11 +287,7 @@ class DBConnector extends EventEmitter { //Работаем только при наличии подключения if (this.bConnected) { //Проверяем структуру переданного объекта с параметрами для проверки аутентифицированности сервиса - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.isServiceAuth, - "Параметры функции проверки аутентифицированности сервиса" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.isServiceAuth, "Параметры функции проверки аутентифицированности сервиса"); //Если структура объекта в норме if (!sCheckResult) { try { @@ -320,10 +298,7 @@ class DBConnector extends EventEmitter { let res = await this.connector.isServiceAuth(isServiceAuthData); //Валидируем результат if (![objServiceSchema.NIS_AUTH_NO, objServiceSchema.NIS_AUTH_YES].includes(res)) - throw new ServerError( - SERR_OBJECT_BAD_INTERFACE, - "Неожиданный ответ функции проверки аутентифицированности сервиса" - ); + throw new ServerError(SERR_OBJECT_BAD_INTERFACE, "Неожиданный ответ функции проверки аутентифицированности сервиса"); //Успешно - возвращаем то, что вернула функция проверки return res; } catch (e) { @@ -385,11 +360,7 @@ class DBConnector extends EventEmitter { //И выполним получение информации о просроченных сообщениях let res = await this.connector.getServiceExpiredQueueInfo(getServiceExpiredQueueInfoData); //Валидируем полученный ответ - sCheckResult = validateObject( - res, - objServiceSchema.ServiceExpiredQueueInfo, - "Сведения о просроченных сообщениях обмена сервиса" - ); + sCheckResult = validateObject(res, objServiceSchema.ServiceExpiredQueueInfo, "Сведения о просроченных сообщениях обмена сервиса"); if (sCheckResult) throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult); //Успешно - отдаём полученные сведения о просроченных сообщениях return res; @@ -408,11 +379,7 @@ class DBConnector extends EventEmitter { //Работаем только при наличии подключения if (this.bConnected) { //Проверяем структуру переданного объекта с параметрами для записи в журнал - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.putLog, - "Параметры функции записи в журнал работы" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.putLog, "Параметры функции записи в журнал работы"); //Если структура объекта в норме if (!sCheckResult) { try { @@ -488,11 +455,7 @@ class DBConnector extends EventEmitter { async getQueue(prms) { if (this.bConnected) { //Проверяем структуру переданных параметров - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.getQueue, - "Параметры функции считывания записи очереди обмена" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.getQueue, "Параметры функции считывания записи очереди обмена"); //Если структура объекта в норме if (!sCheckResult) { //Подготовим параметры @@ -521,11 +484,7 @@ class DBConnector extends EventEmitter { async putQueue(prms) { if (this.bConnected) { //Проверяем структуру переданных параметров - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.putQueue, - "Параметры функции добавления позиции очереди" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.putQueue, "Параметры функции добавления позиции очереди"); //Если структура объекта в норме if (!sCheckResult) { //Подготовим параметры @@ -555,11 +514,7 @@ class DBConnector extends EventEmitter { async getOutgoing(prms) { if (this.bConnected) { //Проверяем структуру переданного объекта с параметрами считывания очереди - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.getOutgoing, - "Параметры функции считывания очереди" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.getOutgoing, "Параметры функции считывания очереди"); //Если структура объекта в норме if (!sCheckResult) { try { @@ -569,11 +524,7 @@ class DBConnector extends EventEmitter { //Выполняем считывание из БД let res = await this.connector.getQueueOutgoing(getQueueOutgoingData); //Валидируем полученный ответ - sCheckResult = validateObject( - { queues: res }, - objQueuesSchema.Queues, - "Список сообщений очереди обмена" - ); + sCheckResult = validateObject({ queues: res }, objQueuesSchema.Queues, "Список сообщений очереди обмена"); if (sCheckResult) throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult); //Вернём сообщения очереди обмена return res; @@ -591,11 +542,7 @@ class DBConnector extends EventEmitter { async setQueueState(prms) { if (this.bConnected) { //Проверяем структуру переданных параметров - let sCheckResult = validateObject( - prms, - prmsDBConnectorSchema.setQueueState, - "Параметры функции установки состояния позиции очереди" - ); + let sCheckResult = validateObject(prms, prmsDBConnectorSchema.setQueueState, "Параметры функции установки состояния позиции очереди"); //Если структура объекта в норме if (!sCheckResult) { //Подготовим параметры @@ -738,11 +685,7 @@ class DBConnector extends EventEmitter { try { let res = await this.connector.getQueueResp(getQueueRespData); //Валидируем полученный ответ - sCheckResult = validateObject( - res, - objQueueSchema.QueueResp, - "Данные ответа сообщения очереди обмена" - ); + sCheckResult = validateObject(res, objQueueSchema.QueueResp, "Данные ответа сообщения очереди обмена"); if (sCheckResult) throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult); //Вернём данные ответа на сообщение return res; @@ -866,11 +809,7 @@ class DBConnector extends EventEmitter { //И выполним обработчик со стороны БД let res = await this.connector.execQueuePrc(execQueuePrcData); //Валидируем полученный ответ - sCheckResult = validateObject( - res, - objQueueSchema.QueuePrcResult, - "Результат обработки очереди обмена" - ); + sCheckResult = validateObject(res, objQueueSchema.QueuePrcResult, "Результат обработки очереди обмена"); if (sCheckResult) throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult); //Вернём результат обработки return res; diff --git a/models/intf_db_connector_module.js b/models/intf_db_connector_module.js index be39898..06d60d8 100644 --- a/models/intf_db_connector_module.js +++ b/models/intf_db_connector_module.js @@ -24,13 +24,63 @@ const validateAsyncFunctionType = val => { //Схема валидации подключаемого модуля взаимодействия с БД exports.dbConnectorModule = new Schema({ + //Тип данных - строка БД + DT_VARCHAR: { + required: true, + message: { + required: path => `Не реализована константа для типа данных "Строка" БД (${path})` + } + }, + //Тип данных - число БД + DT_NUMBER: { + required: true, + message: { + required: path => `Не реализована константа для типа данных "Число" БД (${path})` + } + }, + //Тип данных - дата БД + DT_DATE: { + required: true, + message: { + required: path => `Не реализована константа для типа данных "Дата" БД (${path})` + } + }, + //Тип данных - текстовые данные БД + DT_CLOB: { + required: true, + message: { + required: path => `Не реализована константа для типа данных "Текстовые данные" БД (${path})` + } + }, + //Тип данных - двоичные данные БД + DT_BLOB: { + required: true, + message: { + required: path => `Не реализована константа для типа данных "Двоичные данные" БД (${path})` + } + }, + //Тип данных - курсор БД + DT_CURSOR: { + required: true, + message: { + required: path => `Не реализована константа для типа данных "Курсор" БД (${path})` + } + }, + //Исполнение хранимого объекта БД + executeStored: { + use: { validateAsyncFunctionType }, + required: true, + message: { + validateAsyncFunctionType: path => `Функция исполнения хранимого объекта БД (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + required: path => `Не реализована функция исполнения хранимого объекта БД (${path})` + } + }, //Подключение к БД connect: { use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция подключения к БД (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция подключения к БД (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция подключения к БД (${path})` } }, @@ -39,8 +89,7 @@ exports.dbConnectorModule = new Schema({ use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция отключения от БД (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция отключения от БД (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция отключения от БД (${path})` } }, @@ -49,8 +98,7 @@ exports.dbConnectorModule = new Schema({ use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция получения списка сервисов (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция получения списка сервисов (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция получения списка сервисов (${path})` } }, @@ -59,8 +107,7 @@ exports.dbConnectorModule = new Schema({ use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция получения списка функций сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция получения списка функций сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция получения списка функций сервиса (${path})` } }, @@ -69,8 +116,7 @@ exports.dbConnectorModule = new Schema({ use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция получения контекста сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция получения контекста сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция получения контекста сервиса (${path})` } }, @@ -79,8 +125,7 @@ exports.dbConnectorModule = new Schema({ use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция установки контекста сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция установки контекста сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция установки контекста сервиса (${path})` } }, @@ -89,8 +134,7 @@ exports.dbConnectorModule = new Schema({ use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция очистки контекста сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция очистки контекста сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция очистки контекста сервиса (${path})` } }, @@ -121,8 +165,7 @@ exports.dbConnectorModule = new Schema({ message: { validateAsyncFunctionType: path => `Функция получения информации о просроченных сообщениях обмена сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, - required: path => - `Не реализована функция получения информации о просроченных сообщениях обмена сервиса (${path})` + required: path => `Не реализована функция получения информации о просроченных сообщениях обмена сервиса (${path})` } }, //Протоколирование работы сервиса @@ -130,8 +173,7 @@ exports.dbConnectorModule = new Schema({ use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция протоколирования работы сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция протоколирования работы сервиса (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция протоколирования работы сервиса (${path})` } }, @@ -140,8 +182,7 @@ exports.dbConnectorModule = new Schema({ use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция считывания записи очереди обмена (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция считывания записи очереди обмена (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция считывания записи очереди обмена (${path})` } }, @@ -150,8 +191,7 @@ exports.dbConnectorModule = new Schema({ use: { validateAsyncFunctionType }, required: true, message: { - validateAsyncFunctionType: path => - `Функция добавления сообщения очереди (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, + validateAsyncFunctionType: path => `Функция добавления сообщения очереди (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, required: path => `Не реализована функция добавления сообщения очереди (${path})` } }, @@ -232,8 +272,7 @@ exports.dbConnectorModule = new Schema({ message: { validateAsyncFunctionType: path => `Функция установки параметров результата обработки сообщения очереди (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, - required: path => - `Не реализована функция установки параметров результата обработки сообщения очереди (${path})` + required: path => `Не реализована функция установки параметров результата обработки сообщения очереди (${path})` } }, //Исполнение обработчика со стороны БД для сообщения очереди @@ -243,8 +282,7 @@ exports.dbConnectorModule = new Schema({ message: { validateAsyncFunctionType: path => `Функция исполнения обработчика со стороны БД для сообщения очереди (${path}) имеет неверный формат (ожидалось - AsyncFunction)`, - required: path => - `Не реализована функция исполнения обработчика со стороны БД для сообщения очереди (${path})` + required: path => `Не реализована функция исполнения обработчика со стороны БД для сообщения очереди (${path})` } } }); diff --git a/modules/diadoc.js b/modules/diadoc.js index 505c34d..701d56e 100644 --- a/modules/diadoc.js +++ b/modules/diadoc.js @@ -33,7 +33,7 @@ const tag = [ //------------ //формирования адреса запроса для получения данных о текущей организации пользователя -const buildOrganizationURL = srvRoot => { +const buildMyOrganizationURL = srvRoot => { return `${srvRoot.replace(/\/+$/, "")}/GetMyOrganizations`; }; @@ -42,6 +42,11 @@ const buildOrganizationBoxIdURL = srvRoot => { return `${srvRoot.replace(/\/+$/, "")}/GetBox`; }; +//формирования адреса запроса для получения данных о организации по ИНН/КПП +const buildOrganizationURL = srvRoot => { + return `${srvRoot.replace(/\/+$/, "")}/GetOrganization`; +}; + //формирования адреса запроса для получения данных о организации по ИНН/КПП const buildOrganizationsByInnKppURL = srvRoot => { return `${srvRoot.replace(/\/+$/, "")}/GetOrganizationsByInnKpp`; @@ -131,10 +136,11 @@ const buildHeaders = (sAPIClientId, sToken = null) => ({ const GetOrganizations = Organizations => { //Параметры отбора let isRoaming = false; + let isActive = true; //Итоговая выборка let Organization = { Organizations: [] }; - //Найдем организацию не в роуминге - Organization.Organizations[0] = Organizations.Organizations.find(Org => Org.IsRoaming === isRoaming); + //Найдем активную организацию не в роуминге + Organization.Organizations[0] = Organizations.Organizations.find(Org => (Org.IsRoaming === isRoaming) && (Org.IsActive === isActive)); //Если не удалось получить организацию не в роуминге if (!Organization.Organizations[0]) { //Если нет организации не в роуминге и найдено более одной организации @@ -142,7 +148,7 @@ const GetOrganizations = Organizations => { throw Error(`Найдено несколько организаций в роуминге.`); } else { //Вернем единственную найденую организацию - return Organizations; + return Organizations[0]; } } else { //Вернем найденую организацию @@ -150,6 +156,83 @@ const GetOrganizations = Organizations => { } }; +//Получение организации по ИНН/КПП контрагента +const GetOrganization = async (sSrvRoot, headers, nInn, nKpp) => { + //Параметры запроса + let rqpOptions; + let serverResp; + //Формируем запрос для получения BoxId + rqpOptions = { + uri: buildOrganizationURL(sSrvRoot), + qs: { + inn: nInn, + kpp: nKpp + }, + headers: headers, + json: true + }; + //Выполним запрос + serverResp = { Organizations: [await rqp(rqpOptions)] }; + return serverResp; +}; + +//Получение ящика организации по ИНН/КПП контрагента +const GetOrganizationBoxId = async (sSrvRoot, headers, nInn, nKpp) => { + //Параметры запроса + let rqpOptions; + let serverResp; + let Organization = {}; + //Формируем запрос для получения BoxId по ИНН/КПП + rqpOptions = { + uri: buildOrganizationsByInnKppURL(sSrvRoot), + qs: { + inn: nInn, + kpp: nKpp + }, + headers: headers, + json: true + }; + try { + //Выполним запрос + serverResp = await rqp(rqpOptions); + try { + //Получим организацию не в роуминге (или единственную организацию в роуминге) + serverResp = GetOrganizations(serverResp); + if (!serverResp?.Organizations[0]) { + throw Error(`Не удалось получить ящик получателя для контрагента с ИНН: ${nInn} и КПП: ${nKpp}`); + } + } catch (e) { + //Получим головную организацию по ИНН/КПП + serverResp = await GetOrganization(sSrvRoot, headers, nInn, nKpp); + }; + //Проверим соответствие КПП организации + if ((serverResp?.Organizations[0]?.Kpp != nKpp) && (serverResp?.Organizations[0])) { + //Если КПП не соответстует заданному - проверим, что в полученной организации есть департамент с заданным КПП + for (let i in serverResp.Organizations[0].Departments) { + //Если найден подходящий департамент - запомним идентификатор и выходим из цикла + if (serverResp.Organizations[0].Departments[i]?.Kpp == nKpp) { + //Сохраняем полученный ответ + Organization.DepartmentId = serverResp.Organizations[0].Departments[i].DepartmentId; + break; + }; + }; + }; + //Не удалось получить ящик получателя или полученая организация не соответствует заданному ИНН + if ((!serverResp?.Organizations[0]?.Boxes[0]?.BoxId) || (serverResp?.Organizations[0]?.Inn != nInn)) { + throw new Error(`Не удалось получить ящик получателя для контрагента с ИНН: ${nInn} и КПП: ${nKpp}`); + } + //Не удалось получить департаментом с соответствующим КПП + if ((serverResp?.Organizations[0]?.Kpp != nKpp) && (!Organization?.DepartmentId)) { + throw new Error(`Не удалось получить ящик получателя для контрагента с ИНН: ${nInn} и КПП: ${nKpp}, у головной организации отсутствует подразделение с КПП: ${nKpp}`); + } + //Сохраняем полученный ответ + Organization.BoxId = serverResp.Organizations[0].Boxes[0].BoxId; + return Organization; + } catch (e) { + throw Error(`Ошибка при получении ящика получателя: ${e.message}`); + }; +}; + //Обработчик "До" подключения к сервису const beforeConnect = async prms => { //Подготовим параметры аутентификации @@ -209,11 +292,13 @@ const beforeMessagePost = async prms => { let obj = await toJSON(prms.queue.blMsg.toString()); //Формируем запрос для получения FromBoxId let rqpOptions = { - uri: buildOrganizationURL(prms.service.sSrvRoot), + uri: buildMyOrganizationURL(prms.service.sSrvRoot), headers: buildHeaders(sAPIClientId, sToken), json: true }; + //Переменные для запросов let serverResp; + let Organization; try { //Выполним запрос serverResp = await rqp(rqpOptions); @@ -233,33 +318,13 @@ const beforeMessagePost = async prms => { } catch (e) { throw Error(`Ошибка при получении ящика текущей организации: ${e.message}`); } - //Очистим предыдущий запрос - rqpOptions = null; - serverResp = null; - //Формируем запрос для получения ToBoxId - rqpOptions = { - uri: buildOrganizationsByInnKppURL(prms.service.sSrvRoot), - qs: { - inn: prms.options.inn_cs, - kpp: prms.options.kpp_cs - }, - headers: buildHeaders(sAPIClientId, sToken), - json: true + //Получим ящик получателя + Organization = await GetOrganizationBoxId(prms.service.sSrvRoot, buildHeaders(sAPIClientId, sToken), prms.options.inn_cs, prms.options.kpp_cs); + obj.ToBoxId = Organization.BoxId; + //Если не заполнен идентификатор подразделения и при получении ящика удалось его подобрать + if ((!obj.ToDepartmentId) && (Organization.DepartmentId)) { + obj.ToDepartmentId = Organization.DepartmentId; }; - try { - //Выполним запрос - serverResp = await rqp(rqpOptions); - //Получим организацию не в роуминге (или единственную организацию в роуминге) - serverResp = GetOrganizations(serverResp); - //Не удалось получить ящик получателя - if (!serverResp.Organizations[0].Boxes[0].BoxId) { - throw new Error(`Не удалось получить ящик получателя для контрагента с ИНН: ${prms.options.inn_cs} и КПП: ${prms.options.kpp_cs}`); - } - //Сохраняем полученный ответ - obj.ToBoxId = serverResp.Organizations[0].Boxes[0].BoxId; - } catch (e) { - throw Error(`Ошибка при получении ящика получателя: ${e.message}`); - } //Если пришел ответ if (prms.queue.blResp && serverResp.statusCode == 200) { //Вернем загруженный документ @@ -383,7 +448,7 @@ const beforeEvent = async prms => { if (!sToken) return { bUnAuth: true }; //Формируем запрос для получения BoxId let rqpOptions = { - uri: buildOrganizationURL(prms.service.sSrvRoot), + uri: buildMyOrganizationURL(prms.service.sSrvRoot), headers: buildHeaders(sAPIClientId, sToken), json: true }; @@ -482,10 +547,10 @@ const afterEvent = async prms => { //Получим список уникальных ящиков for (let i in resp.Events) { if (resp.Events[i]?.Message) { - if (!boxIds.boxIds.find(box => box.boxId === resp.Events[i]?.Message.FromBoxId)) { + if ((!boxIds.boxIds.find(box => box.boxId === resp.Events[i]?.Message.FromBoxId)) && (resp.Events[i]?.Message.FromBoxId)) { boxIds.boxIds.push({ boxId: resp.Events[i]?.Message.FromBoxId }); } - if (!boxIds.boxIds.find(box => box.boxId === resp.Events[i]?.Message.ToBoxId)) { + if ((!boxIds.boxIds.find(box => box.boxId === resp.Events[i]?.Message.ToBoxId)) && (resp.Events[i]?.Message.ToBoxId)) { boxIds.boxIds.push({ boxId: resp.Events[i]?.Message.ToBoxId }); } } @@ -756,8 +821,20 @@ const afterDepartmentIdGet = async prms => { //Действие выполнено успешно if (prms.optionsResp.statusCode == 200) { try { - //Получим организацию не в роуминге (или единственную организацию в роуминге) - Organization = GetOrganizations(JSON.parse(prms.queue.blResp.toString())); + try { + //Получим организацию не в роуминге (или единственную организацию в роуминге) + Organization = GetOrganizations(JSON.parse(prms.queue.blResp.toString())); + if (!Organization) { + throw Error(`Не удалось получить ящик для контрагента с ИНН: ${prms.options.nINN} и КПП: ${prms.options.nKPP}`); + } + } catch (e) { + //Получим ключ разработчика + let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); + //Считаем токен доступа из контекста сервиса + let sToken = prms.service.sCtx; + //Получим головную организацию по ИНН/КПП + Organization = await GetOrganization(prms.service.sSrvRoot, buildHeaders(sAPIClientId, sToken), prms.options.nINN, prms.options.nKPP); + }; //Преобразуем JSON ответ сервиса "ДИАДОК" в XML, понятный "Парус 8" resu = toXML({ root: Organization }); } catch (e) { @@ -777,6 +854,60 @@ const afterDepartmentIdGet = async prms => { }; }; +//Обработчик "До" отправки запроса на получение списка документов в сообщении к сервису "ДИАДОК" +const beforeDocumentsByMessageIdGet = async prms => { + //Получим ключ разработчика + let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); + //Проверим ключ разработчика + checkAPIClientId(sAPIClientId); + //Формируем запрос + try { + //Считаем токен доступа из контекста сервиса + let sToken = null; + if (prms.service.sCtx) { + sToken = prms.service.sCtx; + } + //Если не достали из контекста токен доступа - значит нет аутентификации на сервере + if (!sToken) return { bUnAuth: true }; + //Собираем и отдаём общий результат работы + return { + options: { + headers: buildHeaders(sAPIClientId, sToken), + simple: false + } + }; + } catch (e) { + throw Error(e); + } +}; + +//Обработчик "После" отправки запроса на получение списка документов в сообщении к сервису "ДИАДОК" +const afterDocumentsByMessageIdGet = async prms => { + let resu = null; + //Действие выполнено успешно + if (prms.optionsResp.statusCode == 200) { + try { + //Разберем ответ сервера + resp = JSON.parse(prms.queue.blResp.toString()); + //Преобразуем JSON ответ сервиса "ДИАДОК" в XML, понятный "Парус 8" + resu = toXML({ root: resp }); + } catch (e) { + throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК". Ошибка интерпретации: ${e.message}`); + } + } else { + //Если пришел текст ошибки + if (prms.queue.blResp) { + throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК": ${prms.queue.blResp.toString()}`); + } else { + throw new Error('Сервер ЭДО "ДИАДОК" не вернул ответ'); + } + } + //Возврат результата + return { + blResp: Buffer.from(resu) + }; +}; + //----------------- // Интерфейс модуля //----------------- @@ -794,3 +925,5 @@ exports.afterDocLoad = afterDocLoad; exports.beforeDocDelete = beforeDocDelete; exports.beforeDepartmentIdGet = beforeDepartmentIdGet; exports.afterDepartmentIdGet = afterDepartmentIdGet; +exports.beforeDocumentsByMessageIdGet = beforeDocumentsByMessageIdGet; +exports.afterDocumentsByMessageIdGet = afterDocumentsByMessageIdGet; diff --git a/modules/parus_oracle_db.js b/modules/parus_oracle_db.js index f032aa3..53b9c72 100644 --- a/modules/parus_oracle_db.js +++ b/modules/parus_oracle_db.js @@ -14,49 +14,100 @@ const oracledb = require("oracledb"); //Работа с СУБД Oracle //-------------------------- const NPOOL_DRAIN_TIME = 30; //Таймаут ожидания завершения подключений при отключении пула от БД (сек) +const DT_VARCHAR = oracledb.DB_TYPE_VARCHAR; //Тип данных "Строка" БД +const DT_NUMBER = oracledb.DB_TYPE_NUMBER; //Тип данных "Число" БД +const DT_DATE = oracledb.DB_TYPE_DATE; //Тип данных "Дата" БД +const DT_CLOB = oracledb.DB_TYPE_CLOB; //Тип данных "Текстовые данные" БД +const DT_BLOB = oracledb.DB_TYPE_BLOB; //Тип данных "Двоичные данные" БД +const DT_CURSOR = oracledb.CURSOR; //Тип данных "Курсор" БД //------------ // Тело модуля //------------ -//Чтение данных из курсора -const readCursorData = cursor => { - return new Promise((resolve, reject) => { - let queryStream = cursor.toQueryStream(); - let rows = []; - queryStream.on("data", row => { - rows.push(row); - }); - queryStream.on("error", err => { - queryStream.destroy(); - reject(new Error(err.message)); - }); - queryStream.on("close", () => { - queryStream.destroy(); - resolve(rows); - }); - }); +//Формирование имени хранимого объекта БД (с параметрами) +const makeStoredName = (sName, inPrms, outPrms, isFunction = false) => { + let prms = ""; + let resultVar = ""; + for (i in inPrms) prms += `${prms ? ", " : ""}${i} => :${i}`; + for (i in outPrms) { + if (isFunction) resultVar = `:${i} := `; + else prms += `${prms ? ", " : ""}${i} => :${i}`; + break; + } + return `${resultVar ? resultVar : ""}${sName.replace(/\$[0-9]{1,9}$/, "").replace("$", ".")}(${prms})`; }; -//Проверка допустимого количества воркеров -const checkWorkers = async prms => { +//Формирование параметров хранимого объекта БД +const makeStoredPrms = (inPrms, outPrms) => { + let prms = inPrms ? inPrms : {}; + for (i in outPrms) { + prms[i] = { + type: outPrms[i], + dir: oracledb.BIND_OUT + }; + break; + } + return prms; +}; + +//Исполнение хранимого объекта БД +const executeStored = async prms => { let pooledConnection; + let outResult = {}; try { pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute("BEGIN :LIC_CNT := PKG_EXS.UTL_LIC_CLNT_COUNT_GET(); END;", { - LIC_CNT: { dir: oracledb.BIND_OUT, type: oracledb.NUMBER } - }); - let nMaxLic = res.outBinds.LIC_CNT; - if (nMaxLic === 0) { - throw new Error(`Не определено количество лицензий для приложения "ExchangeServer".`); - } - if (prms.nMaxWorkers > nMaxLic - 1) { - throw new Error( - `Недопустимое значение параметра "Количество одновременно обрабатываемых исходящих сообщений" ("outGoing.nMaxWorkers") файла конфигурации сервиса приложений ("config.js"). Максимальное количество одновременно обрабатываемых исходящих сообщений - ${ - nMaxLic - 1 - }.` - ); + let outPrmName = ""; + let outPrmIsCursor = false; + for (i in prms.outPrms) { + outPrmName = i; + outPrmIsCursor = prms.outPrms[i] == DT_CURSOR; + break; } + let res = await pooledConnection.execute( + `begin ${makeStoredName(prms.sName, prms.inPrms, prms.outPrms, prms.isFunction)}; end;`, + makeStoredPrms(prms.inPrms, prms.outPrms), + { + ...(outPrmIsCursor ? { outFormat: oracledb.OBJECT } : {}), + ...{ autoCommit: true } + } + ); + if (res) + if (res.outBinds) { + const outBind = res.outBinds[outPrmName]; + if (outPrmIsCursor) { + const readCursorData = cursor => { + return new Promise((resolve, reject) => { + let queryStream = cursor.toQueryStream(); + let rows = []; + queryStream.on("data", row => { + rows.push(row); + }); + queryStream.on("error", err => { + queryStream.destroy(); + reject(new Error(err.message)); + }); + queryStream.on("close", () => { + queryStream.destroy(); + resolve(rows); + }); + }); + }; + let rows = await readCursorData(outBind); + let rowsRes = []; + await Promise.all( + rows.map(async row => { + let rowRes = {}; + for (i in row) { + let isLob = row[i] ? (row[i].type ? row[i].type == oracledb.BLOB || row[i].type == oracledb.CLOB : false) : false; + rowRes[i] = isLob ? await row[i].getData() : row[i]; + } + rowsRes.push(rowRes); + }) + ); + outResult[outPrmName] = rowsRes; + } else outResult[outPrmName] = outBind; + } } catch (e) { throw new Error(e.message); } finally { @@ -68,32 +119,45 @@ const checkWorkers = async prms => { } } } + if (outResult) return outResult; +}; + +//Проверка допустимого количества воркеров +const checkWorkers = async prms => { + let workersData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.UTL_LIC_CLNT_COUNT_GET", + outPrms: { + LIC_CNT: DT_NUMBER + }, + isFunction: true + }); + if (workersData.LIC_CNT === 0) { + throw new Error(`Не определено количество лицензий для приложения "ExchangeServer".`); + } + if (prms.nMaxWorkers > workersData.LIC_CNT - 1) { + throw new Error( + `Недопустимое значение параметра "Количество одновременно обрабатываемых исходящих сообщений" ("outGoing.nMaxWorkers") файла конфигурации сервиса приложений ("config.js"). Максимальное количество одновременно обрабатываемых исходящих сообщений - ${ + workersData.LIC_CNT - 1 + }.` + ); + } }; //Проверка соответствия релизов сервера приложений и системы const checkRelease = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute("BEGIN :DB_RELEASE := PKG_EXS.UTL_PRODUCT_RELEASE_GET(); END;", { - DB_RELEASE: { dir: oracledb.BIND_OUT, type: oracledb.DB_TYPE_VARCHAR } - }); - let sDB_RELEASE = res.outBinds.DB_RELEASE; - if (sDB_RELEASE !== prms.sRelease) { - throw new Error(`Версия сервера приложений (${prms.sRelease}) не соответствует версии системы (${sDB_RELEASE}).`); - } - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } + let releaseData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.UTL_PRODUCT_RELEASE_GET", + outPrms: { + DB_RELEASE: DT_VARCHAR + }, + isFunction: true + }); + if (releaseData.DB_RELEASE !== prms.sRelease) { + throw new Error(`Версия сервера приложений (${prms.sRelease}) не соответствует версии системы (${releaseData.DB_RELEASE}).`); } -} +}; //Подключение к БД const connect = async prms => { @@ -140,566 +204,294 @@ const disconnect = async prms => { //Получение списка сервисов const getServices = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.SERVICES_GET(RCSERVICES => :RCSERVICES); END;", - { RCSERVICES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, - { outFormat: oracledb.OBJECT } - ); - let rows = await readCursorData(res.outBinds.RCSERVICES); - return rows; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } + let servicesData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.SERVICES_GET", + outPrms: { + RCSERVICES: DT_CURSOR } - } + }); + return servicesData.RCSERVICES; }; //Получение списка функций сервиса const getServiceFunctions = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.SERVICEFNS_GET(NEXSSERVICE => :NEXSSERVICE, RCSERVICEFNS => :RCSERVICEFNS); END;", - { NEXSSERVICE: prms.nServiceId, RCSERVICEFNS: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, - { outFormat: oracledb.OBJECT } - ); - let rows = await readCursorData(res.outBinds.RCSERVICEFNS); - return rows; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } + let serviceFunctionsData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.SERVICEFNS_GET", + inPrms: { + NEXSSERVICE: prms.nServiceId + }, + outPrms: { + RCSERVICEFNS: DT_CURSOR } - } + }); + return serviceFunctionsData.RCSERVICEFNS; }; //Получение контекста сервиса const getServiceContext = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.SERVICE_CTX_GET(NFLAG_SMART => 0, NEXSSERVICE => :NEXSSERVICE, RCSERVICE_CTX => :RCSERVICE_CTX); END;", - { NEXSSERVICE: prms.nServiceId, RCSERVICE_CTX: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, - { outFormat: oracledb.OBJECT } - ); - let rows = await readCursorData(res.outBinds.RCSERVICE_CTX); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } + let serviceContextData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.SERVICE_CTX_GET", + inPrms: { + NFLAG_SMART: 0, + NEXSSERVICE: prms.nServiceId + }, + outPrms: { + RCSERVICE_CTX: DT_CURSOR } - } + }); + return serviceContextData.RCSERVICE_CTX[0]; }; //Установка контекста сервиса const setServiceContext = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - await pooledConnection.execute( - "BEGIN PKG_EXS.SERVICE_CTX_SET(NEXSSERVICE => :NEXSSERVICE, SCTX => :SCTX, DCTX_EXP => :DCTX_EXP); END;", - { NEXSSERVICE: prms.nServiceId, SCTX: prms.sCtx, DCTX_EXP: prms.dCtxExp }, - { autoCommit: true } - ); - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } + await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.SERVICE_CTX_SET", + inPrms: { + NEXSSERVICE: prms.nServiceId, + SCTX: prms.sCtx, + DCTX_EXP: prms.dCtxExp } - } + }); }; //Очистка контекста сервиса const clearServiceContext = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - await pooledConnection.execute( - "BEGIN PKG_EXS.SERVICE_CTX_CLEAR(NEXSSERVICE => :NEXSSERVICE); END;", - { NEXSSERVICE: prms.nServiceId }, - { autoCommit: true } - ); - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.SERVICE_CTX_CLEAR", + inPrms: { NEXSSERVICE: prms.nServiceId } + }); }; //Проверка атуентифицированности сервиса const isServiceAuth = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute("BEGIN :RET := PKG_EXS.SERVICE_IS_AUTH(NEXSSERVICE => :NEXSSERVICE); END;", { - NEXSSERVICE: prms.nServiceId, - RET: { dir: oracledb.BIND_OUT, type: oracledb.NUMBER } - }); - return res.outBinds.RET; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let serviceAuth = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.SERVICE_IS_AUTH", + inPrms: { NEXSSERVICE: prms.nServiceId }, + outPrms: { + RET: DT_NUMBER + }, + isFunction: true + }); + return serviceAuth.RET; }; //Постановка в очередь задания на аутентификацию сервиса const putServiceAuthInQueue = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - await pooledConnection.execute( - "BEGIN PKG_EXS.SERVICE_AUTH_PUT_INQUEUE_AT(NEXSSERVICE => :NEXSSERVICE, NFORCE => :NFORCE); END;", - { NEXSSERVICE: prms.nServiceId, NFORCE: prms.nForce }, - { autoCommit: true } - ); - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.SERVICE_AUTH_PUT_INQUEUE_AT", + inPrms: { NEXSSERVICE: prms.nServiceId, NFORCE: prms.nForce } + }); }; //Получение информации о просроченных сообщениях обмена сервиса const getServiceExpiredQueueInfo = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.SERVICE_QUEUE_EXPIRED_INFO_GET(NEXSSERVICE => :NEXSSERVICE, RCSERVICE_QUEUE_EXPIRED_INFO => :RCSERVICE_QUEUE_EXPIRED_INFO); END;", - { - NEXSSERVICE: prms.nServiceId, - RCSERVICE_QUEUE_EXPIRED_INFO: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT } - ); - let rows = await readCursorData(res.outBinds.RCSERVICE_QUEUE_EXPIRED_INFO); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } + let serviceExpiredQueueInfoData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.SERVICE_QUEUE_EXPIRED_INFO_GET", + inPrms: { + NEXSSERVICE: prms.nServiceId + }, + outPrms: { + RCSERVICE_QUEUE_EXPIRED_INFO: DT_CURSOR } - } + }); + return serviceExpiredQueueInfoData.RCSERVICE_QUEUE_EXPIRED_INFO[0]; }; //Запись в протокол работы const log = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.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 } - ); - let rows = await readCursorData(res.outBinds.RCLOG); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let logData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.LOG_PUT", + inPrms: { + NLOG_STATE: prms.nLogState, + SMSG: prms.sMsg, + NEXSSERVICE: prms.nServiceId, + NEXSSERVICEFN: prms.nServiceFnId, + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCLOG: DT_CURSOR } + }); + return logData.RCLOG[0]; }; //Считывание записи очереди обмена const getQueue = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_GET(NFLAG_SMART => 0, NEXSQUEUE => :NEXSQUEUE, RCQUEUE => :RCQUEUE); END;", - { - NEXSQUEUE: prms.nQueueId, - RCQUEUE: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true } - ); - let rows = await readCursorData(res.outBinds.RCQUEUE); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_GET", + inPrms: { + NFLAG_SMART: 0, + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueData.RCQUEUE[0]; }; //Помещение сообщения в очередь const putQueue = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_PUT(NEXSSERVICEFN => :NEXSSERVICEFN, BMSG => :BMSG, NEXSQUEUE => :NEXSQUEUE, NLNK_COMPANY => :NLNK_COMPANY, NLNK_DOCUMENT => :NLNK_DOCUMENT, SLNK_UNITCODE => :SLNK_UNITCODE, SOPTIONS => :SOPTIONS, RCQUEUE => :RCQUEUE); END;", - { - NEXSSERVICEFN: prms.nServiceFnId, - BMSG: prms.blMsg, - NEXSQUEUE: prms.nQueueId, - NLNK_COMPANY: prms.nLnkCompanyId, - NLNK_DOCUMENT: prms.nLnkDocumentId, - SLNK_UNITCODE: prms.sLnkUnitcode, - SOPTIONS: prms.sOptions, - RCQUEUE: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true } - ); - let rows = await readCursorData(res.outBinds.RCQUEUE); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_PUT", + inPrms: { + NEXSSERVICEFN: prms.nServiceFnId, + BMSG: prms.blMsg, + NEXSQUEUE: prms.nQueueId, + NLNK_COMPANY: prms.nLnkCompanyId, + NLNK_DOCUMENT: prms.nLnkDocumentId, + SLNK_UNITCODE: prms.sLnkUnitcode, + SOPTIONS: prms.sOptions + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueData.RCQUEUE[0]; }; //Считывание очередной порции исходящих сообщений из очереди const getQueueOutgoing = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_SRV_TYPE_SEND_GET(NPORTION_SIZE => :NPORTION_SIZE, RCQUEUES => :RCQUEUES); END;", - { - NPORTION_SIZE: prms.nPortionSize, - RCQUEUES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT } - ); - let rows = await readCursorData(res.outBinds.RCQUEUES); - return rows; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueOutgoingData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_SRV_TYPE_SEND_GET", + inPrms: { + NPORTION_SIZE: prms.nPortionSize + }, + outPrms: { RCQUEUES: DT_CURSOR } + }); + return queueOutgoingData.RCQUEUES; }; //Установка значения состояния в сообщении очереди const setQueueState = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_EXEC_STATE_SET(NEXSQUEUE => :NEXSQUEUE, NEXEC_STATE => :NEXEC_STATE, SEXEC_MSG => :SEXEC_MSG, NINC_EXEC_CNT => :NINC_EXEC_CNT, NRESET_DATA => :NRESET_DATA, RCQUEUE => :RCQUEUE); END;", - { - NEXSQUEUE: prms.nQueueId, - NEXEC_STATE: prms.nExecState, - SEXEC_MSG: prms.sExecMsg, - NINC_EXEC_CNT: prms.nIncExecCnt, - NRESET_DATA: prms.nResetData, - RCQUEUE: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true } - ); - let rows = await readCursorData(res.outBinds.RCQUEUE); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueStateData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_EXEC_STATE_SET", + inPrms: { + NEXSQUEUE: prms.nQueueId, + NEXEC_STATE: prms.nExecState, + SEXEC_MSG: prms.sExecMsg, + NINC_EXEC_CNT: prms.nIncExecCnt, + NRESET_DATA: prms.nResetData + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueStateData.RCQUEUE[0]; }; //Считывание данных сообщения очереди const getQueueMsg = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_MSG_GET(NEXSQUEUE => :NEXSQUEUE, RCQUEUE_MSG => :RCQUEUE_MSG); END;", - { - NEXSQUEUE: prms.nQueueId, - RCQUEUE_MSG: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { - outFormat: oracledb.OBJECT, - autoCommit: true, - fetchInfo: { blMsg: { type: oracledb.BUFFER } } - } - ); - let rows = await readCursorData(res.outBinds.RCQUEUE_MSG); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueMsgData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_MSG_GET", + inPrms: { + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCQUEUE_MSG: DT_CURSOR } + }); + return queueMsgData.RCQUEUE_MSG[0]; }; //Установка данных сообщения очереди const setQueueMsg = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_MSG_SET(NEXSQUEUE => :NEXSQUEUE, BMSG => :BMSG, RCQUEUE => :RCQUEUE); END;", - { - NEXSQUEUE: prms.nQueueId, - BMSG: prms.blMsg, - RCQUEUE: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true } - ); - let rows = await readCursorData(res.outBinds.RCQUEUE); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueMsgData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_MSG_SET", + inPrms: { + NEXSQUEUE: prms.nQueueId, + BMSG: prms.blMsg + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueMsgData.RCQUEUE[0]; }; //Установка параметров сообщения очереди const setQueueOptions = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_OPTIONS_SET(NEXSQUEUE => :NEXSQUEUE, SOPTIONS => :SOPTIONS, RCQUEUE => :RCQUEUE); END;", - { - NEXSQUEUE: prms.nQueueId, - SOPTIONS: prms.sOptions, - RCQUEUE: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true } - ); - let rows = await readCursorData(res.outBinds.RCQUEUE); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueOptionsData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_OPTIONS_SET", + inPrms: { + NEXSQUEUE: prms.nQueueId, + SOPTIONS: prms.sOptions + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueOptionsData.RCQUEUE[0]; }; //Считывание результата обработки сообщения очереди const getQueueResp = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_RESP_GET(NEXSQUEUE => :NEXSQUEUE, RCQUEUE_RESP => :RCQUEUE_RESP); END;", - { - NEXSQUEUE: prms.nQueueId, - RCQUEUE_RESP: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { - outFormat: oracledb.OBJECT, - autoCommit: true, - fetchInfo: { blResp: { type: oracledb.BUFFER } } - } - ); - let rows = await readCursorData(res.outBinds.RCQUEUE_RESP); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueRespData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_RESP_GET", + inPrms: { + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCQUEUE_RESP: DT_CURSOR } + }); + return queueRespData.RCQUEUE_RESP[0]; }; //Установка результата обработки сообщения очереди const setQueueResp = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_RESP_SET(NEXSQUEUE => :NEXSQUEUE, BRESP => :BRESP, NIS_ORIGINAL => :NIS_ORIGINAL, RCQUEUE => :RCQUEUE); END;", - { - NEXSQUEUE: prms.nQueueId, - BRESP: prms.blResp, - NIS_ORIGINAL: prms.nIsOriginal, - RCQUEUE: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true } - ); - let rows = await readCursorData(res.outBinds.RCQUEUE); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueRespData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_RESP_SET", + inPrms: { + NEXSQUEUE: prms.nQueueId, + BRESP: prms.blResp, + NIS_ORIGINAL: prms.nIsOriginal + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueRespData.RCQUEUE[0]; }; //Установка параметров результата обработки сообщения очереди const setQueueOptionsResp = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_OPTIONS_RESP_SET(NEXSQUEUE => :NEXSQUEUE, SOPTIONS_RESP => :SOPTIONS_RESP, RCQUEUE => :RCQUEUE); END;", - { - NEXSQUEUE: prms.nQueueId, - SOPTIONS_RESP: prms.sOptionsResp, - RCQUEUE: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true } - ); - let rows = await readCursorData(res.outBinds.RCQUEUE); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queueOptionsRespData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_OPTIONS_RESP_SET", + inPrms: { + NEXSQUEUE: prms.nQueueId, + SOPTIONS_RESP: prms.sOptionsResp + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueOptionsRespData.RCQUEUE[0]; }; //Исполнение обработчика со стороны БД для сообщения очереди const execQueuePrc = async prms => { - let pooledConnection; - try { - pooledConnection = await prms.connection.getConnection(); - let res = await pooledConnection.execute( - "BEGIN PKG_EXS.QUEUE_PRC(NEXSQUEUE => :NEXSQUEUE, RCRESULT => :RCRESULT); END;", - { - NEXSQUEUE: prms.nQueueId, - RCRESULT: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } - }, - { outFormat: oracledb.OBJECT, autoCommit: true } - ); - let rows = await readCursorData(res.outBinds.RCRESULT); - return rows[0]; - } catch (e) { - throw new Error(e.message); - } finally { - if (pooledConnection) { - try { - await pooledConnection.close(); - } catch (e) { - throw new Error(e.message); - } - } - } + let queuePrcData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS.QUEUE_PRC", + inPrms: { + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCRESULT: DT_CURSOR } + }); + return queuePrcData.RCRESULT[0]; }; //----------------- // Интерфейс модуля //----------------- +exports.DT_VARCHAR = DT_VARCHAR; +exports.DT_NUMBER = DT_NUMBER; +exports.DT_DATE = DT_DATE; +exports.DT_CLOB = DT_CLOB; +exports.DT_BLOB = DT_BLOB; +exports.DT_CURSOR = DT_CURSOR; +exports.executeStored = executeStored; exports.connect = connect; exports.disconnect = disconnect; exports.getServices = getServices; diff --git a/modules/parus_pg_db.js b/modules/parus_pg_db.js new file mode 100644 index 0000000..401fae4 --- /dev/null +++ b/modules/parus_pg_db.js @@ -0,0 +1,509 @@ +/* + Сервис интеграции ПП Парус 8 с WEB API + Дополнительный модуль: работа с БД ПП Парус 8 (Postgre) +*/ + +//---------------------- +// Подключение библиотек +//---------------------- + +const pg = require("pg"); //Работа с СУБД Postgre + +//-------------------------- +// Глобальные идентификаторы +//-------------------------- + +const DT_VARCHAR = pg.types.builtins.VARCHAR; //Тип данных "Строка" БД +const DT_NUMBER = pg.types.builtins.NUMERIC; //Тип данных "Число" БД +const DT_DATE = pg.types.builtins.DATE; //Тип данных "Дата" БД +const DT_CLOB = pg.types.builtins.TEXT; //Тип данных "Текстовые данные" БД +const DT_BLOB = pg.types.builtins.BYTEA; //Тип данных "Двоичные данные" БД +const DT_CURSOR = pg.types.builtins.REFCURSOR; //Тип данных "Курсор" БД + +//------------ +// Тело модуля +//------------ + +//Установка парсера значений для типа данных NUMERIC БД PG +pg.types.setTypeParser(pg.types.builtins.NUMERIC, val => { + return val ? Number(val) : val; +}); + +//Формирование имени хранимого объекта БД (с параметрами) +const makeStoredName = (sName, inPrms) => { + let prms = ""; + let prm_numb = 0; + for (i in inPrms) { + prm_numb++; + let prm_type = ""; + if (inPrms[i] != null && inPrms[i] != undefined) + switch (typeof inPrms[i]) { + case "string": + if (inPrms[i].length ? inPrms[i].length > 4000 : false) prm_type = "::text"; + else prm_type = "::character varying"; + break; + case "number": + prm_type = "::numeric"; + break; + case "bigint": + prm_type = "::numeric"; + break; + case "boolean": + prm_type = "::boolean"; + break; + case "object": + if (inPrms[i] instanceof Date) prm_type = "::date"; + else prm_type = "::bytea"; + break; + default: + break; + } + prms += `${prms ? ", " : ""}$${prm_numb}${prm_type}`; + } + return `${sName.replace(".", "$")}(${prms})`; +}; + +//Формирование параметров хранимого объекта БД +const makeStoredPrms = inPrms => { + let prms = []; + for (i in inPrms) prms.push(inPrms[i]); + return prms; +}; + +//Исполнение хранимого объекта БД +const executeStored = async prms => { + let client; + let outResult = {}; + try { + client = await prms.connection.connect(); + let outPrmName = ""; + let outPrmIsCursor = false; + for (i in prms.outPrms) { + outPrmName = i; + outPrmIsCursor = prms.outPrms[i] == DT_CURSOR; + break; + } + await client.query(`begin;`); + let res = await client.query({ + text: `select ${makeStoredName(prms.sName, prms.inPrms)}${outPrmName ? ` as "${outPrmName}"` : ""};`, + values: makeStoredPrms(prms.inPrms) + }); + if (res) + if (res.rows) + if (res.rows[0]) { + const outBind = res.rows[0][outPrmName]; + if (outPrmIsCursor) { + let rowsRes = []; + let doExit = false; + while (!doExit) { + doExit = true; + res = await client.query(`fetch next from "${outBind}";`); + if (res) + if (res.rows) + if (res.rowCount > 0 && res.rows.length > 0) { + doExit = false; + res.rows.map(r => rowsRes.push(r)); + } + } + outResult[outPrmName] = rowsRes; + } else outResult[outPrmName] = outBind; + } + await client.query(`commit;`); + } catch (e) { + if (client) { + try { + await client.query(`rollback;`); + } catch (err) { + throw new Error(err.message); + } + } + throw new Error(e.message); + } finally { + if (client) { + try { + await client.release(); + } catch (err) { + throw new Error(err.message); + } + } + } + if (outResult) return outResult; +}; + +//Проверка допустимого количества воркеров +const checkWorkers = async prms => { + let workersData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$UTL_LIC_CLNT_COUNT_GET", + outPrms: { + LIC_CNT: DT_NUMBER + } + }); + if (workersData.LIC_CNT === 0) { + throw new Error(`Не определено количество лицензий для приложения "ExchangeServer".`); + } + if (prms.nMaxWorkers > workersData.LIC_CNT - 1) { + throw new Error( + `Недопустимое значение параметра "Количество одновременно обрабатываемых исходящих сообщений" ("outGoing.nMaxWorkers") файла конфигурации сервиса приложений ("config.js"). Максимальное количество одновременно обрабатываемых исходящих сообщений - ${ + workersData.LIC_CNT - 1 + }.` + ); + } +}; + +//Проверка соответствия релизов сервера приложений и системы +const checkRelease = async prms => { + let releaseData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$UTL_PRODUCT_RELEASE_GET", + outPrms: { + DB_RELEASE: DT_VARCHAR + } + }); + if (releaseData.DB_RELEASE !== prms.sRelease) { + throw new Error(`Версия сервера приложений (${prms.sRelease}) не соответствует версии системы (${releaseData.DB_RELEASE}).`); + } +}; + +//Подключение к БД +const connect = async prms => { + try { + let pool = new pg.Pool({ + connectionString: `postgres://${prms.sUser}:${prms.sPassword}@${prms.sConnectString}`, + connectionTimeoutMillis: 600000, + min: prms.nPoolMin ? prms.nPoolMin : 4, + max: prms.nPoolMax ? prms.nPoolMax : 4 + }); + pool.on("acquire", async client => { + await client.query(`select ALTER_SESSION_SET_SCHEMA($1);`, [prms.sSchema]); + }); + if (prms.bControlSystemVersion) { + await checkRelease({ sRelease: prms.sRelease, connection: pool }); + } + await checkWorkers({ nMaxWorkers: prms.nMaxWorkers, connection: pool }); + return pool; + } catch (e) { + throw new Error(e.message); + } +}; + +//Отключение от БД +const disconnect = async prms => { + try { + await prms.connection.end(); + } catch (e) { + throw new Error(e.message); + } +}; + +//Получение списка сервисов +const getServices = async prms => { + let servicesData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$SERVICES_GET", + outPrms: { + RCSERVICES: DT_CURSOR + } + }); + return servicesData.RCSERVICES; +}; + +//Получение списка функций сервиса +const getServiceFunctions = async prms => { + let serviceFunctionsData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$SERVICEFNS_GET", + inPrms: { + NEXSSERVICE: prms.nServiceId + }, + outPrms: { + RCSERVICEFNS: DT_CURSOR + } + }); + return serviceFunctionsData.RCSERVICEFNS; +}; + +//Получение контекста сервиса +const getServiceContext = async prms => { + let serviceContextData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$SERVICE_CTX_GET", + inPrms: { + NFLAG_SMART: 0, + NEXSSERVICE: prms.nServiceId + }, + outPrms: { + RCSERVICE_CTX: DT_CURSOR + } + }); + return serviceContextData.RCSERVICE_CTX[0]; +}; + +//Установка контекста сервиса +const setServiceContext = async prms => { + await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$SERVICE_CTX_SET", + inPrms: { + NEXSSERVICE: prms.nServiceId, + SCTX: prms.sCtx, + DCTX_EXP: prms.dCtxExp + } + }); +}; + +//Очистка контекста сервиса +const clearServiceContext = async prms => { + await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$SERVICE_CTX_CLEAR", + inPrms: { NEXSSERVICE: prms.nServiceId } + }); +}; + +//Проверка атуентифицированности сервиса +const isServiceAuth = async prms => { + let serviceAuth = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$SERVICE_IS_AUTH", + inPrms: { NEXSSERVICE: prms.nServiceId }, + outPrms: { + RET: DT_NUMBER + } + }); + return serviceAuth.RET; +}; + +//Постановка в очередь задания на аутентификацию сервиса +const putServiceAuthInQueue = async prms => { + await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$SERVICE_AUTH_PUT_INQUEUE_AT", + inPrms: { NEXSSERVICE: prms.nServiceId, NFORCE: prms.nForce } + }); +}; + +//Получение информации о просроченных сообщениях обмена сервиса +const getServiceExpiredQueueInfo = async prms => { + let serviceExpiredQueueInfoData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$SERVICE_QUEUE_EXPIRED_INFO_GET", + inPrms: { + NEXSSERVICE: prms.nServiceId + }, + outPrms: { + RCSERVICE_QUEUE_EXPIRED_INFO: DT_CURSOR + } + }); + return serviceExpiredQueueInfoData.RCSERVICE_QUEUE_EXPIRED_INFO[0]; +}; + +//Запись в протокол работы +const log = async prms => { + let logData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$LOG_PUT", + inPrms: { + NLOG_STATE: prms.nLogState, + SMSG: prms.sMsg, + NEXSSERVICE: prms.nServiceId, + NEXSSERVICEFN: prms.nServiceFnId, + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCLOG: DT_CURSOR } + }); + return logData.RCLOG[0]; +}; + +//Считывание записи очереди обмена +const getQueue = async prms => { + let queueData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_GET", + inPrms: { + NFLAG_SMART: 0, + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueData.RCQUEUE[0]; +}; + +//Помещение сообщения в очередь +const putQueue = async prms => { + let queueData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_PUT$2", + inPrms: { + NEXSSERVICEFN: prms.nServiceFnId, + BMSG: prms.blMsg, + NEXSQUEUE: prms.nQueueId, + NLNK_COMPANY: prms.nLnkCompanyId, + NLNK_DOCUMENT: prms.nLnkDocumentId, + SLNK_UNITCODE: prms.sLnkUnitcode, + SOPTIONS: prms.sOptions + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueData.RCQUEUE[0]; +}; + +//Считывание очередной порции исходящих сообщений из очереди +const getQueueOutgoing = async prms => { + let queueOutgoingData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_SRV_TYPE_SEND_GET", + inPrms: { + NPORTION_SIZE: prms.nPortionSize + }, + outPrms: { RCQUEUES: DT_CURSOR } + }); + return queueOutgoingData.RCQUEUES; +}; + +//Установка значения состояния в сообщении очереди +const setQueueState = async prms => { + let queueStateData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_EXEC_STATE_SET", + inPrms: { + NEXSQUEUE: prms.nQueueId, + NEXEC_STATE: prms.nExecState, + SEXEC_MSG: prms.sExecMsg, + NINC_EXEC_CNT: prms.nIncExecCnt, + NRESET_DATA: prms.nResetData + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueStateData.RCQUEUE[0]; +}; + +//Считывание данных сообщения очереди +const getQueueMsg = async prms => { + let queueMsgData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_MSG_GET", + inPrms: { + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCQUEUE_MSG: DT_CURSOR } + }); + return queueMsgData.RCQUEUE_MSG[0]; +}; + +//Установка данных сообщения очереди +const setQueueMsg = async prms => { + let queueMsgData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_MSG_SET$2", + inPrms: { + NEXSQUEUE: prms.nQueueId, + BMSG: prms.blMsg + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueMsgData.RCQUEUE[0]; +}; + +//Установка параметров сообщения очереди +const setQueueOptions = async prms => { + let queueOptionsData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_OPTIONS_SET$2", + inPrms: { + NEXSQUEUE: prms.nQueueId, + SOPTIONS: prms.sOptions + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueOptionsData.RCQUEUE[0]; +}; + +//Считывание результата обработки сообщения очереди +const getQueueResp = async prms => { + let queueRespData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_RESP_GET", + inPrms: { + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCQUEUE_RESP: DT_CURSOR } + }); + return queueRespData.RCQUEUE_RESP[0]; +}; + +//Установка результата обработки сообщения очереди +const setQueueResp = async prms => { + let queueRespData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_RESP_SET$2", + inPrms: { + NEXSQUEUE: prms.nQueueId, + BRESP: prms.blResp, + NIS_ORIGINAL: prms.nIsOriginal + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueRespData.RCQUEUE[0]; +}; + +//Установка параметров результата обработки сообщения очереди +const setQueueOptionsResp = async prms => { + let queueOptionsRespData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_OPTIONS_RESP_SET$2", + inPrms: { + NEXSQUEUE: prms.nQueueId, + SOPTIONS_RESP: prms.sOptionsResp + }, + outPrms: { RCQUEUE: DT_CURSOR } + }); + return queueOptionsRespData.RCQUEUE[0]; +}; + +//Исполнение обработчика со стороны БД для сообщения очереди +const execQueuePrc = async prms => { + let queuePrcData = await executeStored({ + connection: prms.connection, + sName: "PKG_EXS$QUEUE_PRC", + inPrms: { + NEXSQUEUE: prms.nQueueId + }, + outPrms: { RCRESULT: DT_CURSOR } + }); + return queuePrcData.RCRESULT[0]; +}; + +//----------------- +// Интерфейс модуля +//----------------- + +exports.DT_VARCHAR = DT_VARCHAR; +exports.DT_NUMBER = DT_NUMBER; +exports.DT_DATE = DT_DATE; +exports.DT_CLOB = DT_CLOB; +exports.DT_BLOB = DT_BLOB; +exports.DT_CURSOR = DT_CURSOR; +exports.executeStored = executeStored; +exports.connect = connect; +exports.disconnect = disconnect; +exports.getServices = getServices; +exports.getServiceFunctions = getServiceFunctions; +exports.getServiceContext = getServiceContext; +exports.setServiceContext = setServiceContext; +exports.clearServiceContext = clearServiceContext; +exports.isServiceAuth = isServiceAuth; +exports.putServiceAuthInQueue = putServiceAuthInQueue; +exports.getServiceExpiredQueueInfo = getServiceExpiredQueueInfo; +exports.log = log; +exports.getQueue = getQueue; +exports.putQueue = putQueue; +exports.getQueueOutgoing = getQueueOutgoing; +exports.setQueueState = setQueueState; +exports.getQueueMsg = getQueueMsg; +exports.setQueueMsg = setQueueMsg; +exports.setQueueOptions = setQueueOptions; +exports.getQueueResp = getQueueResp; +exports.setQueueResp = setQueueResp; +exports.setQueueOptionsResp = setQueueOptionsResp; +exports.execQueuePrc = execQueuePrc; diff --git a/package-lock.json b/package-lock.json index f6e373e..b88a74b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "mqtt": "^5.10.1", "nodemailer": "^6.4.11", "oracledb": "^4.2.0", + "pg": "^8.13.1", "request": "^2.88.2", "request-promise": "^4.2.6", "validate": "^5.1.0", @@ -998,6 +999,122 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "node_modules/pg": { + "version": "8.13.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", + "integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", + "dependencies": { + "pg-connection-string": "^2.7.0", + "pg-pool": "^3.7.0", + "pg-protocol": "^1.7.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", + "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz", + "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", + "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -1513,6 +1630,14 @@ "engines": { "node": ">=4.0" } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } } }, "dependencies": { @@ -2261,6 +2386,89 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "pg": { + "version": "8.13.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", + "integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", + "requires": { + "pg-cloudflare": "^1.1.1", + "pg-connection-string": "^2.7.0", + "pg-pool": "^3.7.0", + "pg-protocol": "^1.7.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "pg-connection-string": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", + "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz", + "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", + "requires": {} + }, + "pg-protocol": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", + "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + } + }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -2654,6 +2862,11 @@ "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" } } } diff --git a/package.json b/package.json index deec4a9..e81fb89 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "mqtt": "^5.10.1", "nodemailer": "^6.4.11", "oracledb": "^4.2.0", + "pg": "^8.13.1", "request": "^2.88.2", "request-promise": "^4.2.6", "validate": "^5.1.0",