Compare commits
No commits in common. "master" and "2.0.0_NodeJS_22" have entirely different histories.
master
...
2.0.0_Node
18
config.js
18
config.js
@ -7,6 +7,16 @@
|
|||||||
// Тело модуля
|
// Тело модуля
|
||||||
//------------
|
//------------
|
||||||
|
|
||||||
|
//Переменные окружения
|
||||||
|
/*
|
||||||
|
Только для СУБД Oracle.
|
||||||
|
1. NODE_ORACLE_DB_THIN_MODE - Установите значение "1", чтобы использовать режим "тонкого клиента" (Thin-режим)
|
||||||
|
при подключении к БД (не требует установки Oracle Client).
|
||||||
|
2. ORACLE_CLIENT_LIB_DIR - Путь к директории с библиотеками Oracle Client,
|
||||||
|
используется только для работы в режиме "толстого клиента" (Thick-режим), если значение не указано,
|
||||||
|
то будет использоваться значение из переменной операционной системы PATH.
|
||||||
|
*/
|
||||||
|
|
||||||
//Общие параметры
|
//Общие параметры
|
||||||
let common = {
|
let common = {
|
||||||
//Наименование сервера приложений
|
//Наименование сервера приложений
|
||||||
@ -14,7 +24,7 @@ let common = {
|
|||||||
//Версия сервера приложений
|
//Версия сервера приложений
|
||||||
sVersion: "8.5.6.1",
|
sVersion: "8.5.6.1",
|
||||||
//Релиз сервера приложений
|
//Релиз сервера приложений
|
||||||
sRelease: "2026.02.12",
|
sRelease: "2026.02.10",
|
||||||
//Таймаут останова сервера (мс)
|
//Таймаут останова сервера (мс)
|
||||||
nTerminateTimeout: 60000,
|
nTerminateTimeout: 60000,
|
||||||
//Контролировать версию Системы
|
//Контролировать версию Системы
|
||||||
@ -34,11 +44,7 @@ let dbConnect = {
|
|||||||
//Наименование сервера приложений в сессии БД
|
//Наименование сервера приложений в сессии БД
|
||||||
sSessionAppName: "PARUS$ExchangeServer",
|
sSessionAppName: "PARUS$ExchangeServer",
|
||||||
//Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД)
|
//Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД)
|
||||||
sConnectorModule: "parus_oracle_db.js",
|
sConnectorModule: "parus_oracle_db.js"
|
||||||
//Применение "тонкого" (Thin) или "толстого" (Thick) режима подключения (false - Thick-режим - работа через установленного клиента СУБД Oracle, true - Thin-режим - не требует установки клиента СУБД Oracle, допустим только для Oracle >= 12.1)
|
|
||||||
bOraUseThinMode: false,
|
|
||||||
//Путь к домашней директории Oracle Client (только для Thick-режима подключения к СУБД Oracle, если значение не указано, то будет использоваться значение из переменной окружения "PATH" ОС)
|
|
||||||
sOraClient: ""
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//Параметры обработки очереди исходящих сообщений
|
//Параметры обработки очереди исходящих сообщений
|
||||||
|
|||||||
@ -118,6 +118,7 @@ class ParusAppServer {
|
|||||||
await this.logger.info(
|
await this.logger.info(
|
||||||
`Обработчик очереди входящих сообщений запущен (порт - ${nPort}, доступные IP - ${sHost === "0.0.0.0" ? getIPs().join("; ") : sHost})`
|
`Обработчик очереди входящих сообщений запущен (порт - ${nPort}, доступные IP - ${sHost === "0.0.0.0" ? getIPs().join("; ") : sHost})`
|
||||||
);
|
);
|
||||||
|
//Запускаем
|
||||||
//Запускаем модуль отправки уведомлений
|
//Запускаем модуль отправки уведомлений
|
||||||
await this.logger.info("Запуск модуля отправки уведомлений...");
|
await this.logger.info("Запуск модуля отправки уведомлений...");
|
||||||
try {
|
try {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -30,9 +30,8 @@ const { SPROTOCOL_HTTP, SPROTOCOL_KAFKA } = require("../models/obj_service"); //
|
|||||||
|
|
||||||
//Глубокое клонирование
|
//Глубокое клонирование
|
||||||
const deepClone = value => {
|
const deepClone = value => {
|
||||||
//Буфер для фиксации "клонированных" элементов исходного объекта
|
//Клонируем объект в зависимости от его типа, сохраняя прототипы
|
||||||
const seen = new WeakMap();
|
const seen = new WeakMap();
|
||||||
//Функция рекурсивного клонирования (разбирает тип полученного значения и в зависимости от него выполняет клонирование, сохраняя прототипы)
|
|
||||||
const clone = val => {
|
const clone = val => {
|
||||||
//Примитивы и функции возвращаем как есть
|
//Примитивы и функции возвращаем как есть
|
||||||
if (val === null || typeof val !== "object") return val;
|
if (val === null || typeof val !== "object") return val;
|
||||||
@ -105,12 +104,10 @@ const deepClone = value => {
|
|||||||
});
|
});
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
//Выполняем копирование рекурсивно с верхнего уровня
|
|
||||||
try {
|
try {
|
||||||
//Возвращаем что получилось
|
|
||||||
return clone(value);
|
return clone(value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//В случае непредвиденной ошибки формируем исключение
|
//В случае непредвиденной ошибки формируем информативное исключение
|
||||||
const err = new Error("Ошибка глубокого копирования объекта");
|
const err = new Error("Ошибка глубокого копирования объекта");
|
||||||
err.originalError = e;
|
err.originalError = e;
|
||||||
throw err;
|
throw err;
|
||||||
@ -410,33 +407,30 @@ const getNowString = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Глубокое слияние объектов
|
//Глубокое слияние объектов
|
||||||
const deepMerge = (...sources) => {
|
function deepMerge(...sources) {
|
||||||
//Проверка на простой объект (не имеет специального поведения или прототипа)
|
|
||||||
const isPlainObject = value => Object.prototype.toString.call(value) === "[object Object]";
|
const isPlainObject = value => Object.prototype.toString.call(value) === "[object Object]";
|
||||||
//Клоникарование значения
|
|
||||||
const cloneValue = value => deepClone(value);
|
const cloneValue = value => {
|
||||||
//Буфер для результата
|
return deepClone(value);
|
||||||
|
};
|
||||||
|
|
||||||
const target = {};
|
const target = {};
|
||||||
//Обходим входные параметры по очереди
|
|
||||||
for (const source of sources) {
|
for (const source of sources) {
|
||||||
//Пропускаем непростые объекты - сливать можем только простые
|
|
||||||
if (!isPlainObject(source)) continue;
|
if (!isPlainObject(source)) continue;
|
||||||
//Обходим пары "ключ-значение"
|
|
||||||
for (const [key, value] of Object.entries(source)) {
|
for (const [key, value] of Object.entries(source)) {
|
||||||
//Если значение ключа - объект
|
|
||||||
if (isPlainObject(value)) {
|
if (isPlainObject(value)) {
|
||||||
//Сливаем рекурсивно
|
|
||||||
if (!isPlainObject(target[key])) target[key] = {};
|
if (!isPlainObject(target[key])) target[key] = {};
|
||||||
target[key] = deepMerge(target[key], value);
|
target[key] = deepMerge(target[key], value);
|
||||||
} else {
|
} else {
|
||||||
//Примитивы - просто клонируем
|
|
||||||
target[key] = cloneValue(value);
|
target[key] = cloneValue(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Возвращаем собранный буфер, содержащий все слитые воедино объекты-параметры
|
|
||||||
return target;
|
return target;
|
||||||
};
|
}
|
||||||
|
|
||||||
//Глубокое копирование объекта
|
//Глубокое копирование объекта
|
||||||
const deepCopyObject = obj => JSON.parse(JSON.stringify(obj));
|
const deepCopyObject = obj => JSON.parse(JSON.stringify(obj));
|
||||||
@ -515,31 +509,27 @@ const getURLProtocol = sURL => {
|
|||||||
|
|
||||||
//Обёртывание промиса в таймаут исполнения
|
//Обёртывание промиса в таймаут исполнения
|
||||||
const wrapPromiseTimeout = (timeout, executor) => {
|
const wrapPromiseTimeout = (timeout, executor) => {
|
||||||
//Проверяем входные параметры - должен быть указан ненулевой таймаут и функция-исполнитель промиса
|
|
||||||
if (!timeout || typeof executor !== "function") {
|
if (!timeout || typeof executor !== "function") {
|
||||||
//Разрешаем сразу, не ожидая
|
|
||||||
return executor ? executor() : Promise.resolve();
|
return executor ? executor() : Promise.resolve();
|
||||||
}
|
}
|
||||||
//Параметры прошли проверку, создаем экхемпляр контроллера прерывания асинхронного процесса
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
//Подготовим объект для выбрасывания ошибки
|
|
||||||
const sMessage = `Истёк интервал ожидания (${timeout} мс) завершения асинхронного процесса.`;
|
const sMessage = `Истёк интервал ожидания (${timeout} мс) завершения асинхронного процесса.`;
|
||||||
const timeoutError = new Error(sMessage);
|
const timeoutError = new Error(sMessage);
|
||||||
timeoutError.error = sMessage;
|
timeoutError.error = sMessage;
|
||||||
//Буфер для идентификатора таймера
|
|
||||||
let timeoutPid;
|
let timeoutPid;
|
||||||
//Создаём промис с взведенным таумером на у казанный таймаут, промис будет "отклонён" по истечении таймера, но перед этим контроллер прерывания выдаст "сигнал" на отмену осинхронного процесса
|
|
||||||
const timeoutPromise = new Promise((_, reject) => {
|
const timeoutPromise = new Promise((_, reject) => {
|
||||||
timeoutPid = setTimeout(() => {
|
timeoutPid = setTimeout(() => {
|
||||||
controller.abort(timeoutError);
|
controller.abort(timeoutError);
|
||||||
reject(timeoutError);
|
reject(timeoutError);
|
||||||
}, timeout);
|
}, timeout);
|
||||||
});
|
});
|
||||||
//Создаём промис с функцией-исполнителем асинхронного процесса
|
|
||||||
const taskPromise = Promise.resolve(executor(controller.signal));
|
const taskPromise = Promise.resolve(executor(controller.signal));
|
||||||
//Запускаем оба промиса в режиме "гонка" - кто "быстрее" исполнится
|
|
||||||
return Promise.race([taskPromise, timeoutPromise]).finally(() => {
|
return Promise.race([taskPromise, timeoutPromise]).finally(() => {
|
||||||
//В любом случае не забываем зачистить взведённый таймер
|
|
||||||
if (timeoutPid) clearTimeout(timeoutPid);
|
if (timeoutPid) clearTimeout(timeoutPid);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
8
index.js
8
index.js
@ -23,13 +23,7 @@ let appSrv = new app.ParusAppServer(); //Экземпляр сервера пр
|
|||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
//Разрешение на TLS (Transport Layer Security) без авторизации
|
//Разрешение на TLS (Transport Layer Security) без авторизации
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = cfg?.outGoing?.bValidateSSL === false ? "0" : "1";
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = cfg.outGoing.bValidateSSL === false ? "0" : "1";
|
||||||
|
|
||||||
//Включение "Токого режима" для Oracle
|
|
||||||
process.env.NODE_ORACLE_DB_THIN_MODE = cfg?.dbConnect?.bOraUseThinMode === true ? "1" : "0";
|
|
||||||
|
|
||||||
//Путь к клиентским библиотекам для Oracle
|
|
||||||
process.env.ORACLE_CLIENT_LIB_DIR = cfg?.dbConnect?.sOraClient || "";
|
|
||||||
|
|
||||||
//Обработка события "выход" жизненного цикла процесса
|
//Обработка события "выход" жизненного цикла процесса
|
||||||
process.on("exit", code => {
|
process.on("exit", code => {
|
||||||
|
|||||||
@ -189,24 +189,6 @@ const dbConnect = new Schema({
|
|||||||
type: path => `Наименование подключаемого модуля обслуживания БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
type: path => `Наименование подключаемого модуля обслуживания БД (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||||
required: path => `Не указано наименование подключаемого модуля обслуживания БД (${path})`
|
required: path => `Не указано наименование подключаемого модуля обслуживания БД (${path})`
|
||||||
}
|
}
|
||||||
},
|
|
||||||
//Признак применения "тонкого" (Thin) или "толстого" (Thick) режима подключения к БД
|
|
||||||
bOraUseThinMode: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
message: {
|
|
||||||
type: path => `Признак режима подключения (Thin/Thick) к БД (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
|
|
||||||
required: path => `Не указан признак режима подключения (Thin/Thick) к БД (${path})`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//Путь к домашней директории Oracle Client
|
|
||||||
sOraClient: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
message: {
|
|
||||||
type: path => `Путь к домашней директории Oracle Client (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
|
||||||
required: path => `Не указан путь к домашней директории Oracle Client (${path})`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -533,10 +533,6 @@ const beforeEvent = async prms => {
|
|||||||
if (prms.options.sdepartment_name && sDepartmentId) {
|
if (prms.options.sdepartment_name && sDepartmentId) {
|
||||||
surl = `${surl}&departmentId=${sDepartmentId}`;
|
surl = `${surl}&departmentId=${sDepartmentId}`;
|
||||||
}
|
}
|
||||||
//Заполним максимальное количество возвращаемых элементов
|
|
||||||
if (prms.options.limit) {
|
|
||||||
surl = `${surl}&limit=${prms.options.limit}`;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (prms.queue.blMsg) {
|
if (prms.queue.blMsg) {
|
||||||
//Конвертируем XML из "Парус 8" в понятный "ДИАДОК" JSON
|
//Конвертируем XML из "Парус 8" в понятный "ДИАДОК" JSON
|
||||||
|
|||||||
@ -20,7 +20,7 @@ const sax = require("./node_modules/sax"); //Событийный XML-парсе
|
|||||||
|
|
||||||
//Инициализируем Thick-режим до любых подключений к БД
|
//Инициализируем Thick-режим до любых подключений к БД
|
||||||
try {
|
try {
|
||||||
if (typeof oracledb.initOracleClient === "function" && !(process.env.NODE_ORACLE_DB_THIN_MODE === "1")) {
|
if (typeof oracledb.initOracleClient === "function" && !(process.env.NODE_ORACLE_DB_THIN_MODE === 1)) {
|
||||||
const libDir = process.env.ORACLE_CLIENT_LIB_DIR;
|
const libDir = process.env.ORACLE_CLIENT_LIB_DIR;
|
||||||
if (libDir) {
|
if (libDir) {
|
||||||
oracledb.initOracleClient({ libDir });
|
oracledb.initOracleClient({ libDir });
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const { makeErrorText } = require("../core/utils"); //Вспомогательн
|
|||||||
|
|
||||||
//Инициализируем Thick-режим до любых подключений к БД
|
//Инициализируем Thick-режим до любых подключений к БД
|
||||||
try {
|
try {
|
||||||
if (typeof oracledb.initOracleClient === "function" && !(process.env.NODE_ORACLE_DB_THIN_MODE === "1")) {
|
if (typeof oracledb.initOracleClient === "function" && !(process.env.NODE_ORACLE_DB_THIN_MODE === 1)) {
|
||||||
const libDir = process.env.ORACLE_CLIENT_LIB_DIR;
|
const libDir = process.env.ORACLE_CLIENT_LIB_DIR;
|
||||||
if (libDir) {
|
if (libDir) {
|
||||||
oracledb.initOracleClient({ libDir });
|
oracledb.initOracleClient({ libDir });
|
||||||
@ -203,10 +203,9 @@ const clearServer = async prms => {
|
|||||||
|
|
||||||
//Подключение к БД
|
//Подключение к БД
|
||||||
const connect = async prms => {
|
const connect = async prms => {
|
||||||
let pool = null;
|
|
||||||
try {
|
try {
|
||||||
//Создаем пул подключения
|
//Создаем пул подключения
|
||||||
pool = await oracledb.createPool({
|
let pool = await oracledb.createPool({
|
||||||
user: prms.sUser,
|
user: prms.sUser,
|
||||||
password: prms.sPassword,
|
password: prms.sPassword,
|
||||||
connectString: prms.sConnectString,
|
connectString: prms.sConnectString,
|
||||||
@ -230,15 +229,8 @@ const connect = async prms => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//Проверяем доступность пула
|
|
||||||
let tstConn = await pool.getConnection();
|
|
||||||
await tstConn.close();
|
|
||||||
//Всё ок - возвращяем его
|
|
||||||
return pool;
|
return pool;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//Закрываем пул, если успели открыть
|
|
||||||
if (pool) pool.close(NPOOL_DRAIN_TIME);
|
|
||||||
//Возвращаем ошибку
|
|
||||||
throw new Error(e.message);
|
throw new Error(e.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
const xml2js = require("xml2js"); //Конвертация XML в JSON и JSON в XML
|
const xml2js = require("xml2js"); //Конвертация XML в JSON и JSON в XML
|
||||||
const { httpRequest } = require("../core/http_client"); //Работа с HTTP/HTTPS запросами
|
const { httpRequest } = require("../core/http_client"); //Работа с HTTP/HTTPS запросами
|
||||||
const { SMCHD_STORAGE_SYSTEM, NCTX_EXP } = require("./sbis_config"); //Параметры работы расширения
|
const { SMCHD_STORAGE_SYSTEM } = require("./sbis_config"); //Система хранения МЧД
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
// Глобальные константы
|
// Глобальные константы
|
||||||
@ -138,7 +138,7 @@ const afterConnect = async prms => {
|
|||||||
return {
|
return {
|
||||||
blResp: Buffer.from(resp.result),
|
blResp: Buffer.from(resp.result),
|
||||||
sCtx: resp.result,
|
sCtx: resp.result,
|
||||||
dCtxExp: addHours(new Date(), NCTX_EXP)
|
dCtxExp: addHours(new Date(), 23)
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Сервер ЭДО "СБИС" вернул ошибку: ${resp.error.message ? resp.error.message : "Неожиданная ошибка"}`);
|
throw new Error(`Сервер ЭДО "СБИС" вернул ошибку: ${resp.error.message ? resp.error.message : "Неожиданная ошибка"}`);
|
||||||
|
|||||||
@ -9,6 +9,3 @@
|
|||||||
|
|
||||||
//Система хранения МЧД
|
//Система хранения МЧД
|
||||||
exports.SMCHD_STORAGE_SYSTEM = "https://m4d.nalog.gov.ru/EMCHD/check-status";
|
exports.SMCHD_STORAGE_SYSTEM = "https://m4d.nalog.gov.ru/EMCHD/check-status";
|
||||||
|
|
||||||
//Время жизни токена аутентификации (в часах)
|
|
||||||
exports.NCTX_EXP = 20;
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user