diff --git a/config.js b/config.js index 4f12cc8..356fa7a 100644 --- a/config.js +++ b/config.js @@ -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 }; diff --git a/core/constants.js b/core/constants.js index d7b0713..9db9742 100644 --- a/core/constants.js +++ b/core/constants.js @@ -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"; //Ошибка обработчика сервера БД diff --git a/core/db_connector.js b/core/db_connector.js index d51369c..00fbc6e 100644 --- a/core/db_connector.js +++ b/core/db_connector.js @@ -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; diff --git a/core/in_queue.js b/core/in_queue.js index d33d619..e93a4f2 100644 --- a/core/in_queue.js +++ b/core/in_queue.js @@ -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); diff --git a/core/out_queue.js b/core/out_queue.js index f36810f..165fc1e 100644 --- a/core/out_queue.js +++ b/core/out_queue.js @@ -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 { diff --git a/core/out_queue_processor.js b/core/out_queue_processor.js index dc5a2a5..ee636fc 100644 --- a/core/out_queue_processor.js +++ b/core/out_queue_processor.js @@ -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 }); diff --git a/db/PKG_EXS.pck b/db/PKG_EXS.pck index be9a884..379fd11 100644 --- a/db/PKG_EXS.pck +++ b/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; diff --git a/models/obj_in_queue.js b/models/obj_in_queue.js index 300ea77..0be5abd 100644 --- a/models/obj_in_queue.js +++ b/models/obj_in_queue.js @@ -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})` + } } }); diff --git a/models/obj_out_queue_processor.js b/models/obj_out_queue_processor.js index 00327f9..cd36149 100644 --- a/models/obj_out_queue_processor.js +++ b/models/obj_out_queue_processor.js @@ -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})` + } } }); diff --git a/models/obj_queue.js b/models/obj_queue.js index bff0b97..505c335 100644 --- a/models/obj_queue.js +++ b/models/obj_queue.js @@ -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" +}); diff --git a/models/obj_service.js b/models/obj_service.js index afb8c0a..cdb500e 100644 --- a/models/obj_service.js +++ b/models/obj_service.js @@ -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") }); //Схема валидации контекста сервиса diff --git a/models/prms_out_queue_processor.js b/models/prms_out_queue_processor.js index 17f27b8..39c445d 100644 --- a/models/prms_out_queue_processor.js +++ b/models/prms_out_queue_processor.js @@ -67,6 +67,14 @@ exports.dbProcess = new Schema({ message: { required: path => `Не указано обрабатываемое сообщение очреди (${path})` } + }, + //Функция сервиса-обработчика + function: { + schema: ServiceFunction, + required: true, + message: { + required: path => `Не указана функция сервиса для обработки сообщения очереди (${path})` + } } }); diff --git a/modules/parus_oracle_db.js b/modules/parus_oracle_db.js index 7654b6e..0b7901a 100644 --- a/modules/parus_oracle_db.js +++ b/modules/parus_oracle_db.js @@ -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);