538 lines
17 KiB
JavaScript
538 lines
17 KiB
JavaScript
/*
|
||
Сервис интеграции ПП Парус 8 с WEB API
|
||
Дополнительный модуль: работа с БД ПП Парус 8 (Postgre)
|
||
*/
|
||
|
||
//----------------------
|
||
// Подключение библиотек
|
||
//----------------------
|
||
|
||
const pg = require("pg"); //Работа с СУБД Postgre
|
||
|
||
//--------------------------
|
||
// Глобальные идентификаторы
|
||
//--------------------------
|
||
|
||
const DT_VARCHAR = pg.types.builtins.VARCHAR; //Тип данных "Строка" БД
|
||
const DT_NUMBER = pg.types.builtins.NUMERIC; //Тип данных "Число" БД
|
||
const DT_DATE = pg.types.builtins.DATE; //Тип данных "Дата" БД
|
||
const DT_CLOB = pg.types.builtins.TEXT; //Тип данных "Текстовые данные" БД
|
||
const DT_BLOB = pg.types.builtins.BYTEA; //Тип данных "Двоичные данные" БД
|
||
const DT_CURSOR = pg.types.builtins.REFCURSOR; //Тип данных "Курсор" БД
|
||
|
||
//------------
|
||
// Тело модуля
|
||
//------------
|
||
|
||
//Установка парсера значений для типа данных NUMERIC БД PG
|
||
pg.types.setTypeParser(pg.types.builtins.NUMERIC, val => {
|
||
return val ? Number(val) : val;
|
||
});
|
||
|
||
//Формирование имени хранимого объекта БД (с параметрами)
|
||
const makeStoredName = (sName, inPrms) => {
|
||
let prms = "";
|
||
let prm_numb = 0;
|
||
for (i in inPrms) {
|
||
prm_numb++;
|
||
let prm_type = "";
|
||
if (inPrms[i] != null && inPrms[i] != undefined)
|
||
switch (typeof inPrms[i]) {
|
||
case "string":
|
||
if (inPrms[i].length ? inPrms[i].length > 4000 : false) prm_type = "::text";
|
||
else prm_type = "::character varying";
|
||
break;
|
||
case "number":
|
||
prm_type = "::numeric";
|
||
break;
|
||
case "bigint":
|
||
prm_type = "::numeric";
|
||
break;
|
||
case "boolean":
|
||
prm_type = "::boolean";
|
||
break;
|
||
case "object":
|
||
if (inPrms[i] instanceof Date) prm_type = "::date";
|
||
else prm_type = "::bytea";
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
prms += `${prms ? ", " : ""}$${prm_numb}${prm_type}`;
|
||
}
|
||
return `${sName.replace(".", "$")}(${prms})`;
|
||
};
|
||
|
||
//Формирование параметров хранимого объекта БД
|
||
const makeStoredPrms = inPrms => {
|
||
let prms = [];
|
||
for (i in inPrms) prms.push(inPrms[i]);
|
||
return prms;
|
||
};
|
||
|
||
//Исполнение хранимого объекта БД
|
||
const executeStored = async prms => {
|
||
let client;
|
||
let outResult = {};
|
||
try {
|
||
client = await prms.connection.connect();
|
||
let outPrmName = "";
|
||
let outPrmIsCursor = false;
|
||
for (i in prms.outPrms) {
|
||
outPrmName = i;
|
||
outPrmIsCursor = prms.outPrms[i] == DT_CURSOR;
|
||
break;
|
||
}
|
||
await client.query(`begin;`);
|
||
let res = await client.query({
|
||
text: `select ${makeStoredName(prms.sName, prms.inPrms)}${outPrmName ? ` as "${outPrmName}"` : ""};`,
|
||
values: makeStoredPrms(prms.inPrms)
|
||
});
|
||
if (res)
|
||
if (res.rows)
|
||
if (res.rows[0]) {
|
||
const outBind = res.rows[0][outPrmName];
|
||
if (outPrmIsCursor) {
|
||
let rowsRes = [];
|
||
let doExit = false;
|
||
while (!doExit) {
|
||
doExit = true;
|
||
res = await client.query(`fetch next from "${outBind}";`);
|
||
if (res)
|
||
if (res.rows)
|
||
if (res.rowCount > 0 && res.rows.length > 0) {
|
||
doExit = false;
|
||
res.rows.map(r => rowsRes.push(r));
|
||
}
|
||
}
|
||
outResult[outPrmName] = rowsRes;
|
||
} else outResult[outPrmName] = outBind;
|
||
}
|
||
await client.query(`commit;`);
|
||
} catch (e) {
|
||
if (client) {
|
||
try {
|
||
await client.query(`rollback;`);
|
||
} catch (err) {
|
||
throw new Error(err.message);
|
||
}
|
||
}
|
||
throw new Error(e.message);
|
||
} finally {
|
||
if (client) {
|
||
try {
|
||
await client.release();
|
||
} catch (err) {
|
||
throw new Error(err.message);
|
||
}
|
||
}
|
||
}
|
||
if (outResult) return outResult;
|
||
};
|
||
|
||
//Проверка условий при запуске сервиса интеграции
|
||
const 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 !== "" ? prms.sServerName : null,
|
||
SSESSION_APP_NAME: prms.sSessionAppName
|
||
},
|
||
outPrms: {
|
||
SERR_TEXT: DT_VARCHAR
|
||
}
|
||
});
|
||
//Если есть ошибки запуска
|
||
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
|
||
}
|
||
});
|
||
//Если рег. номер сервера интеграции потерялся
|
||
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
|
||
}
|
||
});
|
||
};
|
||
|
||
//Подключение к БД
|
||
const connect = async prms => {
|
||
try {
|
||
//Создаем пул подключения
|
||
let pool = new pg.Pool({
|
||
connectionString: `postgres://${prms.sUser}:${prms.sPassword}@${prms.sConnectString}`,
|
||
connectionTimeoutMillis: 600000,
|
||
min: prms.nPoolMin ? prms.nPoolMin : 4,
|
||
max: prms.nPoolMax ? prms.nPoolMax : 4
|
||
});
|
||
pool.on("acquire", async client => {
|
||
//Устанавливаем схему
|
||
await client.query(`select ALTER_SESSION_SET_SCHEMA($1);`, [prms.sSchema]);
|
||
//Устанавливаем модуль сессии
|
||
await client.query(`select PKG_EXS$UTL_MODULE_SET($1);`, [prms.exsSrv.sServerName]);
|
||
});
|
||
return pool;
|
||
} catch (e) {
|
||
throw new Error(e.message);
|
||
}
|
||
};
|
||
|
||
//Отключение от БД
|
||
const disconnect = async prms => {
|
||
try {
|
||
await prms.connection.end();
|
||
} catch (e) {
|
||
throw new Error(e.message);
|
||
}
|
||
};
|
||
|
||
//Получение списка сервисов
|
||
const getServices = async prms => {
|
||
let servicesData = await executeStored({
|
||
connection: prms.connection,
|
||
sName: "PKG_EXS$SERVICES_GET",
|
||
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
|
||
}
|
||
});
|
||
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$2",
|
||
inPrms: {
|
||
NEXSSERVICEFN: prms.nServiceFnId,
|
||
BMSG: prms.blMsg,
|
||
NEXSQUEUE: prms.nQueueId,
|
||
NLNK_COMPANY: prms.nLnkCompanyId,
|
||
NLNK_DOCUMENT: prms.nLnkDocumentId,
|
||
SLNK_UNITCODE: prms.sLnkUnitcode,
|
||
SOPTIONS: prms.sOptions
|
||
},
|
||
outPrms: { RCQUEUE: DT_CURSOR }
|
||
});
|
||
return queueData.RCQUEUE[0];
|
||
};
|
||
|
||
//Считывание очередной порции исходящих сообщений из очереди
|
||
const getQueueOutgoing = async prms => {
|
||
let queueOutgoingData = await executeStored({
|
||
connection: prms.connection,
|
||
sName: "PKG_EXS$QUEUE_SRV_TYPE_SEND_GET",
|
||
inPrms: {
|
||
NPORTION_SIZE: prms.nPortionSize,
|
||
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$2",
|
||
inPrms: {
|
||
NEXSQUEUE: prms.nQueueId,
|
||
BMSG: prms.blMsg
|
||
},
|
||
outPrms: { RCQUEUE: DT_CURSOR }
|
||
});
|
||
return queueMsgData.RCQUEUE[0];
|
||
};
|
||
|
||
//Установка параметров сообщения очереди
|
||
const setQueueOptions = async prms => {
|
||
let queueOptionsData = await executeStored({
|
||
connection: prms.connection,
|
||
sName: "PKG_EXS$QUEUE_OPTIONS_SET$2",
|
||
inPrms: {
|
||
NEXSQUEUE: prms.nQueueId,
|
||
SOPTIONS: prms.sOptions
|
||
},
|
||
outPrms: { RCQUEUE: DT_CURSOR }
|
||
});
|
||
return queueOptionsData.RCQUEUE[0];
|
||
};
|
||
|
||
//Считывание результата обработки сообщения очереди
|
||
const getQueueResp = async prms => {
|
||
let queueRespData = await executeStored({
|
||
connection: prms.connection,
|
||
sName: "PKG_EXS$QUEUE_RESP_GET",
|
||
inPrms: {
|
||
NEXSQUEUE: prms.nQueueId
|
||
},
|
||
outPrms: { RCQUEUE_RESP: DT_CURSOR }
|
||
});
|
||
return queueRespData.RCQUEUE_RESP[0];
|
||
};
|
||
|
||
//Установка результата обработки сообщения очереди
|
||
const setQueueResp = async prms => {
|
||
let queueRespData = await executeStored({
|
||
connection: prms.connection,
|
||
sName: "PKG_EXS$QUEUE_RESP_SET$2",
|
||
inPrms: {
|
||
NEXSQUEUE: prms.nQueueId,
|
||
BRESP: prms.blResp,
|
||
NIS_ORIGINAL: prms.nIsOriginal
|
||
},
|
||
outPrms: { RCQUEUE: DT_CURSOR }
|
||
});
|
||
return queueRespData.RCQUEUE[0];
|
||
};
|
||
|
||
//Установка параметров результата обработки сообщения очереди
|
||
const setQueueOptionsResp = async prms => {
|
||
let queueOptionsRespData = await executeStored({
|
||
connection: prms.connection,
|
||
sName: "PKG_EXS$QUEUE_OPTIONS_RESP_SET$2",
|
||
inPrms: {
|
||
NEXSQUEUE: prms.nQueueId,
|
||
SOPTIONS_RESP: prms.sOptionsResp
|
||
},
|
||
outPrms: { RCQUEUE: DT_CURSOR }
|
||
});
|
||
return queueOptionsRespData.RCQUEUE[0];
|
||
};
|
||
|
||
//Исполнение обработчика со стороны БД для сообщения очереди
|
||
const execQueuePrc = async prms => {
|
||
let queuePrcData = await executeStored({
|
||
connection: prms.connection,
|
||
sName: "PKG_EXS$QUEUE_PRC",
|
||
inPrms: {
|
||
NEXSQUEUE: prms.nQueueId
|
||
},
|
||
outPrms: { RCRESULT: DT_CURSOR }
|
||
});
|
||
return queuePrcData.RCRESULT[0];
|
||
};
|
||
|
||
//-----------------
|
||
// Интерфейс модуля
|
||
//-----------------
|
||
|
||
exports.DT_VARCHAR = DT_VARCHAR;
|
||
exports.DT_NUMBER = DT_NUMBER;
|
||
exports.DT_DATE = DT_DATE;
|
||
exports.DT_CLOB = DT_CLOB;
|
||
exports.DT_BLOB = DT_BLOB;
|
||
exports.DT_CURSOR = DT_CURSOR;
|
||
exports.executeStored = executeStored;
|
||
exports.checkAppStart = checkAppStart;
|
||
exports.initServer = initServer;
|
||
exports.clearServer = clearServer;
|
||
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;
|