forked from CITKParus/P8-ExchangeService
Переход к реальной схеме аутентификации (транш второй)
This commit is contained in:
parent
01a3e88e6b
commit
1a64f7999b
@ -14,7 +14,7 @@ let dbConnect = {
|
||||
//Пароль пользователя БД
|
||||
sPassword: "parus",
|
||||
//Строка подключения к БД
|
||||
sConnectString: "DEMOP_CITKSERV",
|
||||
sConnectString: "DEMOP_CITKSERV_WAN",
|
||||
//Наименование сервера приложений в сессии БД
|
||||
sSessionAppName: "PARUS$ExchangeServer",
|
||||
//Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД)
|
||||
@ -24,7 +24,7 @@ let dbConnect = {
|
||||
//Параметры обработки очереди исходящих сообщений
|
||||
let outGoing = {
|
||||
//Количество одновременно обрабатываемых исходящих сообщений
|
||||
nMaxWorkers: 1,
|
||||
nMaxWorkers: 3,
|
||||
//Интервал проверки наличия исходящих сообщений (мс)
|
||||
nCheckTimeout: 1
|
||||
};
|
||||
|
@ -33,6 +33,7 @@ exports.SERR_MAIL_FAILED = "ERR_MAIL_FAILED"; //Ошибка отправки п
|
||||
//Типовые коды ошибок WEB-сервера
|
||||
exports.SERR_WEB_SERVER = "ERR_WEB_SERVER"; //Ошибка WEB-сервера
|
||||
|
||||
//Типовые коди ошибок пользовательских обработчиков сервера приложений
|
||||
//Типовые коди ошибок пользовательских обработчиков сервера приложений и сервера БД
|
||||
exports.SERR_APP_SERVER_BEFORE = "ERR_APP_SERVER_BEFORE"; //Ошибка предобработчика
|
||||
exports.SERR_APP_SERVER_AFTER = "ERR_APP_SERVER_AFTER"; //Ошибка постобработчика
|
||||
exports.SERR_DB_SERVER = "SERR_DB_SERVER"; //Ошибка обработчика сервера БД
|
||||
|
@ -139,7 +139,6 @@ class DBConnector extends EventEmitter {
|
||||
let srvs = await this.connector.getServices({ connection: this.connection });
|
||||
srvs.forEach(s => {
|
||||
s.functions = [];
|
||||
s.context = {};
|
||||
});
|
||||
//Валидируем его
|
||||
let sCheckResult = validateObject({ services: srvs }, objServicesSchema.Services, "Список сервисов");
|
||||
@ -760,14 +759,19 @@ class DBConnector extends EventEmitter {
|
||||
if (!sCheckResult) {
|
||||
//Исполняем действие в БД
|
||||
try {
|
||||
let res = await this.connector.execQueuePrc({
|
||||
nQueueId: prms.nQueueId,
|
||||
connection: this.connection
|
||||
});
|
||||
//Подготовим параметры для передачи в БД
|
||||
let execQueuePrcData = _.cloneDeep(prms);
|
||||
execQueuePrcData.connection = this.connection;
|
||||
//И выполним обработчик со стороны БД
|
||||
let res = await this.connector.execQueuePrc(execQueuePrcData);
|
||||
//Валидируем полученный ответ
|
||||
sCheckResult = validateObject(res, objQueueSchema.Queue, "Изменённое сообщение очереди обмена");
|
||||
sCheckResult = validateObject(
|
||||
res,
|
||||
objQueueSchema.QueuePrcResult,
|
||||
"Результат обработки очереди обмена"
|
||||
);
|
||||
if (sCheckResult) throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult);
|
||||
//Вернём измененную запись
|
||||
//Вернём результат обработки
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (e instanceof ServerError) throw e;
|
||||
|
@ -23,7 +23,9 @@ const {
|
||||
SERR_OBJECT_BAD_INTERFACE,
|
||||
SERR_WEB_SERVER,
|
||||
SERR_APP_SERVER_BEFORE,
|
||||
SERR_APP_SERVER_AFTER
|
||||
SERR_APP_SERVER_AFTER,
|
||||
SERR_DB_SERVER,
|
||||
SERR_UNAUTH
|
||||
} = require("./constants"); //Общесистемные константы
|
||||
|
||||
//--------------------------
|
||||
@ -144,7 +146,7 @@ class InQueue extends EventEmitter {
|
||||
nQueueId: q.nId,
|
||||
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_APP_OK
|
||||
});
|
||||
//Фиксируем успех исполнения
|
||||
//Фиксируем результат исполнения
|
||||
if (!_.isUndefined(resBefore.blMsg)) {
|
||||
blMsg = resBefore.blMsg;
|
||||
q = await this.dbConn.setQueueMsg({
|
||||
@ -159,6 +161,10 @@ class InQueue extends EventEmitter {
|
||||
blResp
|
||||
});
|
||||
}
|
||||
//Если пришел флаг ошибочной аутентификации и он положительный - то это ошибка, дальше ничего не делаем
|
||||
if (!_.isUndefined(resBefore.bUnAuth))
|
||||
if (resBefore.bUnAuth === true)
|
||||
throw new ServerError(SERR_UNAUTH, "Не аутентифицирован");
|
||||
} else {
|
||||
//Или расскажем об ошибке
|
||||
throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult);
|
||||
@ -173,7 +179,13 @@ class InQueue extends EventEmitter {
|
||||
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_DB
|
||||
});
|
||||
//Вызов обработчика БД
|
||||
q = await this.dbConn.execQueueDBPrc({ nQueueId: q.nId });
|
||||
let prcRes = await this.dbConn.execQueueDBPrc({ nQueueId: q.nId });
|
||||
//Если результат - ошибка пробрасываем её
|
||||
if (prcRes.sResult == objQueueSchema.SPRC_RESP_RESULT_ERR)
|
||||
throw new ServerError(SERR_DB_SERVER, prcRes.sMsg);
|
||||
//Если результат - ошибка аутентификации, то и её пробрасываем, но с правильным кодом
|
||||
if (prcRes.sResult == objQueueSchema.SPRC_RESP_RESULT_UNAUTH)
|
||||
throw new ServerError(SERR_UNAUTH, prcRes.sMsg || "Не аутентифицирован");
|
||||
//Выставим статус сообщению очереди - исполнено обработчиком БД
|
||||
q = await this.dbConn.setQueueState({
|
||||
nQueueId: q.nId,
|
||||
@ -216,7 +228,7 @@ class InQueue extends EventEmitter {
|
||||
nQueueId: q.nId,
|
||||
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_APP_OK
|
||||
});
|
||||
//Фиксируем успех исполнения
|
||||
//Фиксируем результат исполнения
|
||||
if (!_.isUndefined(resAfter.blResp)) {
|
||||
blResp = resAfter.blResp;
|
||||
q = await this.dbConn.setQueueResp({
|
||||
@ -224,6 +236,10 @@ class InQueue extends EventEmitter {
|
||||
blResp
|
||||
});
|
||||
}
|
||||
//Если пришел флаг ошибочной аутентификации и он положительный - то это ошибка, дальше ничего не делаем
|
||||
if (!_.isUndefined(resAfter.bUnAuth))
|
||||
if (resAfter.bUnAuth === true)
|
||||
throw new ServerError(SERR_UNAUTH, "Не аутентифицирован");
|
||||
} else {
|
||||
//Или расскажем об ошибке
|
||||
throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult);
|
||||
|
@ -220,9 +220,8 @@ class OutQueue extends EventEmitter {
|
||||
} else {
|
||||
//Ошибки обработки нет, но может быть есть ошибка аутентификации
|
||||
if (result.sResult == objOutQueueProcessorSchema.STASK_RESULT_UNAUTH) {
|
||||
//!!!!!!!!!!!!!!
|
||||
//??????????????
|
||||
//!!!!!!!!!!!!!!
|
||||
//Ставим задачу на аутентификацию сервиса
|
||||
await this.dbConn.putServiceAuthInQueue({ nServiceId: prms.queue.nServiceId });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -23,6 +23,7 @@ const {
|
||||
SERR_OBJECT_BAD_INTERFACE,
|
||||
SERR_APP_SERVER_BEFORE,
|
||||
SERR_APP_SERVER_AFTER,
|
||||
SERR_DB_SERVER,
|
||||
SERR_UNAUTH
|
||||
} = require("./constants"); //Глобальные константы
|
||||
const { NINC_EXEC_CNT_YES, NINC_EXEC_CNT_NO } = require("../models/prms_db_connector"); //Схемы валидации параметров функций модуля взаимодействия с БД
|
||||
@ -114,21 +115,23 @@ const appProcess = async prms => {
|
||||
let qData = await dbConn.getQueueMsg({ nQueueId: prms.queue.nId });
|
||||
//Считаем контекст сервиса
|
||||
let serviceCtx = await dbConn.getServiceContext({ nServiceId: prms.service.nId });
|
||||
//Флаг установленности контекста для функции начала сеанса
|
||||
let bCtxIsSet = false;
|
||||
//Кладём данные тела в объект сообщения и инициализируем поле для ответа
|
||||
_.extend(prms.queue, { blMsg: qData.blMsg, blResp: null });
|
||||
//Кладём данные контекста в сервис
|
||||
_.extend(prms.service, serviceCtx);
|
||||
//Собираем параметры для передачи серверу
|
||||
let options = { method: prms.service.sFnPrmsType };
|
||||
let options = { method: prms.function.sFnPrmsType };
|
||||
//Определимся с URL и телом сообщения в зависимости от способа передачи параметров
|
||||
if (prms.service.sFnPrmsType == objServiceFnSchema.NFN_PRMS_TYPE_POST) {
|
||||
if (prms.function.nFnPrmsType == objServiceFnSchema.NFN_PRMS_TYPE_POST) {
|
||||
options.url = buildURL({ sSrvRoot: prms.service.sSrvRoot, sFnURL: prms.function.sFnURL });
|
||||
options.body = prms.queue.blMsg;
|
||||
} else {
|
||||
options.url = buildURL({
|
||||
sSrvRoot: prms.service.sSrvRoot,
|
||||
sFnURL: prms.function.sFnURL,
|
||||
sQuery: prms.queue.blMsg.toString()
|
||||
sQuery: prms.queue.blMsg === null ? "" : prms.queue.blMsg.toString()
|
||||
});
|
||||
}
|
||||
//Выполняем обработчик "До" (если он есть)
|
||||
@ -150,26 +153,40 @@ const appProcess = async prms => {
|
||||
);
|
||||
//Если структура ответа в норме
|
||||
if (!sCheckResult) {
|
||||
//Применим её
|
||||
//Применим ответ "До" - обработанное сообщение очереди
|
||||
if (!_.isUndefined(resBefore.blMsg)) {
|
||||
prms.queue.blMsg = resBefore.blMsg;
|
||||
await dbConn.setQueueMsg({
|
||||
nQueueId: prms.queue.nId,
|
||||
blMsg: prms.queue.blMsg
|
||||
});
|
||||
if (prms.service.sFnPrmsType == objServiceFnSchema.NFN_PRMS_TYPE_POST) {
|
||||
if (prms.function.nFnPrmsType == objServiceFnSchema.NFN_PRMS_TYPE_POST) {
|
||||
options.body = prms.queue.blMsg;
|
||||
} else {
|
||||
options.url = buildURL({
|
||||
sSrvRoot: prms.service.sSrvRoot,
|
||||
sFnURL: prms.function.sFnURL,
|
||||
sQuery: prms.queue.blMsg.toString()
|
||||
sQuery: prms.queue.blMsg === null ? "" : prms.queue.blMsg.toString()
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!_.isUndefined(resBefore.options)) options = _.cloneDeep(resBefore.options);
|
||||
//Применим ответ "До" - параметры отправки сообщения удаленному серверу
|
||||
if (!_.isUndefined(resBefore.options)) _.extend(options, resBefore.options);
|
||||
//Применим ответ "До" - флаг отсуствия аутентификации
|
||||
if (!_.isUndefined(resBefore.bUnAuth))
|
||||
throw new ServerError(SERR_UNAUTH, "Не аутентифицирован");
|
||||
if (resBefore.bUnAuth === true) {
|
||||
throw new ServerError(SERR_UNAUTH, "Не аутентифицирован");
|
||||
}
|
||||
//Применим ответ "До" - контекст работы сервиса
|
||||
if (!_.isUndefined(resBefore.sCtx))
|
||||
if (prms.function.nFnType == objServiceFnSchema.NFN_TYPE_LOGIN) {
|
||||
await dbConn.setServiceContext({
|
||||
nServiceId: prms.service.nId,
|
||||
sCtx: resBefore.sCtx,
|
||||
dCtxExp: resBefore.dCtxExp
|
||||
});
|
||||
bCtxIsSet = true;
|
||||
}
|
||||
} else {
|
||||
//Или расскажем об ошибке в структуре ответа
|
||||
throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult);
|
||||
@ -207,7 +224,7 @@ const appProcess = async prms => {
|
||||
);
|
||||
//Если структура ответа в норме
|
||||
if (!sCheckResult) {
|
||||
//Применим её
|
||||
//Применим ответ "После" - обработанный ответ удаленного сервиса
|
||||
if (!_.isUndefined(resAfter.blResp)) {
|
||||
prms.queue.blResp = resAfter.blResp;
|
||||
await dbConn.setQueueResp({
|
||||
@ -215,14 +232,38 @@ const appProcess = async prms => {
|
||||
blResp: prms.queue.blResp
|
||||
});
|
||||
}
|
||||
//Применим ответ "После" - флаг утентификации сервиса
|
||||
if (!_.isUndefined(resAfter.bUnAuth))
|
||||
throw new ServerError(SERR_UNAUTH, "Не аутентифицирован");
|
||||
if (resAfter.bUnAuth === true)
|
||||
throw new ServerError(SERR_UNAUTH, "Не аутентифицирован");
|
||||
//Применим ответ "После" - контекст работы сервиса
|
||||
if (!_.isUndefined(resAfter.sCtx))
|
||||
if (prms.function.nFnType == objServiceFnSchema.NFN_TYPE_LOGIN) {
|
||||
await dbConn.setServiceContext({
|
||||
nServiceId: prms.service.nId,
|
||||
sCtx: resAfter.sCtx,
|
||||
dCtxExp: resAfter.dCtxExp
|
||||
});
|
||||
bCtxIsSet = true;
|
||||
}
|
||||
} else {
|
||||
//Или расскажем об ошибке в структуре ответа
|
||||
throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Если это функция начала сеанса, и нет обработчика на стороне БД и контекст не был установлен до сих пор - то положим в него то, что нам ответил сервер
|
||||
if (
|
||||
prms.function.nFnType == objServiceFnSchema.NFN_TYPE_LOGIN &&
|
||||
!prms.function.sPrcResp &&
|
||||
!bCtxIsSet
|
||||
) {
|
||||
await dbConn.setServiceContext({ nServiceId: prms.service.nId, sCtx: serverResp });
|
||||
}
|
||||
//Если это функция окончания сеанса, и нет обработчика на стороне БД - то сбросим контекст здесь
|
||||
if (prms.function.nFnType == objServiceFnSchema.NFN_TYPE_LOGOUT && !prms.function.sPrcResp) {
|
||||
await dbConn.clearServiceContext({ nServiceId: prms.service.nId });
|
||||
}
|
||||
//Фиксируем успешное исполнение сервером приложений - в статусе сообщения
|
||||
res = await dbConn.setQueueState({
|
||||
nQueueId: prms.queue.nId,
|
||||
@ -287,8 +328,17 @@ const dbProcess = async prms => {
|
||||
}, ${prms.queue.sExecState}, попытка исполнения - ${prms.queue.nExecCnt + 1}`,
|
||||
{ nQueueId: prms.queue.nId }
|
||||
);
|
||||
//Вызов обработчика БД
|
||||
res = await dbConn.execQueueDBPrc({ nQueueId: prms.queue.nId });
|
||||
//Если обработчик со стороны БД указан
|
||||
if (prms.function.sPrcResp) {
|
||||
//Вызываем его
|
||||
let prcRes = await dbConn.execQueueDBPrc({ nQueueId: prms.queue.nId });
|
||||
//Если результат - ошибка пробрасываем её
|
||||
if (prcRes.sResult == objQueueSchema.SPRC_RESP_RESULT_ERR)
|
||||
throw new ServerError(SERR_DB_SERVER, prcRes.sMsg);
|
||||
//Если результат - ошибка аутентификации, то и её пробрасываем, но с правильным кодом
|
||||
if (prcRes.sResult == objQueueSchema.SPRC_RESP_RESULT_UNAUTH)
|
||||
throw new ServerError(SERR_UNAUTH, prcRes.sMsg || "Не аутентифицирован");
|
||||
}
|
||||
//Фиксируем успешное исполнение (полное - дальше обработки нет) - в статусе сообщения
|
||||
res = await dbConn.setQueueState({
|
||||
nQueueId: prms.queue.nId,
|
||||
@ -351,8 +401,6 @@ const processTask = async prms => {
|
||||
await dbConn.connect();
|
||||
//Считываем запись очереди
|
||||
q = await dbConn.getQueue({ nQueueId: prms.task.nQueueId });
|
||||
//Выставим флаг - нет ошибок аутентификации на удаленном сервере
|
||||
let bUnAuthFlag = false;
|
||||
//Далее работаем от статуса считанной записи
|
||||
switch (q.nExecState) {
|
||||
//Статусы "Поставлено в очередь" или "Ошибка обработки сервером приложений"
|
||||
@ -361,60 +409,21 @@ const processTask = async prms => {
|
||||
//Если ещё не обрабатывали или есть ещё попытки отработки
|
||||
if (q.nExecCnt == 0 || q.nExecCnt < q.nRetryAttempts) {
|
||||
//Запускаем обработку сервером приложений
|
||||
try {
|
||||
let res = await appProcess({
|
||||
queue: q,
|
||||
service: prms.task.service,
|
||||
function: prms.task.function
|
||||
});
|
||||
//Если результат обработки - ошибка аутентификации
|
||||
if (res === objOutQueueProcessorSchema.STASK_RESULT_UNAUTH) {
|
||||
//Выставим флаг, который будет указывать на ошибку аутентификации
|
||||
bUnAuthFlag = true;
|
||||
} else {
|
||||
//Нет такой ошибки, посмотрим что прилетело сообщение в успешном статусе и тогда запустим обработку сервером БД
|
||||
if (res.nExecState == objQueueSchema.NQUEUE_EXEC_STATE_APP_OK) {
|
||||
try {
|
||||
await dbProcess({ queue: res });
|
||||
} catch (e) {
|
||||
//Фиксируем ошибку обработки сервером БД - в статусе сообщения
|
||||
await dbConn.setQueueState({
|
||||
nQueueId: res.nId,
|
||||
sExecMsg: makeErrorText(e),
|
||||
nIncExecCnt: NINC_EXEC_CNT_YES,
|
||||
nExecState:
|
||||
res.nExecCnt + 1 < res.nRetryAttempts
|
||||
? objQueueSchema.NQUEUE_EXEC_STATE_DB_ERR
|
||||
: objQueueSchema.NQUEUE_EXEC_STATE_ERR
|
||||
});
|
||||
//Фиксируем ошибку обработки сервером БД - в протоколе работы сервиса
|
||||
await logger.error(
|
||||
`Ошибка обработки исходящего сообщения ${
|
||||
res.nId
|
||||
} сервером БД: ${makeErrorText(e)}`,
|
||||
{ nQueueId: res.nId }
|
||||
);
|
||||
}
|
||||
}
|
||||
let res = await appProcess({
|
||||
queue: q,
|
||||
service: prms.task.service,
|
||||
function: prms.task.function
|
||||
});
|
||||
//Если результат обработки ошибка - пробрасываем её дальше
|
||||
if (res instanceof ServerError) {
|
||||
throw res;
|
||||
} else {
|
||||
//Нет ошибки, посмотрим что прилетело сообщение в успешном статусе и тогда запустим обработку сервером БД
|
||||
if (res.nExecState == objQueueSchema.NQUEUE_EXEC_STATE_APP_OK) {
|
||||
res = await dbProcess({ queue: res, function: prms.task.function });
|
||||
//Если результат обработки ошибка - пробрасываем её дальше
|
||||
if (res instanceof ServerError) throw res;
|
||||
}
|
||||
} catch (e) {
|
||||
//Фиксируем ошибку обработки сервером приложений - в статусе сообщения
|
||||
newQueue = await dbConn.setQueueState({
|
||||
nQueueId: q.nId,
|
||||
sExecMsg: makeErrorText(e),
|
||||
nIncExecCnt: NINC_EXEC_CNT_YES,
|
||||
nExecState:
|
||||
q.nExecCnt + 1 < q.nRetryAttempts
|
||||
? objQueueSchema.NQUEUE_EXEC_STATE_APP_ERR
|
||||
: objQueueSchema.NQUEUE_EXEC_STATE_ERR
|
||||
});
|
||||
//Фиксируем ошибку обработки сервером приложений - в протоколе работы сервиса
|
||||
await logger.error(
|
||||
`Ошибка обработки исходящего сообщения ${q.nId} сервером приложений: ${makeErrorText(
|
||||
e
|
||||
)}`,
|
||||
{ nQueueId: q.nId }
|
||||
);
|
||||
}
|
||||
} else {
|
||||
//Попыток нет - финализируем обработку
|
||||
@ -433,25 +442,9 @@ const processTask = async prms => {
|
||||
//Если ещё есть попытки отработки
|
||||
if (q.nExecCnt == 0 || q.nExecCnt < q.nRetryAttempts) {
|
||||
//Снова запускаем обработку сервером БД
|
||||
try {
|
||||
await dbProcess({ queue: q });
|
||||
} catch (e) {
|
||||
//Фиксируем ошибку обработки сервером БД - в статусе сообщения
|
||||
await dbConn.setQueueState({
|
||||
nQueueId: q.nId,
|
||||
sExecMsg: makeErrorText(e),
|
||||
nIncExecCnt: NINC_EXEC_CNT_YES,
|
||||
nExecState:
|
||||
q.nExecCnt + 1 < q.nRetryAttempts
|
||||
? objQueueSchema.NQUEUE_EXEC_STATE_DB_ERR
|
||||
: objQueueSchema.NQUEUE_EXEC_STATE_ERR
|
||||
});
|
||||
//Фиксируем ошибку обработки сервером БД - в протоколе работы сервиса
|
||||
await logger.error(
|
||||
`Ошибка обработки исходящего сообщения ${q.nId} сервером БД: ${makeErrorText(e)}`,
|
||||
{ nQueueId: q.nId }
|
||||
);
|
||||
}
|
||||
let res = await dbProcess({ queue: q, function: prms.task.function });
|
||||
//Если результат обработки ошибка - пробрасываем её дальше
|
||||
if (res instanceof ServerError) throw res;
|
||||
} else {
|
||||
//Попыток нет - финализируем обработку
|
||||
await dbConn.setQueueState({
|
||||
@ -493,14 +486,14 @@ const processTask = async prms => {
|
||||
}
|
||||
//Отключаемся от БД
|
||||
if (dbConn) await dbConn.disconnect();
|
||||
//Отправляем успех или ошибку аутентификации
|
||||
if (bUnAuthFlag) sendUnAuthResult();
|
||||
else sendOKResult();
|
||||
//Отправляем успех
|
||||
sendOKResult();
|
||||
} catch (e) {
|
||||
//Отключаемся от БД
|
||||
if (dbConn) await dbConn.disconnect();
|
||||
//Отправляем ошибку
|
||||
sendErrorResult({ sMessage: makeErrorText(e) });
|
||||
if (e instanceof ServerError && e.sCode == SERR_UNAUTH) sendUnAuthResult();
|
||||
else sendErrorResult({ sMessage: makeErrorText(e) });
|
||||
}
|
||||
} else {
|
||||
sendErrorResult({ sMessage: sCheckResult });
|
||||
|
342
db/PKG_EXS.pck
342
db/PKG_EXS.pck
@ -9,8 +9,11 @@ create or replace package PKG_EXS as
|
||||
SCONT_PRC constant PKG_STD.TSTRING := 'PRC'; -- Íàèìåíîâàíèå êîíòåéíåðà äëÿ ïàðàìåòðîâ ïðîöåññà
|
||||
|
||||
/* Êîíñòàíòû - ïîëÿ êîíòåéíåðîâ */
|
||||
SCONT_FLD_SERR constant PKG_STD.TSTRING := 'SERR'; -- Íàèìåíîâàíèå ïîëÿ êîíòåéíåðà äëÿ îøèáêè
|
||||
SCONT_FLD_BRESP constant PKG_STD.TSTRING := 'BRESP'; -- Íàèìåíîâàíèå ïîëÿ êîíòåéíåðà äëÿ ðåçóëüòàòà îáðàáîòêè
|
||||
SCONT_FLD_SRESULT constant PKG_STD.TSTRING := 'SRESULT'; -- Íàèìåíîâàíèå ïîëÿ êîíòåéíåðà äëÿ êîäà ðåçóëüòàòà îáðàáîòêè
|
||||
SCONT_FLD_SMSG constant PKG_STD.TSTRING := 'SMSG'; -- Íàèìåíîâàíèå ïîëÿ êîíòåéíåðà äëÿ ñîîáùåíèÿ îáðàáîòêè
|
||||
SCONT_FLD_BRESP constant PKG_STD.TSTRING := 'BRESP'; -- Íàèìåíîâàíèå ïîëÿ êîíòåéíåðà äëÿ ðåçóëüòàòà îáðàáîòêè
|
||||
SCONT_FLD_DCTX_EXP constant PKG_STD.TSTRING := 'DCTX_EXP'; -- Íàèìåíîâàíèå ïîëÿ êîíòåéíåðà äëÿ äàòû èñòå÷åíèÿ êîíòåêòñà ñåðâèñà
|
||||
SCONT_FLD_SCTX constant PKG_STD.TSTRING := 'SCTX'; -- Íàèìåíîâàíèå ïîëÿ êîíòåéíåðà äëÿ äëÿ êîíòåêñòà ñåðâèñà
|
||||
|
||||
/* Êîíñòàíòû - òèïû ñåðâèñîâ */
|
||||
NSRV_TYPE_SEND constant EXSSERVICE.SRV_TYPE%type := 0; -- Îòïðàâêà ñîîáùåíèé
|
||||
@ -108,8 +111,13 @@ create or replace package PKG_EXS as
|
||||
SAUTH_ONLY_YES constant varchar2(40) := 'AUTH_ONLY_YES'; -- Òðåáóåòñÿ àóòåíòèôèêàöèÿ (ñòðîêîâûé êîä)
|
||||
SAUTH_ONLY_NO constant varchar2(40) := 'AUTH_ONLY_NO'; -- Àóòåíòèôèêàöèÿ íå òðåáóåòñÿ (ñòðîêîâûé êîä)
|
||||
|
||||
/* Êîíñòàíòû - êîäû ðåçóëüòàòîâ èñïîëíåíèÿ îáðàáîò÷èêà ñîîáùåíèÿ */
|
||||
SPRC_RESP_RESULT_OK constant varchar2(40) := 'OK'; -- Îáðàáîòàíî óñïåøíî
|
||||
SPRC_RESP_RESULT_ERR constant varchar2(40) := 'ERR'; -- Îøèáêà îáðàáîòêè
|
||||
SPRC_RESP_RESULT_UNAUTH constant varchar2(40) := 'UNAUTH'; -- Íåàóòåíòèôèöèðîâàí
|
||||
|
||||
/* Êîíñòàíòû - îæèäàåìûé èíòåðôåéñ ïðîöåäóðû îáðàáîòêè ñîîáùåíèÿ î÷åðåäè íà ñòîðîíå ÁÄ */
|
||||
SPRC_RESP_ARGS constant varchar2(80) := 'NIDENT,IN,NUMBER;NSRV_TYPE,IN,NUMBER;NEXSQUEUE,IN,NUMBER;'; -- Ñïèñîê ïàðàìåòðîâ ïðîöåäóðû îáðàáîòêè
|
||||
SPRC_RESP_ARGS constant varchar2(80) := 'NIDENT,IN,NUMBER;NEXSQUEUE,IN,NUMBER;'; -- Ñïèñîê ïàðàìåòðîâ ïðîöåäóðû îáðàáîòêè
|
||||
|
||||
/* Ïðîâåðêà àêòèâíîñòè ñåðâåðà ïðèëîæåíèé */
|
||||
function UTL_APPSRV_IS_ACTIVE
|
||||
@ -223,6 +231,28 @@ create or replace package PKG_EXS as
|
||||
SARG in varchar2 -- Íàèìåíîâàíèå ïàðàìåòðà
|
||||
) return blob; -- Çíà÷åíèå ïàðàìåòðà
|
||||
|
||||
/* Óñòàíîâêà ðåçóëüòàòà èñïîëíåíèÿ îáðàáîò÷èêà */
|
||||
procedure PRC_RESP_RESULT_SET
|
||||
(
|
||||
NIDENT in number, -- Èäåíòèôèêàòîð ïðîöåññà
|
||||
SRESULT in varchar2 := SPRC_RESP_RESULT_OK, -- Êîä ðåçóëüòàòà (ñì. êîíñòàíòû SPRC_RESP_RESULT_*)
|
||||
BRESP in blob := null, -- Ðåçóëüòàò îáðàáîòêè
|
||||
SMSG in varchar2 := null, -- Ñîîáùåíèå îáðàáîò÷èêà
|
||||
SCTX in varchar2 := null, -- Êîíòåêñò
|
||||
DCTX_EXP in date := null -- Äàòà èñòå÷åíèÿ êîíòåêñòà
|
||||
);
|
||||
|
||||
/* Ñ÷èòûâàíèå ðåçóëüòàòà èñïîëíåíèÿ îáðàáîò÷èêà */
|
||||
procedure PRC_RESP_RESULT_GET
|
||||
(
|
||||
NIDENT in number, -- Èäåíòèôèêàòîð ïðîöåññà
|
||||
SRESULT out varchar2, -- Êîä ðåçóëüòàòà (ñì. êîíñòàíòû SPRC_RESP_RESULT_*)
|
||||
BRESP out blob, -- Ðåçóëüòàò îáðàáîòêè
|
||||
SMSG out varchar2, -- Ñîîáùåíèå îáðàáîò÷èêà
|
||||
SCTX out varchar2, -- Êîíòåêñò
|
||||
DCTX_EXP out date -- Äàòà èñòå÷åíèÿ êîíòåêñòà
|
||||
);
|
||||
|
||||
/* Áàçîâîå äîáàâëåíèå â áóôåð îòáîðà äîêóìåíòîâ */
|
||||
procedure RNLIST_BASE_INSERT
|
||||
(
|
||||
@ -269,9 +299,9 @@ create or replace package PKG_EXS as
|
||||
/* Óñòàíîâêà êîíòåêñòà ñåðâèñà */
|
||||
procedure SERVICE_CTX_SET
|
||||
(
|
||||
NEXSSERVICE in number, -- Ðåã. íîìåð çàïèñè ñåðâèñà
|
||||
SCTX in varchar2, -- Êîíòåêñò
|
||||
DCTX_EXP in date -- Äàòà èñòå÷åíèÿ êîíòåêñòà
|
||||
NEXSSERVICE in number, -- Ðåã. íîìåð çàïèñè ñåðâèñà
|
||||
SCTX in varchar2, -- Êîíòåêñò
|
||||
DCTX_EXP in date := null -- Äàòà èñòå÷åíèÿ êîíòåêñòà
|
||||
);
|
||||
|
||||
/* Î÷èñòêà êîíòåêñòà ñåðâèñà */
|
||||
@ -421,6 +451,13 @@ create or replace package PKG_EXS as
|
||||
|
||||
/* Óñòàíîâêà ðåçóëüòàòà îáðàáîòêè çàïèñè î÷åðåäè */
|
||||
procedure QUEUE_RESP_SET
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
BRESP in blob -- Ðåçóëüòàò îáðàáîòêè
|
||||
);
|
||||
|
||||
/* Óñòàíîâêà ðåçóëüòàòà îáðàáîòêè çàïèñè î÷åðåäè (âîçâðàùàåò èçìåíåííóþ ïîçèöèþ î÷åðåäè) */
|
||||
procedure QUEUE_RESP_SET
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
BRESP in blob, -- Ðåçóëüòàò îáðàáîòêè
|
||||
@ -436,6 +473,13 @@ create or replace package PKG_EXS as
|
||||
|
||||
/* Óñòàíîâêà ñîîáùåíèÿ çàïèñè î÷åðåäè */
|
||||
procedure QUEUE_MSG_SET
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
BMSG in blob -- Ðåçóëüòàò îáðàáîòêè
|
||||
);
|
||||
|
||||
/* Óñòàíîâêà ñîîáùåíèÿ çàïèñè î÷åðåäè (âîçâðàùàåò èçìåíåííóþ ïîçèöèþ î÷åðåäè) */
|
||||
procedure QUEUE_MSG_SET
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
BMSG in blob, -- Ðåçóëüòàò îáðàáîòêè
|
||||
@ -500,7 +544,7 @@ create or replace package PKG_EXS as
|
||||
procedure QUEUE_PRC
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
RCQUEUE out sys_refcursor -- Êóðñîð ñ îáðàáîòàííîé ïîçèöèåé î÷åðåäè
|
||||
RCRESULT out sys_refcursor -- Êóðñîð ñ ðåçóëüòàòàìè îáðàáîòêè
|
||||
);
|
||||
|
||||
end;
|
||||
@ -720,6 +764,10 @@ create or replace package body PKG_EXS as
|
||||
NARGS_LIST_CUR_CORRECT := 0;
|
||||
end if;
|
||||
end loop;
|
||||
/* Ïðîâåðèì ñîâïàäåíèå è ïî êîëè÷åñòâó */
|
||||
if (RARGS_LIST.COUNT <> RARGS_LIST_CUR.COUNT) then
|
||||
NARGS_LIST_CUR_CORRECT := 0;
|
||||
end if;
|
||||
/* Óñòàíîâêà ðåçóëüòàòà */
|
||||
NRESULT := NARGS_LIST_CUR_CORRECT;
|
||||
/* Óñòàíîâèì ñîîáùåíèå îá îæèäàåìîì èíòåðôåéñå */
|
||||
@ -1006,24 +1054,88 @@ create or replace package body PKG_EXS as
|
||||
SCONTAINER := UTL_CONTAINER_MAKE_NAME(NIDENT => NIDENT);
|
||||
/* Ñ÷èòàåì çíà÷åíèå èäåíòèôèêàòîðà áóôåðà èç êîíòåéíåðà */
|
||||
NFILE_IDENT := PKG_CONTVARGLB.GETN(SCONTAINER => SCONTAINER, SNAME => SARG);
|
||||
/* Çàáåðåì ðåçóëüòàòû îáðàáîòêè èç ôàéëîâîãî áóôåðà */
|
||||
begin
|
||||
select T.BDATA into BRESP from FILE_BUFFER T where T.IDENT = NFILE_IDENT;
|
||||
exception
|
||||
when NO_DATA_FOUND then
|
||||
P_EXCEPTION(0,
|
||||
'Ðåçóëüòàòû îáðàáîòêè íå íàéäåíû â áóôåðå (IDENT: %s).',
|
||||
TO_CHAR(NFILE_IDENT));
|
||||
when TOO_MANY_ROWS then
|
||||
P_EXCEPTION(0,
|
||||
'Ðåçóëüòàòû îáðàáîòêè íå îïðåäåëåíû îäíîçíà÷íî (IDENT: %s).',
|
||||
TO_CHAR(NFILE_IDENT));
|
||||
end;
|
||||
/* Çà÷èñòèì ôàéëîâûé áóôåð */
|
||||
P_FILE_BUFFER_CLEAR(NIDENT => NFILE_IDENT);
|
||||
/* Åñëè èäåíòèôèêàòîð áóôåðà áûë â êîíòåéíåðå */
|
||||
if (NFILE_IDENT is not null) then
|
||||
/* Çàáåðåì ðåçóëüòàòû îáðàáîòêè èç ôàéëîâîãî áóôåðà */
|
||||
begin
|
||||
select T.BDATA into BRESP from FILE_BUFFER T where T.IDENT = NFILE_IDENT;
|
||||
exception
|
||||
when NO_DATA_FOUND then
|
||||
P_EXCEPTION(0,
|
||||
'Ðåçóëüòàòû îáðàáîòêè íå íàéäåíû â áóôåðå (IDENT: %s).',
|
||||
TO_CHAR(NFILE_IDENT));
|
||||
when TOO_MANY_ROWS then
|
||||
P_EXCEPTION(0,
|
||||
'Ðåçóëüòàòû îáðàáîòêè íå îïðåäåëåíû îäíîçíà÷íî (IDENT: %s).',
|
||||
TO_CHAR(NFILE_IDENT));
|
||||
end;
|
||||
/* Çà÷èñòèì ôàéëîâûé áóôåð */
|
||||
P_FILE_BUFFER_CLEAR(NIDENT => NFILE_IDENT);
|
||||
else
|
||||
/* Èäåíòèôèêàòîð áóôåðà â êîíòåéíåðå îòñóòñòâîâàë - äàííûõ íåò */
|
||||
BRESP := null;
|
||||
end if;
|
||||
/* Âåðí¸ì çíà÷åíèå */
|
||||
return BRESP;
|
||||
end PRC_RESP_ARG_BLOB_GET;
|
||||
|
||||
/* Óñòàíîâêà ðåçóëüòàòà èñïîëíåíèÿ îáðàáîò÷èêà */
|
||||
procedure PRC_RESP_RESULT_SET
|
||||
(
|
||||
NIDENT in number, -- Èäåíòèôèêàòîð ïðîöåññà
|
||||
SRESULT in varchar2 := SPRC_RESP_RESULT_OK, -- Êîä ðåçóëüòàòà (ñì. êîíñòàíòû SPRC_RESP_RESULT_*)
|
||||
BRESP in blob := null, -- Äàííûå îòâåòà
|
||||
SMSG in varchar2 := null, -- Ñîîáùåíèå îáðàáîò÷èêà
|
||||
SCTX in varchar2 := null, -- Êîíòåêñò
|
||||
DCTX_EXP in date := null -- Äàòà èñòå÷åíèÿ êîíòåêñòà
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Ïðîâåðèì ïàðàìåòðû */
|
||||
if (SRESULT is not null) then
|
||||
if (SRESULT not in (SPRC_RESP_RESULT_OK, SPRC_RESP_RESULT_ERR, SPRC_RESP_RESULT_UNAUTH)) then
|
||||
P_EXCEPTION(0,
|
||||
'Êîä ðåçóëüòàòà èñïîëíåíèÿ îáðàáîò÷èêà "%s" íå ïîääåðæèâàåòñÿ',
|
||||
SRESULT);
|
||||
end if;
|
||||
else
|
||||
P_EXCEPTION(0, 'Íå óêàçàí êîä ðåçóëüòàòà èñïîëíåíèÿ îáðàáîò÷èêà');
|
||||
end if;
|
||||
/* Ñîõðàíÿåì êîä ðåçóëüòàòà */
|
||||
PRC_RESP_ARG_STR_SET(NIDENT => NIDENT, SARG => SCONT_FLD_SRESULT, SVALUE => SRESULT);
|
||||
/* Ñîõðàíÿåì äàííûå îòâåòà */
|
||||
PRC_RESP_ARG_BLOB_SET(NIDENT => NIDENT, SARG => SCONT_FLD_BRESP, BVALUE => BRESP);
|
||||
/* Ñîõðàíÿåì ñîîáùåíèå îáðàáîò÷èêà */
|
||||
PRC_RESP_ARG_STR_SET(NIDENT => NIDENT, SARG => SCONT_FLD_SMSG, SVALUE => SMSG);
|
||||
/* Ñîõðàíÿåì êîíòåêñò */
|
||||
PRC_RESP_ARG_STR_SET(NIDENT => NIDENT, SARG => SCONT_FLD_SCTX, SVALUE => SCTX);
|
||||
/* Ñîõðàíÿåì äàòó èñòå÷åíèÿ êîíòåêñòà */
|
||||
PRC_RESP_ARG_DATE_SET(NIDENT => NIDENT, SARG => SCONT_FLD_DCTX_EXP, DVALUE => DCTX_EXP);
|
||||
end PRC_RESP_RESULT_SET;
|
||||
|
||||
/* Ñ÷èòûâàíèå ðåçóëüòàòà èñïîëíåíèÿ îáðàáîò÷èêà */
|
||||
procedure PRC_RESP_RESULT_GET
|
||||
(
|
||||
NIDENT in number, -- Èäåíòèôèêàòîð ïðîöåññà
|
||||
SRESULT out varchar2, -- Êîä ðåçóëüòàòà (ñì. êîíñòàíòû SPRC_RESP_RESULT_*)
|
||||
BRESP out blob, -- Äàííûå îòâåòà
|
||||
SMSG out varchar2, -- Ñîîáùåíèå îáðàáîò÷èêà
|
||||
SCTX out varchar2, -- Êîíòåêñò
|
||||
DCTX_EXP out date -- Äàòà èñòå÷åíèÿ êîíòåêñòà
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Ñ÷èòàåì êîä ðåçóëüòàòà */
|
||||
SRESULT := PRC_RESP_ARG_STR_GET(NIDENT => NIDENT, SARG => SCONT_FLD_SRESULT);
|
||||
/* Ñ÷èòàåì äàííûå îòâåòà */
|
||||
BRESP := PRC_RESP_ARG_BLOB_GET(NIDENT => NIDENT, SARG => SCONT_FLD_BRESP);
|
||||
/* Ñ÷èòàåì ñîîáùåíèå îáðàáîò÷èêà */
|
||||
SMSG := PRC_RESP_ARG_STR_GET(NIDENT => NIDENT, SARG => SCONT_FLD_SMSG);
|
||||
/* Ñ÷èòàåì êîíòåêñò */
|
||||
SCTX := PRC_RESP_ARG_STR_GET(NIDENT => NIDENT, SARG => SCONT_FLD_SCTX);
|
||||
/* Ñ÷èòàåì äàòó èñòå÷åíèÿ êîíòåêñòà */
|
||||
DCTX_EXP := PRC_RESP_ARG_DATE_GET(NIDENT => NIDENT, SARG => SCONT_FLD_DCTX_EXP);
|
||||
end PRC_RESP_RESULT_GET;
|
||||
|
||||
/* Áàçîâîå äîáàâëåíèå â áóôåð îòáîðà äîêóìåíòîâ */
|
||||
procedure RNLIST_BASE_INSERT
|
||||
@ -1149,7 +1261,7 @@ create or replace package body PKG_EXS as
|
||||
(
|
||||
NEXSSERVICE in number, -- Ðåã. íîìåð çàïèñè ñåðâèñà
|
||||
SCTX in varchar2, -- Êîíòåêñò
|
||||
DCTX_EXP in date -- Äàòà èñòå÷åíèÿ êîíòåêñòà
|
||||
DCTX_EXP in date := null -- Äàòà èñòå÷åíèÿ êîíòåêñòà
|
||||
)
|
||||
is
|
||||
REXSSERVICE EXSSERVICE%rowtype; -- Çàïèñü ñåðâèñà
|
||||
@ -1386,7 +1498,7 @@ create or replace package body PKG_EXS as
|
||||
SRETRY_SCHEDULE_MONTH) "sRetrySchedule",
|
||||
T.EXSMSGTYPE "nMsgId",
|
||||
M.CODE "sMsgCode",
|
||||
DECODE(M.PRC_RESP, null, null, UTL_STORED_MAKE_LINK(SPROCEDURE => M.PRC_RESP, SPACKAGE => M.PKG_RESP)) "sPrcResp",
|
||||
DECODE(M.PRC_RESP, null, null, UTL_STORED_MAKE_LINK(M.PRC_RESP, M.PKG_RESP)) "sPrcResp",
|
||||
M.APPSRV_BEFORE "sAppSrvBefore",
|
||||
M.APPSRV_AFTER "sAppSrvAfter",
|
||||
T.AUTH_ONLY "nAuthOnly",
|
||||
@ -1833,9 +1945,24 @@ create or replace package body PKG_EXS as
|
||||
open RCQUEUE_RESP for
|
||||
select REXSQUEUE.RESP "blResp" from DUAL;
|
||||
end QUEUE_RESP_GET;
|
||||
|
||||
|
||||
/* Óñòàíîâêà ðåçóëüòàòà îáðàáîòêè çàïèñè î÷åðåäè */
|
||||
procedure QUEUE_RESP_SET
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
BRESP in blob -- Ðåçóëüòàò îáðàáîòêè
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Âûñòàâèì ðåçóëüòàò */
|
||||
update EXSQUEUE T set T.RESP = BRESP where T.RN = NEXSQUEUE;
|
||||
if (sql%rowcount = 0) then
|
||||
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEXSQUEUE, SUNIT_TABLE => 'EXSQUEUE');
|
||||
end if;
|
||||
end QUEUE_RESP_SET;
|
||||
|
||||
/* Óñòàíîâêà ðåçóëüòàòà îáðàáîòêè çàïèñè î÷åðåäè (âîçâðàùàåò èçìåíåííóþ ïîçèöèþ î÷åðåäè) */
|
||||
procedure QUEUE_RESP_SET
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
BRESP in blob, -- Ðåçóëüòàò îáðàáîòêè
|
||||
@ -1844,10 +1971,7 @@ create or replace package body PKG_EXS as
|
||||
is
|
||||
begin
|
||||
/* Âûñòàâèì ðåçóëüòàò */
|
||||
update EXSQUEUE T set T.RESP = BRESP where T.RN = NEXSQUEUE;
|
||||
if (sql%rowcount = 0) then
|
||||
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEXSQUEUE, SUNIT_TABLE => 'EXSQUEUE');
|
||||
end if;
|
||||
QUEUE_RESP_SET(NEXSQUEUE => NEXSQUEUE, BRESP => BRESP);
|
||||
/* Âåðíåì èçìåíåííóþ ïîçèöèþ î÷åðåäè */
|
||||
QUEUE_GET(NFLAG_SMART => 0, NEXSQUEUE => NEXSQUEUE, RCQUEUE => RCQUEUE);
|
||||
end QUEUE_RESP_SET;
|
||||
@ -1867,9 +1991,24 @@ create or replace package body PKG_EXS as
|
||||
open RCQUEUE_MSG for
|
||||
select REXSQUEUE.MSG "blMsg" from DUAL;
|
||||
end QUEUE_MSG_GET;
|
||||
|
||||
|
||||
/* Óñòàíîâêà ñîîáùåíèÿ çàïèñè î÷åðåäè */
|
||||
procedure QUEUE_MSG_SET
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
BMSG in blob -- Ðåçóëüòàò îáðàáîòêè
|
||||
)
|
||||
is
|
||||
begin
|
||||
/* Âûñòàâèì ñîîáùåíèå */
|
||||
update EXSQUEUE T set T.MSG = BMSG where T.RN = NEXSQUEUE;
|
||||
if (sql%rowcount = 0) then
|
||||
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEXSQUEUE, SUNIT_TABLE => 'EXSQUEUE');
|
||||
end if;
|
||||
end QUEUE_MSG_SET;
|
||||
|
||||
/* Óñòàíîâêà ñîîáùåíèÿ çàïèñè î÷åðåäè (âîçâðàùàåò èçìåíåííóþ ïîçèöèþ î÷åðåäè) */
|
||||
procedure QUEUE_MSG_SET
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
BMSG in blob, -- Ðåçóëüòàò îáðàáîòêè
|
||||
@ -1878,10 +2017,7 @@ create or replace package body PKG_EXS as
|
||||
is
|
||||
begin
|
||||
/* Âûñòàâèì ñîîáùåíèå */
|
||||
update EXSQUEUE T set T.MSG = BMSG where T.RN = NEXSQUEUE;
|
||||
if (sql%rowcount = 0) then
|
||||
PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEXSQUEUE, SUNIT_TABLE => 'EXSQUEUE');
|
||||
end if;
|
||||
QUEUE_MSG_SET(NEXSQUEUE => NEXSQUEUE, BMSG => BMSG);
|
||||
/* Âåðíåì èçìåíåííóþ ïîçèöèþ î÷åðåäè */
|
||||
QUEUE_GET(NFLAG_SMART => 0, NEXSQUEUE => NEXSQUEUE, RCQUEUE => RCQUEUE);
|
||||
end QUEUE_MSG_SET;
|
||||
@ -2036,15 +2172,19 @@ create or replace package body PKG_EXS as
|
||||
procedure QUEUE_PRC
|
||||
(
|
||||
NEXSQUEUE in number, -- Ðåã. íîìåð çàïèñè î÷åðåäè
|
||||
RCQUEUE out sys_refcursor -- Êóðñîð ñ îáðàáîòàííîé ïîçèöèåé î÷åðåäè
|
||||
RCRESULT out sys_refcursor -- Êóðñîð ñ ðåçóëüòàòàìè îáðàáîòêè
|
||||
)
|
||||
is
|
||||
REXSQUEUE EXSQUEUE%rowtype; -- Çàïèñü ïîçèöèè î÷åðåäè
|
||||
REXSSERVICE EXSSERVICE%rowtype; -- Çàïèñü ñåðâèñà îáðàáîòêè
|
||||
REXSSERVICEFN EXSSERVICEFN%rowtype; -- Çàïèñü ôóíêöèè îáðàáîòêè
|
||||
REXSMSGTYPE EXSMSGTYPE%rowtype; -- Çàïèñü òèïîâîãî ñîîáùåíèÿ îáìåíà
|
||||
SERR EXSQUEUE.EXEC_MSG%type; -- Ñîîáùåíèå îá îøèáêå îáðàáîò÷èêà
|
||||
REXSMSGTYPE EXSMSGTYPE%rowtype; -- Çàïèñü òèïîâîãî ñîîáùåíèÿ îáìåíà
|
||||
NIDENT PKG_STD.TREF; -- Èäåíòèôèêàòîð ïðîöåññà îáðàáîòêè
|
||||
SRESULT PKG_STD.TSTRING; -- Áóôåð äëÿ ðåçóëüòàòà: êîä ðåçóëüòàòà
|
||||
BRESP blob; -- Áóôåð äëÿ ðåçóëüòàòà: äàííûå îòâåòà
|
||||
SMSG PKG_STD.TSTRING; -- Áóôåð äëÿ ðåçóëüòàòà: ñîîáùåíèå îáðàáîò÷èêà
|
||||
SCTX PKG_STD.TSTRING; -- Áóôåð äëÿ ðåçóëüòàòà: êîíòåêñò
|
||||
DCTX_EXP PKG_STD.TLDATE; -- Áóôåð äëÿ ðåçóëüòàòà: äàòà èñòå÷åíèÿ êîíòåêñòà
|
||||
PRMS PKG_CONTPRMLOC.TCONTAINER; -- Êîíòåéíåð äëÿ ïàðàìåòðîâ ïðîöåäóðû îáðàáîòêè
|
||||
begin
|
||||
/* Ñ÷èòàåì çàïèñü î÷åðåäè */
|
||||
@ -2057,49 +2197,95 @@ create or replace package body PKG_EXS as
|
||||
REXSMSGTYPE := GET_EXSMSGTYPE_ID(NFLAG_SMART => 0, NRN => REXSSERVICEFN.EXSMSGTYPE);
|
||||
/* Çàïóñòèì îáðàáîò÷èê, åñëè îí åñòü */
|
||||
if (REXSMSGTYPE.PRC_RESP is not null) then
|
||||
/* Ïðîâåðÿåì èíòåðôåéñ îáðàáîò÷èêà */
|
||||
UTL_STORED_CHECK(NFLAG_SMART => 0,
|
||||
SPKG => REXSMSGTYPE.PKG_RESP,
|
||||
SPRC => REXSMSGTYPE.PRC_RESP,
|
||||
SARGS => SPRC_RESP_ARGS,
|
||||
NRESULT => NIDENT);
|
||||
/* Ôîðìèðóåì èäåíòèôèêàòîð ïðîöåññà */
|
||||
NIDENT := GEN_IDENT();
|
||||
/* Óñòàíîâèì çíà÷åíèÿ ôèêñèðîâàííûõ âõîäíûõ ïàðàìåòðîâ */
|
||||
PKG_CONTPRMLOC.APPENDN(RCONTAINER => PRMS,
|
||||
SNAME => 'NIDENT',
|
||||
NVALUE => NIDENT,
|
||||
NIN_OUT => PKG_STD.IPARAM_TYPE_IN);
|
||||
PKG_CONTPRMLOC.APPENDN(RCONTAINER => PRMS,
|
||||
SNAME => 'NSRV_TYPE',
|
||||
NVALUE => REXSSERVICE.SRV_TYPE,
|
||||
NIN_OUT => PKG_STD.IPARAM_TYPE_IN);
|
||||
PKG_CONTPRMLOC.APPENDN(RCONTAINER => PRMS,
|
||||
SNAME => 'NEXSQUEUE',
|
||||
NVALUE => REXSQUEUE.RN,
|
||||
NIN_OUT => PKG_STD.IPARAM_TYPE_IN);
|
||||
/* Èñïîëíÿåì ïðîöåäóðó */
|
||||
PKG_SQL_CALL.EXECUTE_STORED(SSTORED_NAME => UTL_STORED_MAKE_LINK(SPACKAGE => REXSMSGTYPE.PKG_RESP,
|
||||
SPROCEDURE => REXSMSGTYPE.PRC_RESP),
|
||||
RPARAM_CONTAINER => PRMS);
|
||||
/* Çàáèðàåì ïàðàìåòð ñ îøèáêàìè îáðàáîò÷èêà */
|
||||
SERR := PRC_RESP_ARG_STR_GET(NIDENT => NIDENT, SARG => SCONT_FLD_SERR);
|
||||
/* Åñëè áûëè îøèáêè - ñêàæåì îá ýòîì */
|
||||
if (SERR is not null) then
|
||||
P_EXCEPTION(0, SERR);
|
||||
else
|
||||
/* Çàôèêñèðóåì ðåçóëüòàò îáðàáîòêè (òîëüêî äëÿ âõîäÿùèõ è òîëüêî åñëè íåò îøèáîê îáðàáîòêè) */
|
||||
if (REXSSERVICE.SRV_TYPE = NSRV_TYPE_RECIVE) then
|
||||
QUEUE_RESP_SET(NEXSQUEUE => REXSQUEUE.RN,
|
||||
BRESP => PRC_RESP_ARG_BLOB_GET(NIDENT => NIDENT, SARG => SCONT_FLD_BRESP),
|
||||
RCQUEUE => RCQUEUE);
|
||||
begin
|
||||
/* Ïðîâåðÿåì èíòåðôåéñ îáðàáîò÷èêà */
|
||||
UTL_STORED_CHECK(NFLAG_SMART => 0,
|
||||
SPKG => REXSMSGTYPE.PKG_RESP,
|
||||
SPRC => REXSMSGTYPE.PRC_RESP,
|
||||
SARGS => SPRC_RESP_ARGS,
|
||||
NRESULT => NIDENT);
|
||||
/* Ôîðìèðóåì èäåíòèôèêàòîð ïðîöåññà */
|
||||
NIDENT := GEN_IDENT();
|
||||
/* Óñòàíîâèì çíà÷åíèÿ ôèêñèðîâàííûõ âõîäíûõ ïàðàìåòðîâ */
|
||||
PKG_CONTPRMLOC.APPENDN(RCONTAINER => PRMS,
|
||||
SNAME => 'NIDENT',
|
||||
NVALUE => NIDENT,
|
||||
NIN_OUT => PKG_STD.IPARAM_TYPE_IN);
|
||||
PKG_CONTPRMLOC.APPENDN(RCONTAINER => PRMS,
|
||||
SNAME => 'NEXSQUEUE',
|
||||
NVALUE => REXSQUEUE.RN,
|
||||
NIN_OUT => PKG_STD.IPARAM_TYPE_IN);
|
||||
/* Èñïîëíÿåì ïðîöåäóðó */
|
||||
PKG_SQL_CALL.EXECUTE_STORED(SSTORED_NAME => UTL_STORED_MAKE_LINK(SPACKAGE => REXSMSGTYPE.PKG_RESP,
|
||||
SPROCEDURE => REXSMSGTYPE.PRC_RESP),
|
||||
RPARAM_CONTAINER => PRMS);
|
||||
/* Î÷èñòèì êîíòåéíåð ïàðàìåòðîâ */
|
||||
PKG_CONTPRMLOC.PURGE(RCONTAINER => PRMS);
|
||||
/* Çàáèðàåì ðåçóëüòàòû */
|
||||
PRC_RESP_RESULT_GET(NIDENT => NIDENT,
|
||||
SRESULT => SRESULT,
|
||||
BRESP => BRESP,
|
||||
SMSG => SMSG,
|
||||
SCTX => SCTX,
|
||||
DCTX_EXP => DCTX_EXP);
|
||||
/* Åñëè êîä ðåçóëüòàòà óñòàíîâëåí */
|
||||
if (SRESULT is not null) then
|
||||
/* È åñëè ðåçóëüòàò óñïåøåí - ïðèìåíèì åãî */
|
||||
if (SRESULT = SPRC_RESP_RESULT_OK) then
|
||||
/* Çàôèêñèðóåì ðåçóëüòàò îáðàáîòêè (äëÿ âõîäÿùèõ - âñåãäà, äëÿ èñõîäÿùèõ - òîëüêî åñëè íå ïóñòîé) */
|
||||
if ((REXSSERVICE.SRV_TYPE = NSRV_TYPE_RECIVE) or
|
||||
((REXSSERVICE.SRV_TYPE = NSRV_TYPE_SEND) and (BRESP is not null) and (DBMS_LOB.GETLENGTH(BRESP) > 0))) then
|
||||
QUEUE_RESP_SET(NEXSQUEUE => REXSQUEUE.RN, BRESP => BRESP);
|
||||
end if;
|
||||
/* Åñëè ýòî áûëà ôóíêöèÿ íà÷àëà ñåàíñà */
|
||||
if (REXSSERVICEFN.FN_TYPE = NFN_TYPE_LOGIN) then
|
||||
/* Åñëè îáðàáîò÷èê âåðíóë êîíòåêñò */
|
||||
if (SCTX is not null) then
|
||||
/* Ïðîïèøåì åãî ñåðâèñó, âíå çàâèñèìîñòè îò òîãî, ÷òî òàì áûëî äî ýòîãî */
|
||||
SERVICE_CTX_SET(NEXSSERVICE => REXSSERVICE.RN, SCTX => SCTX, DCTX_EXP => DCTX_EXP);
|
||||
else
|
||||
/* Îáðàáîò÷èê íå âåðíóë êîíòåêñòà, ïðîâåðèì, åñòü ëè îí ñåé÷àñ ó ñåðâèñà */
|
||||
REXSSERVICE := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => REXSSERVICEFN.PRN);
|
||||
if (REXSSERVICE.CTX is null) then
|
||||
/* Îáðàáîò÷èê íå âåðíóë êîíòåêñò è ñåé÷àñ îí íå óñòàíîâëåí äëÿ ñåðâèñà, ýòî ïðîáëåìà - áîëüøå îáðàáîòîê íå áóäåò çíà÷èò ìû íå çàëîãèíèëèñü */
|
||||
P_EXCEPTION(0,
|
||||
'Ôóíêöèÿ íà÷àëà ñåàíñà "%s" íå óñòàíîâèëà êîíòåêñò ðàáîòû äëÿ ñåðâèñà "%s"',
|
||||
REXSSERVICEFN.CODE,
|
||||
REXSSERVICE.CODE);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
/* Åñëè ýòî áûëà ôóíêöèÿ çàâåðøåíèÿ ñåàíñà */
|
||||
if (REXSSERVICEFN.FN_TYPE = NFN_TYPE_LOGOUT) then
|
||||
/* Óäàëèì êîíòåêñò ñåðâèñà */
|
||||
SERVICE_CTX_CLEAR(NEXSSERVICE => REXSSERVICE.RN);
|
||||
end if;
|
||||
else
|
||||
/* Âî âñåõ îñòàëüíûõ ñëó÷àÿõ - îòêàòûâàåì òðàíçàêöèþ, ò.ê. åñòü êàêèå-òî îøèáêè îáðàáîòêè */
|
||||
rollback;
|
||||
end if;
|
||||
else
|
||||
/* Ðåçóëüòàò íå óñòàíîâëåí - ýòî îøèáêà */
|
||||
P_EXCEPTION(0,
|
||||
'Ïðîöåäóðà îáðàáîò÷èê "%s" íå âåðíóëà ðåçóëüòàò ðàáîòû',
|
||||
UTL_STORED_MAKE_LINK(SPACKAGE => REXSMSGTYPE.PKG_RESP, SPROCEDURE => REXSMSGTYPE.PRC_RESP));
|
||||
end if;
|
||||
end if;
|
||||
/* Î÷èñòèì êîíòåéíåð ïàðàìåòðîâ */
|
||||
PKG_CONTPRMLOC.PURGE(RCONTAINER => PRMS);
|
||||
exception
|
||||
when others then
|
||||
rollback;
|
||||
SRESULT := SPRC_RESP_RESULT_ERR;
|
||||
SMSG := sqlerrm;
|
||||
end;
|
||||
else
|
||||
/* Îáðàáîò÷èêà íåò è íåò ïðîáëåì */
|
||||
SRESULT := SPRC_RESP_RESULT_OK;
|
||||
SMSG := null;
|
||||
end if;
|
||||
/* Âîçâðàùàåì îáðàáîòàííóþ ïîçèöèþ î÷åðåäè */
|
||||
QUEUE_GET(NFLAG_SMART => 0, NEXSQUEUE => REXSQUEUE.RN, RCQUEUE => RCQUEUE);
|
||||
/* Âîçâðàùàåì ðåçóëüòàò â âèäå êóðñîðà */
|
||||
open RCRESULT for
|
||||
select SRESULT "sResult",
|
||||
SMSG "sMsg"
|
||||
from DUAL;
|
||||
end QUEUE_PRC;
|
||||
|
||||
end;
|
||||
|
@ -33,6 +33,16 @@ exports.InQueueProcessorFnBefore = new Schema({
|
||||
type: path => `Ответ системы (${path}) имеет некорректный тип данных (ожидалось - Buffer)`,
|
||||
required: path => `Не указан ответ системы (${path})`
|
||||
}
|
||||
},
|
||||
//Флаг ошибки аутентификации удаленного клиента
|
||||
bUnAuth: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
message: {
|
||||
type: path =>
|
||||
`Флаг ошибки аутентификации удаленного клиента (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
|
||||
required: path => `Не указан флаг ошибки аутентификации удаленного клиента (${path})`
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -46,5 +56,15 @@ exports.InQueueProcessorFnAfter = new Schema({
|
||||
type: path => `Обработанный ответ системы (${path}) имеет некорректный тип данных (ожидалось - Buffer)`,
|
||||
required: path => `Не указан обработанный ответ системы (${path})`
|
||||
}
|
||||
},
|
||||
//Флаг ошибки аутентификации удаленного клиента
|
||||
bUnAuth: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
message: {
|
||||
type: path =>
|
||||
`Флаг ошибки аутентификации удаленного клиента (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
|
||||
required: path => `Не указан флаг ошибки аутентификации удаленного клиента (${path})`
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -127,6 +127,24 @@ exports.OutQueueProcessorFnBefore = new Schema({
|
||||
`Флаг ошибки аутентификации на удаленном сервисе (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
|
||||
required: path => `Не указан флаг ошибки аутентификации на удаленном сервисе (${path})`
|
||||
}
|
||||
},
|
||||
//Контекст сервиса
|
||||
sCtx: {
|
||||
type: String,
|
||||
required: false,
|
||||
message: {
|
||||
type: path => `Контектс сервиса (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||
required: path => `Не указан контекст сервиса (${path})`
|
||||
}
|
||||
},
|
||||
//Дата истечения контекста
|
||||
dCtxExp: {
|
||||
type: Date,
|
||||
required: false,
|
||||
message: {
|
||||
type: path => `Дата истечения контекста (${path}) имеет некорректный тип данных (ожидалось - Date)`,
|
||||
required: path => `Не указана дата истечения контекста (${path})`
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -151,5 +169,23 @@ exports.OutQueueProcessorFnAfter = new Schema({
|
||||
`Флаг ошибки аутентификации на удаленном сервисе (${path}) имеет некорректный тип данных (ожидалось - Boolean)`,
|
||||
required: path => `Не указан флаг ошибки аутентификации на удаленном сервисе (${path})`
|
||||
}
|
||||
},
|
||||
//Контекст сервиса
|
||||
sCtx: {
|
||||
type: String,
|
||||
required: false,
|
||||
message: {
|
||||
type: path => `Контектс сервиса (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||
required: path => `Не указан контекст сервиса (${path})`
|
||||
}
|
||||
},
|
||||
//Дата истечения контекста
|
||||
dCtxExp: {
|
||||
type: Date,
|
||||
required: false,
|
||||
message: {
|
||||
type: path => `Дата истечения контекста (${path}) имеет некорректный тип данных (ожидалось - Date)`,
|
||||
required: path => `Не указана дата истечения контекста (${path})`
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -33,6 +33,11 @@ const SQUEUE_EXEC_STATE_DB_ERR = "DB_ERR"; //Ошибка обработки С
|
||||
const SQUEUE_EXEC_STATE_OK = "OK"; //Обработано успешно (строковый код)
|
||||
const SQUEUE_EXEC_STATE_ERR = "ERR"; //Обработано с ошибками (строковый код)
|
||||
|
||||
//Коды результатов исполнения обработчика сообщения
|
||||
const SPRC_RESP_RESULT_OK = "OK"; //Обработано успешно
|
||||
const SPRC_RESP_RESULT_ERR = "ERR"; //Ошибка обработки
|
||||
const SPRC_RESP_RESULT_UNAUTH = "UNAUTH"; //Неаутентифицирован
|
||||
|
||||
//------------------
|
||||
// Интерфейс модуля
|
||||
//------------------
|
||||
@ -56,6 +61,9 @@ exports.SQUEUE_EXEC_STATE_DB_OK = SQUEUE_EXEC_STATE_DB_OK;
|
||||
exports.SQUEUE_EXEC_STATE_DB_ERR = SQUEUE_EXEC_STATE_DB_ERR;
|
||||
exports.SQUEUE_EXEC_STATE_OK = SQUEUE_EXEC_STATE_OK;
|
||||
exports.SQUEUE_EXEC_STATE_ERR = SQUEUE_EXEC_STATE_ERR;
|
||||
exports.SPRC_RESP_RESULT_OK = SPRC_RESP_RESULT_OK;
|
||||
exports.SPRC_RESP_RESULT_ERR = SPRC_RESP_RESULT_ERR;
|
||||
exports.SPRC_RESP_RESULT_UNAUTH = SPRC_RESP_RESULT_UNAUTH;
|
||||
|
||||
//Схема валидации сообщения очереди обмена
|
||||
exports.Queue = new Schema({
|
||||
@ -270,3 +278,31 @@ exports.QueueResp = new Schema({
|
||||
}
|
||||
}
|
||||
}).validator({ required: val => val === null || val });
|
||||
|
||||
//Схема валидации результата обработки сообщения очереди
|
||||
exports.QueuePrcResult = new Schema({
|
||||
//Состояние обработки сообщения очереди обмена
|
||||
sResult: {
|
||||
type: String,
|
||||
enum: [SPRC_RESP_RESULT_OK, SPRC_RESP_RESULT_ERR, SPRC_RESP_RESULT_UNAUTH],
|
||||
required: true,
|
||||
message: {
|
||||
type: path =>
|
||||
`Состояние обработки сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||
enum: path => `Значение состояния обработки сообщения очереди обмена (${path}) не поддерживается`,
|
||||
required: path => `Не указано состояние обработки сообщения очереди обмена (${path})`
|
||||
}
|
||||
},
|
||||
//Информация от обработчика сообщения очереди обмена
|
||||
sMsg: {
|
||||
type: String,
|
||||
required: true,
|
||||
message: {
|
||||
type: path =>
|
||||
`Информация от обработчика сообщения очереди обмена (${path}) имеет некорректный тип данных (ожидалось - String)`,
|
||||
required: path => `Не указана информация от обработчика сообщения очереди обмена (${path})`
|
||||
}
|
||||
}
|
||||
}).validator({
|
||||
required: val => typeof val != "undefined"
|
||||
});
|
||||
|
@ -190,16 +190,7 @@ exports.Service = new Schema({
|
||||
}
|
||||
},
|
||||
//Список функций сервиса
|
||||
functions: defServiceFunctions(true, "functions"),
|
||||
//Контекст работы сервиса
|
||||
context: {
|
||||
type: Object,
|
||||
required: true,
|
||||
message: {
|
||||
type: "Контекст работы сервиса (context) имеет некорректный тип данных (ожидалось - Object)",
|
||||
required: "Не указан контекст работы сервиса (context)"
|
||||
}
|
||||
}
|
||||
functions: defServiceFunctions(true, "functions")
|
||||
});
|
||||
|
||||
//Схема валидации контекста сервиса
|
||||
|
@ -67,6 +67,14 @@ exports.dbProcess = new Schema({
|
||||
message: {
|
||||
required: path => `Не указано обрабатываемое сообщение очреди (${path})`
|
||||
}
|
||||
},
|
||||
//Функция сервиса-обработчика
|
||||
function: {
|
||||
schema: ServiceFunction,
|
||||
required: true,
|
||||
message: {
|
||||
required: path => `Не указана функция сервиса для обработки сообщения очереди (${path})`
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -341,14 +341,14 @@ const setQueueResp = async prms => {
|
||||
const execQueuePrc = async prms => {
|
||||
try {
|
||||
let res = await prms.connection.execute(
|
||||
"BEGIN PKG_EXS.QUEUE_PRC(NEXSQUEUE => :NEXSQUEUE, RCQUEUE => :RCQUEUE); END;",
|
||||
"BEGIN PKG_EXS.QUEUE_PRC(NEXSQUEUE => :NEXSQUEUE, RCRESULT => :RCRESULT); END;",
|
||||
{
|
||||
NEXSQUEUE: prms.nQueueId,
|
||||
RCQUEUE: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
|
||||
RCRESULT: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
|
||||
},
|
||||
{ outFormat: oracledb.OBJECT, autoCommit: true }
|
||||
);
|
||||
let rows = await readCursorData(res.outBinds.RCQUEUE);
|
||||
let rows = await readCursorData(res.outBinds.RCRESULT);
|
||||
return rows[0];
|
||||
} catch (e) {
|
||||
throw new Error(e.message);
|
||||
|
Loading…
x
Reference in New Issue
Block a user