Рефакторинг: приведение полей объектов и параметров процедур к общему стилю + песочница npm test

This commit is contained in:
Mikhail Chechnev 2018-11-16 20:55:48 +03:00
parent ea74ff4ed1
commit 326565d3b4
6 changed files with 214 additions and 148 deletions

View File

@ -10,23 +10,23 @@
//Параметры подключения к БД //Параметры подключения к БД
let dbConnect = { let dbConnect = {
//Пользователь БД //Пользователь БД
user: "parus", sUser: "parus",
//Пароль пользователя БД //Пароль пользователя БД
password: "parus", sPassword: "parus",
//Строка подключения к БД //Строка подключения к БД
connectString: "DEMOP_CITKSERV_WAN", sConnectString: "DEMOP_CITKSERV_WAN",
//Наименование модуля (для сессии БД) //Наименование модуля (для сессии БД)
sessionModuleName: "PARUS$ExchangeServer", sSessionModuleName: "PARUS$ExchangeServer",
//Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД) //Подключаемый модуль обслуживания БД (низкоуровневые функции работы с СУБД)
connectorModule: "parus_oracle_db.js" sConnectorModule: "parus_oracle_db.js"
}; };
//Параметры обработки очереди исходящих сообщений //Параметры обработки очереди исходящих сообщений
let outgoing = { let outgoing = {
//Размер блока одновременно обрабатываемых исходящих сообщений //Размер блока одновременно обрабатываемых исходящих сообщений
portionSize: 1, nPortionSize: 1,
//Скорость проверки наличия исходящих сообщений (мс) //Скорость проверки наличия исходящих сообщений (мс)
checkTimeout: 500 nCheckTimeout: 500
}; };
//----------------- //-----------------

View File

@ -17,9 +17,9 @@ const { ServerError } = require("@core/server_errors.js"); //Типовая ош
//---------- //----------
//Состояния записей журнала работы сервиса //Состояния записей журнала работы сервиса
const MSG_TYPE_INF = 0; //Информация const NLOG_STATE_INF = 0; //Информация
const MSG_TYPE_WRN = 1; //Предупреждение const NLOG_STATE_WRN = 1; //Предупреждение
const MSG_TYPE_ERR = 2; //Ошибка const NLOG_STATE_ERR = 2; //Ошибка
//------------ //------------
// Тело модуля // Тело модуля
@ -27,23 +27,23 @@ const MSG_TYPE_ERR = 2; //Ошибка
class DBConnector { class DBConnector {
//Конструктор //Конструктор
constructor(dbConnect) { constructor(prms) {
//Проверяем структуру переданного объекта для подключения //Проверяем структуру переданного объекта для подключения
let checkResult = checkObject(dbConnect, { let checkResult = checkObject(prms, {
fields: [ fields: [
{ name: "user", required: true }, { name: "sUser", required: true },
{ name: "password", required: true }, { name: "sPassword", required: true },
{ name: "connectString", required: true }, { name: "sConnectString", required: true },
{ name: "sessionModuleName", required: true }, { name: "sSessionModuleName", required: true },
{ name: "connectorModule", required: false } { name: "sConnectorModule", required: false }
] ]
}); });
//Если структура объекта в норме //Если структура объекта в норме
if (!checkResult) { if (!checkResult) {
//Проверяем наличие модуля для работы с БД в настройках подключения //Проверяем наличие модуля для работы с БД в настройках подключения
if (dbConnect.connectorModule) { if (prms.sConnectorModule) {
//Подключим модуль //Подключим модуль
this.connector = require(makeModuleFullPath(dbConnect.connectorModule)); this.connector = require(makeModuleFullPath(prms.sConnectorModule));
//Проверим его интерфейс //Проверим его интерфейс
if ( if (
!checkModuleInterface(this.connector, { !checkModuleInterface(this.connector, {
@ -61,12 +61,12 @@ class DBConnector {
) { ) {
throw new ServerError( throw new ServerError(
glConst.ERR_MODULES_BAD_INTERFACE, glConst.ERR_MODULES_BAD_INTERFACE,
"Модуль " + dbConnect.module + " реализует неверный интерфейс!" "Модуль " + prms.sConnectorModule + " реализует неверный интерфейс!"
); );
} }
//Всё успешно - сохраним настройки подключения //Всё успешно - сохраним настройки подключения
this.connectSettings = {}; this.connectSettings = {};
_.extend(this.connectSettings, dbConnect); _.extend(this.connectSettings, prms);
//Инициализируем остальные свойства //Инициализируем остальные свойства
this.connection = {}; this.connection = {};
} else { } else {
@ -85,12 +85,12 @@ class DBConnector {
//Подключиться к БД //Подключиться к БД
async connect() { async connect() {
try { try {
this.connection = await this.connector.connect( this.connection = await this.connector.connect({
this.connectSettings.user, sUser: this.connectSettings.sUser,
this.connectSettings.password, sPassword: this.connectSettings.sPassword,
this.connectSettings.connectString, sConnectString: this.connectSettings.sConnectString,
this.connectSettings.sessionModuleName sSessionModuleName: this.connectSettings.sSessionModuleName
); });
return this.connection; return this.connection;
} catch (e) { } catch (e) {
throw new ServerError(glConst.ERR_DB_CONNECT, e.message); throw new ServerError(glConst.ERR_DB_CONNECT, e.message);
@ -99,7 +99,7 @@ class DBConnector {
//Отключиться от БД //Отключиться от БД
async disconnect() { async disconnect() {
try { try {
await this.connector.disconnect(this.connection); await this.connector.disconnect({ connection: this.connection });
this.connection = {}; this.connection = {};
return; return;
} catch (e) { } catch (e) {
@ -109,9 +109,12 @@ class DBConnector {
//Получить список сервисов //Получить список сервисов
async getServices() { async getServices() {
try { try {
let srvs = await this.connector.getServices(this.connection); let srvs = await this.connector.getServices({ connection: this.connection });
let srvsFuncs = srvs.map(async srv => { let srvsFuncs = srvs.map(async srv => {
const response = await this.connector.getServiceFunctions(this.connection, srv.NRN); const response = await this.connector.getServiceFunctions({
connection: this.connection,
ddd: srv.NRN
});
let tmp = {}; let tmp = {};
_.extend(tmp, srv, { FN: [] }); _.extend(tmp, srv, { FN: [] });
response.map(f => { response.map(f => {
@ -126,21 +129,61 @@ class DBConnector {
} }
} }
//Запись в журнал работы //Запись в журнал работы
async putLog(msgType, msg, queueID) { async putLog(prms) {
try { //Проверяем структуру переданного объекта для подключения
let res = await this.connector.log(this.connection, msgType, msg, queueID); let checkResult = checkObject(prms, {
return res; fields: [
} catch (e) { { name: "nLogState", required: true },
throw new ServerError(glConst.ERR_DB_EXECUTE, e.message); { name: "sMsg", required: false },
{ name: "nServiceId", required: false },
{ name: "nServiceFnId", required: false },
{ name: "nQueueId", required: false }
]
});
//Если структура объекта в норме
if (!checkResult) {
try {
let res = await this.connector.log({
connection: this.connection,
nLogState: prms.nLogState,
sMsg: prms.sMsg,
nServiceId: prms.nServiceId,
nServiceFnId: prms.nServiceFnId,
nQueueId: prms.nQueueId
});
return res;
} catch (e) {
throw new ServerError(glConst.ERR_DB_EXECUTE, e.message);
}
} else {
throw new ServerError(
glConst.ERR_OBJECT_BAD_INTERFACE,
"qqqОбъект имеет недопустимый интерфейс: " + checkResult
);
} }
} }
//Считать очередную порцию исходящих сообщений //Считать очередную порцию исходящих сообщений
async getOutgoing(portionSize) { async getOutgoing(prms) {
try { //Проверяем структуру переданного объекта для подключения
let res = await this.connector.getQueueOutgoing(this.connection, portionSize); let checkResult = checkObject(prms, {
return res; fields: [{ name: "nPortionSize", required: true }]
} catch (e) { });
throw new ServerError(glConst.ERR_DB_EXECUTE, e.message); //Если структура объекта в норме
if (!checkResult) {
try {
let res = await this.connector.getQueueOutgoing({
connection: this.connection,
nPortionSize: prms.nPortionSize
});
return res;
} catch (e) {
throw new ServerError(glConst.ERR_DB_EXECUTE, e.message);
}
} else {
throw new ServerError(
glConst.ERR_OBJECT_BAD_INTERFACE,
"Объект имеет недопустимый интерфейс: " + checkResult
);
} }
} }
} }
@ -149,7 +192,7 @@ class DBConnector {
// Интерфейс модуля // Интерфейс модуля
//----------------- //-----------------
exports.MSG_TYPE_INF = MSG_TYPE_INF; exports.NLOG_STATE_INF = NLOG_STATE_INF;
exports.MSG_TYPE_WRN = MSG_TYPE_WRN; exports.NLOG_STATE_WRN = NLOG_STATE_WRN;
exports.MSG_TYPE_ERR = MSG_TYPE_ERR; exports.NLOG_STATE_ERR = NLOG_STATE_ERR;
exports.DBConnector = DBConnector; exports.DBConnector = DBConnector;

View File

@ -73,13 +73,16 @@ const checkObject = (obj, interface) => {
let noValues = []; let noValues = [];
//Обходим проверяемые поля //Обходим проверяемые поля
interface.fields.forEach(fld => { interface.fields.forEach(fld => {
//Проверим наличие поля в объекте //Проверим наличие поля в объекте (только для обязательных)
if (!(fld.name in obj)) { if (fld.required && !(fld.name in obj)) {
//Поля нет //Поля нет
noFields.push(fld.name); noFields.push(fld.name);
} else { } else {
//Поле есть, проверим наличие значения //Поле есть, проверим наличие значения
if (fld.required && !obj[fld.name]) if (
fld.required &&
(obj[fld.name] === "undefined" || obj[fld.name] === null || obj[fld.name] === "")
)
//Обязательное поле не содержит значения //Обязательное поле не содержит значения
noValues.push(fld.name); noValues.push(fld.name);
} }

View File

@ -38,39 +38,45 @@ const SLOG_STATE_ERR = "ERR"; //Ошибка (строковый код)
//------------ //------------
//Подключение к БД //Подключение к БД
const connect = async (user, password, connectString, moduleName) => { const connect = async prms => {
try { try {
const conn = await oracledb.getConnection({ if (prms && prms.sUser && prms.sPassword && prms.sConnectString) {
user, const conn = await oracledb.getConnection({
password, user: prms.sUser,
connectString password: prms.sPassword,
}); connectString: prms.sConnectString
conn.module = moduleName; });
return conn; if (prms.sSessionModuleName) conn.module = prms.sSessionModuleName;
return conn;
} else {
throw new Error(
"Не указаны параметры подключения (отсутствует одно из полей: sUser, sPassword, sConnectString)"
);
}
} catch (e) { } catch (e) {
throw new Error(e.message); throw new Error(e.message);
} }
}; };
//Отключение от БД //Отключение от БД
const disconnect = async connection => { const disconnect = async prms => {
if (connection) { if (prms && prms.connection) {
try { try {
const conn = await connection.close(); const conn = await prms.connection.close();
return; return;
} catch (e) { } catch (e) {
throw new Error(e.message); throw new Error(e.message);
} }
} else { } else {
throw new Error("Не указано подключение"); throw new Error("Не указано подключение (отсутствует поле: connection)");
} }
}; };
//Получение списка сервисов //Получение списка сервисов
const getServices = async connection => { const getServices = prms => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (connection) { if (prms && prms.connection) {
connection.execute( prms.connection.execute(
"BEGIN PKG_EXS.SERVICE_GET(RCSERVICES => :RCSERVICES); END;", "BEGIN PKG_EXS.SERVICE_GET(RCSERVICES => :RCSERVICES); END;",
{ RCSERVICES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, { RCSERVICES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } },
{ outFormat: oracledb.OBJECT }, { outFormat: oracledb.OBJECT },
@ -94,115 +100,129 @@ const getServices = async connection => {
} }
); );
} else { } else {
reject(new Error("Не указано подключение")); reject(new Error("Не указано подключение (отсутствует поле: connection)"));
} }
}); });
}; };
//Получение списка функций сервиса //Получение списка функций сервиса
const getServiceFunctions = (connection, serviceID) => { const getServiceFunctions = prms => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (connection) { if (prms && prms.connection) {
connection.execute( if (prms.nServiceId) {
"BEGIN PKG_EXS.SERVICEFN_GET(NSERVICE => :NSERVICE, RCSERVICEFNS => :RCSERVICEFNS); END;", prms.connection.execute(
{ NSERVICE: serviceID, RCSERVICEFNS: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, "BEGIN PKG_EXS.SERVICEFN_GET(NSERVICE => :NSERVICE, RCSERVICEFNS => :RCSERVICEFNS); END;",
{ outFormat: oracledb.OBJECT }, { NSERVICE: prms.nServiceId, RCSERVICEFNS: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } },
(err, result) => { { outFormat: oracledb.OBJECT },
if (err) { (err, result) => {
reject(new Error(err.message)); if (err) {
} else {
let cursor = result.outBinds.RCSERVICEFNS;
let queryStream = cursor.toQueryStream();
let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
reject(new Error(err.message)); reject(new Error(err.message));
}); } else {
queryStream.on("close", () => { let cursor = result.outBinds.RCSERVICEFNS;
resolve(rows); let queryStream = cursor.toQueryStream();
}); let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
reject(new Error(err.message));
});
queryStream.on("close", () => {
resolve(rows);
});
}
} }
} );
); } else {
reject(new Error("Не указан идентификатор сервиса"));
}
} else { } else {
reject(new Error("Не указано подключение")); reject(new Error("Не указано подключение (отсутствует поле: connection)"));
} }
}); });
}; };
//Запись в протокол работы //Запись в протокол работы
const log = (connection, logState, msg, queueID) => { const log = prms => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (connection) { if (prms && prms.connection) {
connection.execute( if (!(prms.nLogState === "undefined")) {
"BEGIN PKG_EXS.LOG_PUT(NLOG_STATE => :NLOG_STATE, SMSG => :SMSG, NEXSQUEUE => :NEXSQUEUE, RCLOG => :RCLOG); END;", prms.connection.execute(
{ "BEGIN PKG_EXS.LOG_PUT(NLOG_STATE => :NLOG_STATE, SMSG => :SMSG, NEXSSERVICE => :NEXSSERVICE, NEXSSERVICEFN => :NEXSSERVICEFN, NEXSQUEUE => :NEXSQUEUE, RCLOG => :RCLOG); END;",
NLOG_STATE: logState, {
SMSG: msg, NLOG_STATE: prms.nLogState,
NEXSQUEUE: queueID, SMSG: prms.sMsg,
RCLOG: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } NEXSSERVICE: prms.nServiceId,
}, NEXSSERVICEFN: prms.nServiceFnId,
{ outFormat: oracledb.OBJECT, autoCommit: true }, NEXSQUEUE: prms.nQueueId,
(err, result) => { RCLOG: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
if (err) { },
reject(new Error(err.message)); { outFormat: oracledb.OBJECT, autoCommit: true },
} else { (err, result) => {
let cursor = result.outBinds.RCLOG; if (err) {
let queryStream = cursor.toQueryStream();
let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
reject(new Error(err.message)); reject(new Error(err.message));
}); } else {
queryStream.on("close", () => { let cursor = result.outBinds.RCLOG;
resolve(rows[0]); let queryStream = cursor.toQueryStream();
}); let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
reject(new Error(err.message));
});
queryStream.on("close", () => {
resolve(rows[0]);
});
}
} }
} );
); } else {
reject(new Error("Не указан тип сообщения журнала (отсутствует поле: nLogState)"));
}
} else { } else {
reject(new Error("Не указано подключение")); reject(new Error("Не указано подключение (отсутствует поле: connection)"));
} }
}); });
}; };
//Считывание очередной порции исходящих сообщений из очереди //Считывание очередной порции исходящих сообщений из очереди
const getQueueOutgoing = (connection, portionSize) => { const getQueueOutgoing = prms => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (connection) { if (prms && prms.connection) {
connection.execute( if (prms.nPortionSize) {
"BEGIN PKG_EXS.QUEUE_NEXT_GET(NPORTION => :NPORTION, NSRV_TYPE => :NSRV_TYPE, RCQUEUES => :RCQUEUES); END;", prms.connection.execute(
{ "BEGIN PKG_EXS.QUEUE_NEXT_GET(NPORTION_SIZE => :NPORTION_SIZE, NSRV_TYPE => :NSRV_TYPE, RCQUEUES => :RCQUEUES); END;",
NPORTION: portionSize, {
NSRV_TYPE: NSRV_TYPE_SEND, NPORTION_SIZE: prms.nPortionSize,
RCQUEUES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } NSRV_TYPE: NSRV_TYPE_SEND,
}, RCQUEUES: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
{ outFormat: oracledb.OBJECT, autoCommit: true, fetchInfo: { BMSG: { type: oracledb.BUFFER } } }, },
(err, result) => { { outFormat: oracledb.OBJECT, autoCommit: true, fetchInfo: { bMsg: { type: oracledb.BUFFER } } },
if (err) { (err, result) => {
reject(new Error(err.message)); if (err) {
} else {
let cursor = result.outBinds.RCQUEUES;
let queryStream = cursor.toQueryStream();
let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
reject(new Error(err.message)); reject(new Error(err.message));
}); } else {
queryStream.on("close", () => { let cursor = result.outBinds.RCQUEUES;
resolve(rows); let queryStream = cursor.toQueryStream();
}); let rows = [];
queryStream.on("data", row => {
rows.push(row);
});
queryStream.on("error", err => {
reject(new Error(err.message));
});
queryStream.on("close", () => {
resolve(rows);
});
}
} }
} );
); } else {
reject(new Error("Не указан размер извлекаемой порции сообщений (отсутствует поле: nPortionSize)"));
}
} else { } else {
reject(new Error("Не указано подключение")); reject(new Error("Не указано подключение (отсутствует поле: connection)"));
} }
}); });
}; };

View File

@ -5,7 +5,7 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "node index.js", "start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1" "test": "node test.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -23,7 +23,7 @@ try {
a.connect() a.connect()
.then(res => { .then(res => {
console.log("CONNECTED"); console.log("CONNECTED");
a.getOutgoing(cfg.outgoing.portionSize) a.getOutgoing({ nPortionSize: cfg.outgoing.nPortionSize })
.then(res => { .then(res => {
if (res.length > 0) { if (res.length > 0) {
res.map(r => { res.map(r => {
@ -32,7 +32,7 @@ try {
} else { } else {
console.log("NO MESSAGES IN QUEUE!!!"); console.log("NO MESSAGES IN QUEUE!!!");
} }
a.putLog(db.MSG_TYPE_INF, "Сервер приложений подключен") a.putLog({ nLogState: db.NLOG_STATE_INF, sMsg: "Сервер приложений подключен" })
.then(res => { .then(res => {
console.log(res); console.log(res);
setTimeout(() => { setTimeout(() => {