P8-ExchangeService/core/db_connector.js

264 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

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

/*
Сервис интеграции ПП Парус 8 с WEB API
Модуль ядра: взаимодействие с БД
*/
//----------------------
// Подключение библиотек
//----------------------
const _ = require("lodash"); //Работа с массивами и объектами
const EventEmitter = require("events"); //Обработчик пользовательских событий
const glConst = require("../core/constants.js"); //Глобальные константы
const { ServerError } = require("../core/server_errors.js"); //Типовая ошибка
const { checkModuleInterface, makeModuleFullPath, checkObject } = require("../core/utils.js"); //Вспомогательные функции
//----------
// Константы
//----------
//Состояния записей журнала работы сервиса
const NLOG_STATE_INF = 0; //Информация
const NLOG_STATE_WRN = 1; //Предупреждение
const NLOG_STATE_ERR = 2; //Ошибка
//Типовые коды ошибок работы с БД
const SERR_DB_CONNECT = "ERR_DB_CONNECT"; //Ошибка подключения к БД
const SERR_DB_DISCONNECT = "ERR_DB_DISCONNECT"; //Ошибка отключения от БД
const SERR_DB_EXECUTE = "ERR_DB_EXECUTE"; //Ошибка исполнения функции в БД
//События модуля
const SEVT_DB_CONNECTOR_CONNECTED = "DB_CONNECTOR_CONNECTED"; //Подключено к БД
const SEVT_DB_CONNECTOR_DISCONNECTED = "DB_CONNECTOR_DISCONNECTED"; //Отключено от БД
//------------
// Тело модуля
//------------
class DBConnector extends EventEmitter {
//Конструктор
constructor(prms) {
//создадим экземпляр родительского класса
super();
//Проверяем структуру переданного объекта для подключения
let sCheckResult = checkObject(prms, {
fields: [
{ sName: "sUser", bRequired: true },
{ sName: "sPassword", bRequired: true },
{ sName: "sConnectString", bRequired: true },
{ sName: "sSessionModuleName", bRequired: true },
{ sName: "sConnectorModule", bRequired: false }
]
});
//Если структура объекта в норме
if (!sCheckResult) {
//Проверяем наличие модуля для работы с БД в настройках подключения
if (prms.sConnectorModule) {
//Подключим модуль
this.connector = require(makeModuleFullPath(prms.sConnectorModule));
//Проверим его интерфейс
if (
!checkModuleInterface(this.connector, {
functions: [
"connect",
"disconnect",
"getServices",
"getServiceFunctions",
"log",
"getQueueOutgoing",
"putQueueIncoming",
"setQueueValue"
]
})
) {
throw new ServerError(
glConst.SERR_MODULES_BAD_INTERFACE,
"Модуль " + prms.sConnectorModule + " реализует неверный интерфейс!"
);
}
//Всё успешно - сохраним настройки подключения
this.connectSettings = {};
_.extend(this.connectSettings, prms);
//Инициализируем остальные свойства
this.connection = {};
this.bConnected = false;
} else {
throw new ServerError(
glConst.SERR_MODULES_NO_MODULE_SPECIFIED,
"Не указано имя подключаемого модуля-коннектора!"
);
}
} else {
throw new ServerError(
glConst.SERR_OBJECT_BAD_INTERFACE,
"Объект имеет недопустимый интерфейс: " + sCheckResult
);
}
}
//Подключиться к БД
async connect() {
try {
this.connection = await this.connector.connect(this.connectSettings);
this.bConnected = true;
this.emit(SEVT_DB_CONNECTOR_CONNECTED, this.connection);
return this.connection;
} catch (e) {
throw new ServerError(SERR_DB_CONNECT, e.message);
}
}
//Отключиться от БД
async disconnect() {
if (this.bConnected) {
try {
await this.connector.disconnect({ connection: this.connection });
this.connection = {};
this.bConnected = false;
this.emit(SEVT_DB_CONNECTOR_DISCONNECTED, this.connection);
return;
} catch (e) {
throw new ServerError(SERR_DB_DISCONNECT, e.message);
}
}
}
//Получить список сервисов
async getServices() {
if (this.bConnected) {
try {
let srvs = await this.connector.getServices({ connection: this.connection });
let srvsFuncs = srvs.map(async srv => {
const response = await this.connector.getServiceFunctions({
connection: this.connection,
nServiceId: srv.nId
});
let tmp = {};
_.extend(tmp, srv, { functions: [] });
response.map(f => {
tmp.functions.push(f);
});
return tmp;
});
let res = await Promise.all(srvsFuncs);
return res;
} catch (e) {
throw new ServerError(SERR_DB_EXECUTE, e.message);
}
} else {
throw new ServerError(SERR_DB_EXECUTE, "Нет подключения к БД");
}
}
//Запись в журнал работы
async putLog(prms) {
if (this.bConnected) {
//Проверяем структуру переданного объекта для подключения
let sCheckResult = checkObject(prms, {
fields: [
{ sName: "nLogState", bRequired: true },
{ sName: "sMsg", bRequired: false },
{ sName: "nServiceId", bRequired: false },
{ sName: "nServiceFnId", bRequired: false },
{ sName: "nQueueId", bRequired: false }
]
});
//Если структура объекта в норме
if (!sCheckResult) {
try {
let logData = { connection: this.connection };
_.extend(logData, prms);
let res = await this.connector.log(logData);
return res;
} catch (e) {
throw new ServerError(SERR_DB_EXECUTE, e.message);
}
} else {
throw new ServerError(
glConst.SERR_OBJECT_BAD_INTERFACE,
"Объект имеет недопустимый интерфейс: " + sCheckResult
);
}
} else {
throw new ServerError(SERR_DB_EXECUTE, "Нет подключения к БД");
}
}
//Запись информации в журнал работы
async putLogInf(sMsg, prms) {
let logData = {};
_.extend(logData, prms);
logData.nLogState = NLOG_STATE_INF;
logData.sMsg = sMsg;
try {
let res = await this.putLog(logData);
return res;
} catch (e) {
throw new ServerError(SERR_DB_EXECUTE, e.message);
}
}
//Запись предупреждения в журнал работы
async putLogWrn(sMsg, prms) {
let logData = {};
_.extend(logData, prms);
logData.nLogState = NLOG_STATE_WRN;
logData.sMsg = sMsg;
try {
let res = await this.putLog(logData);
return res;
} catch (e) {
throw new ServerError(SERR_DB_EXECUTE, e.message);
}
}
//Запись ошибки в журнал работы
async putLogErr(sMsg, prms) {
let logData = {};
_.extend(logData, prms);
logData.nLogState = NLOG_STATE_ERR;
logData.sMsg = sMsg;
try {
let res = await this.putLog(logData);
return res;
} catch (e) {
throw new ServerError(SERR_DB_EXECUTE, e.message);
}
}
//Считать очередную порцию исходящих сообщений
async getOutgoing(prms) {
if (this.bConnected) {
//Проверяем структуру переданного объекта для подключения
let sCheckResult = checkObject(prms, {
fields: [{ sName: "nPortionSize", bRequired: true }]
});
//Если структура объекта в норме
if (!sCheckResult) {
try {
let res = await this.connector.getQueueOutgoing({
connection: this.connection,
nPortionSize: prms.nPortionSize
});
return res;
} catch (e) {
throw new ServerError(SERR_DB_EXECUTE, e.message);
}
} else {
throw new ServerError(
glConst.SERR_OBJECT_BAD_INTERFACE,
"Объект имеет недопустимый интерфейс: " + sCheckResult
);
}
} else {
throw new ServerError(SERR_DB_EXECUTE, "Нет подключения к БД");
}
}
}
//-----------------
// Интерфейс модуля
//-----------------
exports.NLOG_STATE_INF = NLOG_STATE_INF;
exports.NLOG_STATE_WRN = NLOG_STATE_WRN;
exports.NLOG_STATE_ERR = NLOG_STATE_ERR;
exports.SERR_DB_CONNECT = SERR_DB_CONNECT;
exports.SERR_DB_DISCONNECT = SERR_DB_DISCONNECT;
exports.SERR_DB_EXECUTE = SERR_DB_EXECUTE;
exports.SEVT_DB_CONNECTOR_CONNECTED = SEVT_DB_CONNECTOR_CONNECTED;
exports.SEVT_DB_CONNECTOR_DISCONNECTED = SEVT_DB_CONNECTOR_DISCONNECTED;
exports.DBConnector = DBConnector;