P8-ExchangeService/modules/parus_oracle_db.js

576 lines
20 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Сервис интеграции ПП Парус 8 с WEB API
Дополнительный модуль: работа с БД ПП Парус 8 (Oracle)
*/
//----------------------
// Подключение библиотек
//----------------------
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 DT_VARCHAR_LENGTH = 32767; //Длина типа "Строка"
//------------
// Тело модуля
//------------
//Формирование имени хранимого объекта БД (с параметрами)
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 makeStoredPrms = (inPrms, outPrms) => {
let prms = inPrms ? inPrms : {};
for (i in outPrms) {
prms[i] = {
type: outPrms[i],
dir: oracledb.BIND_OUT,
...(outPrms[i] === DT_VARCHAR ? { maxSize: DT_VARCHAR_LENGTH } : {})
};
break;
}
return prms;
};
//Исполнение хранимого объекта БД
const executeStored = async prms => {
let pooledConnection;
let outResult = {};
try {
pooledConnection = await prms.connection.getConnection();
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 {
if (pooledConnection) {
try {
await pooledConnection.close();
} catch (e) {
throw new Error(e.message);
}
}
}
if (outResult) return outResult;
};
//Проверка условий при запуске сервиса интеграции
const checkAppStart = async prms => {
let res = await executeStored({
connection: prms.connection,
sName: "PKG_EXS.UTL_APPSRV_START_CHECK",
inPrms: {
NCONTROL_VERSION: prms.bControlSystemVersion ? 1 : 0,
SEXS_RELEASE_DATE: prms.sRelease,
NWORKERS: prms.nWorkers,
SEXSSRV: prms.sServerName,
SMODULE_NAME: prms.sModuleName
},
outPrms: {
SERR_TEXT: DT_VARCHAR
},
isFunction: false
});
//Если есть ошибки запуска
if (res.SERR_TEXT) {
throw new Error(res.SERR_TEXT);
}
};
//Инициализация сервера интеграции
const initServer = async prms => {
let res = await executeStored({
connection: prms.connection,
sName: "PKG_EXS.EXSSRV_INIT",
inPrms: {
SEXSSRV: prms.sServerName,
SIP: prms.sServerIP,
NWORKERS: prms.nMaxWorkers
},
outPrms: {
NEXSSRV: DT_NUMBER
},
isFunction: false
});
//Если рег. номер сервера интеграции не определен
if (!res.NEXSSRV) {
throw new Error(`Ошибка считывания сервера интеграции с мнемокодом "${prms.sServerName}".`);
}
//Возвращаем рег. номер сервера интеграции
return res.NEXSSRV;
};
//Очистка информации о сервере при закрытии сервиса
const clearServer = async prms => {
await executeStored({
connection: prms.connection,
sName: "PKG_EXS.EXSSRV_CLEAR",
inPrms: {
NEXSSRV: prms.nExsSrv
},
isFunction: false
});
};
//Подключение к БД
const connect = async prms => {
try {
//Инициализируем результат подключения
let connection = { pool: null, nExsSrv: null };
//Определяем наименование модуля сессии
let moduleName = prms.connectSettings.exsSrv.sServerName
? `${prms.connectSettings.sSessionAppName}$${prms.connectSettings.exsSrv.sServerName}`
: prms.connectSettings.sSessionAppName;
//Создаем пул подключения
connection.pool = await oracledb.createPool({
user: prms.connectSettings.sUser,
password: prms.connectSettings.sPassword,
connectString: prms.connectSettings.sConnectString,
queueTimeout: 600000,
poolMin: prms.connectSettings.nPoolMin ? prms.connectSettings.nPoolMin : 4,
poolMax: prms.connectSettings.nPoolMax ? prms.connectSettings.nPoolMax : 4,
poolIncrement: prms.connectSettings.nPoolIncrement ? prms.connectSettings.nPoolIncrement : 0,
sessionCallback: (connection, requestedTag, callback) => {
connection.module = moduleName;
connection.execute(`ALTER SESSION SET CURRENT_SCHEMA=${prms.connectSettings.sSchema}`).then(
r => {
callback(null, connection);
},
e => {
callback(e, null);
}
);
}
});
//Если это запуск сервиса интеграции
if (prms.bServerStart) {
//Проверяем общие условия запуска
await checkAppStart({
bControlSystemVersion: prms.connectSettings.bControlSystemVersion,
sRelease: prms.connectSettings.sRelease,
nWorkers: prms.connectSettings.nMaxWorkers,
sServerName: prms.connectSettings.exsSrv.sServerName,
sModuleName: moduleName,
connection: connection.pool
});
//Если сервис интеграции разделяется на сервера
if (prms.connectSettings.exsSrv.sServerName) {
//Инициализируем информацию о сервере интеграции
connection.nExsSrv = await initServer({
sServerName: prms.connectSettings.exsSrv.sServerName,
sServerIP: prms.connectSettings.exsSrv.sServerIP,
nMaxWorkers: prms.connectSettings.nMaxWorkers,
connection: connection.pool
});
}
}
return connection;
} catch (e) {
throw new Error(e.message);
}
};
//Отключение от БД
const disconnect = async prms => {
try {
//Если указана информация о сервере и это закрытие сервиса интеграции
if (prms.nExsSrv && prms.bServerClose) {
//Очищаем информацию о сервере
await clearServer({ nExsSrv: prms.nExsSrv, connection: prms.connection });
}
//Отключаем от базы данных
await prms.connection.close(NPOOL_DRAIN_TIME);
return;
} catch (e) {
throw new Error(e.message);
}
};
//Получение списка сервисов
const getServices = async prms => {
let servicesData = await executeStored({
connection: prms.connection,
sName: "PKG_EXS.SERVICES_GET",
inPrms: {
NEXSSRV: prms.nExsSrv
},
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
},
isFunction: true
});
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,
NEXSSRV: prms.nExsSrv
},
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",
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,
NEXSSRV: prms.nExsSrv
},
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",
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",
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",
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",
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;