diff --git a/config.js b/config.js index 5ab90c0..9000b25 100644 --- a/config.js +++ b/config.js @@ -1,5 +1,28 @@ -module.exports = { +/* + Сервис интеграции ПП Парус 8 с WEB API + Конфигурация сервера приложений +*/ + +//------------ +// Тело модуля +//------------ + +//Параметры подключения к БД +let dbConnect = { + //Пользователь БД user: "parus", + //Пароль пользователя БД password: "parus", - connectString: "DEMOP_CITKSERV" + //Строка подключения к БД + connectString: "DEMOP_CITKSERV", + //Модуль обслуживания БД + module: "parus_db.js" +}; + +//----------------- +// Интерфейс модуля +//----------------- + +module.exports = { + dbConnect }; diff --git a/core/constants.js b/core/constants.js new file mode 100644 index 0000000..33bac2c --- /dev/null +++ b/core/constants.js @@ -0,0 +1,20 @@ +/* + Сервис интеграции ПП Парус 8 с WEB API + Модуль ядра: глобавльные константы +*/ + +//----------------- +// Интерфейс модуля +//----------------- + +//Путь к модулям +exports.MODULES_PATH_CORE = "@core"; //Модули ядра +exports.MODULES_PATH_EX = "@modules"; //Дополнительные пользовательские модули + +//Типовые коды ошибок подключения модулей +exports.ERR_MODULES_NO_MODULE_SPECIFIED = "ERR_MODULES_NO_MODULE_SPECIFIED"; //Не указан подключаемый модуль +exports.ERR_MODULES_BAD_INTERFACE = "ERR_MODULES_BAD_INTERFACE"; //Ошибочный интерфейс подключаемого модуля + +//Типовые коды ошибок работы с БД +exports.ERR_DB_CONNECT = "ERR_DB_CONNECT"; //Ошибка подключения к БД +exports.ERR_DB_DISCONNECT = "ERR_DB_DISCONNECT"; //Ошибка отключения от БД diff --git a/core/db_connector.js b/core/db_connector.js new file mode 100644 index 0000000..c33dc81 --- /dev/null +++ b/core/db_connector.js @@ -0,0 +1,72 @@ +/* + Сервис интеграции ПП Парус 8 с WEB API + Модуль ядра: взаимодействие с БД +*/ + +//---------------------- +// Подключение библиотек +//---------------------- + +const _ = require("lodash"); //Работа с массивами и объектами +const glConst = require("@core/constants.js"); //Глобальные константы +const { checkModuleInterface, makeModuleFullPath } = require("@core/utils.js"); //Вспомогательные функции +const { ServerError } = require("@core/server_errors.js"); //Типовая ошибка + +//------------ +// Тело модуля +//------------ + +class DBConnector { + //Конструктор + constructor(dbConnect) { + //Проверяем наличие модуля для работы с БД в настройках подключения + if (dbConnect.module) { + //Подключим модуль + this.connector = require(makeModuleFullPath(dbConnect.module)); + //Проверим его интерфейс + if (!checkModuleInterface(this.connector, { functions: ["connect", "disconnect", "execute"] })) { + throw new ServerError( + glConst.ERR_MODULES_BAD_INTERFACE, + "Модуль " + dbConnect.module + " реализует неверный интерфейс!" + ); + } + //Всё успешно - сохраним настройки подключения + this.connectSettings = {}; + _.extend(this.connectSettings, dbConnect); + //Инициализируем остальные свойства + this.connection = {}; + } else { + throw new ServerError( + glConst.ERR_MODULES_NO_MODULE_SPECIFIED, + "Не указано имя подключаемого модуля-коннектора!" + ); + } + } + //Подключиться к БД + async connect() { + try { + this.connection = await this.connector.connect(this.connectSettings); + return this.connection; + } catch (e) { + throw new ServerError(glConst.ERR_DB_CONNECT, e.message); + } + } + //Отключиться от БД + async disconnect() { + try { + await this.connector.disconnect(this.connection); + this.connection = {}; + return; + } catch (e) { + throw new ServerError(glConst.ERR_DB_DISCONNECT, e.message); + } + } + //Исполнить запрос + async execute() {} +} + +//----------------- +// Интерфейс модуля +//----------------- + +exports.DBConnector = DBConnector; diff --git a/core/logger.js b/core/logger.js new file mode 100644 index 0000000..9727c0e --- /dev/null +++ b/core/logger.js @@ -0,0 +1,87 @@ +/* + Сервис интеграции ПП Парус 8 с WEB API + Модуль ядра: протоколирование работы +*/ + +//------------ +// Тело модуля +//------------ + +//Тип сообщения протокола - ошибка +const LOGGER_MESSAGE_TYPE_ERROR = "ERROR"; + +//Тип сообщения протокола - предупреждение +const LOGGER_MESSAGE_TYPE_WARN = "WARN"; + +//Тип сообщения протокола - информация +const LOGGER_MESSAGE_TYPE_INFO = "INFO"; + +//Сообщение протокола +class LoggerMessage { + //Конструктор класса + constructor(type, message) { + this.type = type; + this.message = message; + } +} + +//Класс управления протоколом +class Logger { + //Конструктор класса + constructor() {} + //Протоколирование ошибки + error(msg) { + this.log(new LoggerMessage(LOGGER_MESSAGE_TYPE_ERROR, msg)); + } + //Протоколирование предупреждения + warn(msg) { + this.log(new LoggerMessage(LOGGER_MESSAGE_TYPE_WARN, msg)); + } + //Протоколирование информации + info(msg) { + this.log(new LoggerMessage(LOGGER_MESSAGE_TYPE_INFO, msg)); + } + //Протоколирование + log(loggerMessage) { + let message = ""; + let prefix = "LOG MESSAGE"; + let colorPattern = ""; + //Конструируем сообщение + if (loggerMessage instanceof LoggerMessage) { + switch (loggerMessage.type) { + case LOGGER_MESSAGE_TYPE_ERROR: { + prefix = "ERROR"; + colorPattern = "\x1b[31m%s\x1b[0m%s"; + break; + } + case LOGGER_MESSAGE_TYPE_WARN: { + prefix = "WARNING"; + colorPattern = "\x1b[33m%s\x1b[0m%s"; + break; + } + case LOGGER_MESSAGE_TYPE_INFO: { + prefix = "INFORMATION"; + colorPattern = "\x1b[32m%s\x1b[0m%s"; + break; + } + default: + break; + } + message = loggerMessage.message; + } else { + message = loggerMessage; + } + //Выдаём сообщение + console.log(colorPattern, prefix + ": ", message); + } +} + +//----------------- +// Интерфейс модуля +//----------------- + +exports.LOGGER_MESSAGE_TYPE_ERROR = LOGGER_MESSAGE_TYPE_ERROR; +exports.LOGGER_MESSAGE_TYPE_WARN = LOGGER_MESSAGE_TYPE_WARN; +exports.LOGGER_MESSAGE_TYPE_INFO = LOGGER_MESSAGE_TYPE_INFO; +exports.LoggerMessage = LoggerMessage; +exports.Logger = Logger; diff --git a/core/server_errors.js b/core/server_errors.js new file mode 100644 index 0000000..6ba9978 --- /dev/null +++ b/core/server_errors.js @@ -0,0 +1,23 @@ +/* + Сервис интеграции ПП Парус 8 с WEB API + Модуль ядра: ошибки системы +*/ + +//------------ +// Тело модуля +//------------ + +//Общая ошибка системы +class ServerError extends Error { + //Конструктор + constructor(code, message) { + super(message); + this.code = code; + } +} + +//----------------- +// Интерфейс модуля +//----------------- + +exports.ServerError = ServerError; diff --git a/core/utils.js b/core/utils.js new file mode 100644 index 0000000..ecce4ef --- /dev/null +++ b/core/utils.js @@ -0,0 +1,78 @@ +/* + Сервис интеграции ПП Парус 8 с WEB API + Модуль ядра: вспомогательные функции +*/ + +//---------------------- +// Подключение библиотек +//---------------------- + +const { MODULES_PATH_EX } = require("@core/constants.js"); //Глобавльные константы системы + +//------------ +// Тело модуля +//------------ + +//Проверка на функцию +const isFunction = functionToCheck => { + return functionToCheck && {}.toString.call(functionToCheck) === "[object Function]"; +}; + +//Проверка объекта на наличие списка функций +const haveFunctions = (obj, list) => { + //Объявим результат + let res = true; + //Если есть что проверять + if (obj && list) { + //И если пришел массив наименований функций + if (Array.isArray(list)) { + list.forEach(fn => { + if (!isFunction(obj[fn])) res = false; + }); + } else { + res = false; + } + } else { + res = false; + } + //Вернем результат + return res; +}; + +//Проверка корректности интерфейса модуля +const checkModuleInterface = (module, interface) => { + //Объявим результат + let res = true; + //Если есть что проверять + if (module && interface) { + //Eсли есть список функций + if (interface.functions) { + //Проверим их наличие + res = haveFunctions(module, interface.functions); + } else { + res = false; + } + } else { + res = false; + } + //Вернем результат + return res; +}; + +//Формирование полного пути к подключаемому модулю +const makeModuleFullPath = moduleName => { + if (moduleName) { + return MODULES_PATH_EX + "/" + moduleName; + } else { + return ""; + } +}; + +//----------------- +// Интерфейс модуля +//----------------- + +exports.isFunction = isFunction; +exports.haveFunctions = haveFunctions; +exports.checkModuleInterface = checkModuleInterface; +exports.makeModuleFullPath = makeModuleFullPath; diff --git a/index.js b/index.js index 2e333d8..1a467f5 100644 --- a/index.js +++ b/index.js @@ -1,62 +1,78 @@ -var oracledb = require("oracledb"); -var dbConfig = require("./config.js"); +/* + Сервис интеграции ПП Парус 8 с WEB API + Точка входа в сервер приложений +*/ +require("module-alias/register"); +const cfg = require("./config.js"); +const { Logger } = require("@core/logger.js"); +const db = require("@core/db_connector.js"); +const { ServerError } = require("@core/server_errors.js"); +const parus = require("@modules/parus_db.js"); +const utls = require("@core/utils.js"); -// Get a non-pooled connection -oracledb.getConnection( - { - user: dbConfig.user, - password: dbConfig.password, - connectString: dbConfig.connectString - }, - function(err, connection) { - if (err) { - console.error(err.message); - return; - } - connection.execute( - // The statement to execute - "SELECT rn, agnabbr FROM agnlist WHERE rn = :id", +let a = new db.DBConnector(cfg.dbConnect); +a.connect() + .then(res => { + console.log(res); + setTimeout(() => { + a.disconnect() + .then(res => { + console.log("DISCONNECTED"); + }) + .catch(e => { + console.log(e.code + ": " + e.message); + }); + }, 2000); + }) + .catch(e => { + console.log(e.code + ": " + e.message); + }); - // The "bind value" 180 for the bind variable ":id" - [1431890], +/* - // execute() options argument. Since the query only returns one - // row, we can optimize memory usage by reducing the default - // maxRows value. For the complete list of other options see - // the documentation. - { - maxRows: 1 - //, outFormat: oracledb.OBJECT // query result format - //, extendedMetaData: true // get extra metadata - //, fetchArraySize: 100 // internal buffer allocation size for tuning - }, +const log = new Logger(); +log.error("Это ошибка"); +log.warn("Предупреждение это"); +log.info("Просто информация"); - // The callback function handles the SQL execution results - function(err, result) { - if (err) { - console.error(err.message); - setTimeout(() => { - doRelease(connection); - }, 2000); - return; - } - console.log(result.metaData); // [ { name: 'DEPARTMENT_ID' }, { name: 'DEPARTMENT_NAME' } ] - console.log(result.rows); // [ [ 180, 'Construction' ] ] - setTimeout(() => { - doRelease(connection); - }, 2000); - } - ); - } -); -// Note: connections should always be released when not needed -function doRelease(connection) { - connection.close(function(err) { - if (err) { - console.log("Connection closed with erros: " + err.message); + +const test = async prms => { + return new Promise((resolve, reject) => { + if (prms == 0) { + reject(new ServerError(1234, "Ошибка!")); } else { - console.log("Connection closed - no erros"); + setTimeout(() => { + resolve(prms + 1); + }, 1000); } }); -} +}; + +const callTest = async prms => { + try { + console.log("in async before"); + let a = await test(prms); + console.log("in async after " + a); + return a; + } catch (e) { + console.log("in async I'm here: " + e.code + " - " + e.message); + throw e; + } +}; + +process.on("unhandledRejection", err => { + console.error("PROCESS ERROR: " + err.code + " - " + err.message); + process.exit(0); +}); + +console.log("BEFORE"); +callTest(0) + .then(result => { + console.log("MAIN RESULT: " + result); + }) + .catch(err => { + console.error("MAIN ERROR: " + err.code + " - " + err.message); + }); +console.log("AFTER"); +*/ diff --git a/package-lock.json b/package-lock.json index b6139cd..2873169 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,16 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "module-alias": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.1.0.tgz", + "integrity": "sha1-w21P0V9/nXES9i+gFThee2WihsE=" + }, "oracledb": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/oracledb/-/oracledb-2.3.0.tgz", diff --git a/package.json b/package.json index 39e6556..339564d 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,12 @@ }, "homepage": "https://github.com/CITKParus/ExchangeService#readme", "dependencies": { + "lodash": "^4.17.11", + "module-alias": "^2.1.0", "oracledb": "^2.3.0" + }, + "_moduleAliases": { + "@core": "core", + "@modules": "modules" } }