From 175511ba456e574667af49ce880532c3c019060b Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 4 Apr 2024 18:02:16 +0700 Subject: [PATCH] =?UTF-8?q?=D0=92=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=D1=8B=20=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE?= =?UTF-8?q?=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B4=D0=B0=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BF=D1=83=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BA=20=D1=84=D0=B0=D0=B9=D0=BB=D1=83=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=84=D0=B8=D0=B3=D1=83=D1=80=D0=B0=D1=86=D0=B8=D0=B8,?= =?UTF-8?q?=20=D0=B0=20=D0=B2=D1=81=D0=B5=20=D0=BE=D1=81=D1=82=D0=B0=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B8=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D1=83?= =?UTF-8?q?=D0=BA=D0=B0=D0=B7=D0=B0=D1=82=D1=8C=20=D0=B2=20=D0=BD=D0=B5?= =?UTF-8?q?=D0=BC=20=D1=81=D0=B0=D0=BC=D0=BE=D0=BC=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 63 ++++++++++++++++++++++++++++++++---------- server/config/base.js | 6 ++++ server/config/index.js | 50 +++++++++++++++++---------------- server/index.js | 44 +++++++++++++++++++---------- 4 files changed, 110 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 53038cc..c325110 100644 --- a/README.md +++ b/README.md @@ -66,29 +66,63 @@ OPDS-сервер доступен по адресу [http://127.0.0.1:12380/opd Usage: inpx-web [options] Options: - --help Показать опции командной строки - --host= Задать имя хоста для веб сервера, по умолчанию: 0.0.0.0 - --port= Задать порт для веб сервера, по умолчанию: 12380 - --app-dir= Задать рабочую директорию, по умолчанию: /.inpx-web - --lib-dir= Задать директорию библиотеки (с zip-архивами), по умолчанию: там же, где лежит файл приложения - --inpx= Задать путь к файлу .inpx, по умолчанию: тот, что найдется в директории библиотеки - --recreate Принудительно пересоздать поисковую БД при запуске приложения + --help Показать опции командной строки + --host= Задать имя хоста для веб сервера, по умолчанию: 0.0.0.0 + --port= Задать порт для веб сервера, по умолчанию: 12380 + --config= Задать файл конфигурации, по умолчанию: /config.json + --data-dir= (или --app-dir) Задать рабочую директорию, по умолчанию: /.inpx-web + --lib-dir= Задать директорию библиотеки (с zip-архивами), по умолчанию: там же, где лежит файл приложения + --inpx= Задать путь к файлу .inpx, по умолчанию: тот, что найдется в директории библиотеки + --recreate Принудительно пересоздать поисковую БД при запуске приложения + --unsafe-filter Использовать небезопасный фильтр на свой страх и риск ``` ### Конфигурация -При первом запуске в рабочей директории будет создан конфигурационный файл `config.json`: + +По умолчанию, при первом запуске в рабочей директории будет создан конфигурационный файл `config.json`. +При необходимости, можно настроить нужный параметр в этом файле вручную. Параметры командной +строки имеют больший приоритет, чем настройки из `config.json`. + ```js { + // рабочая директория приложения, аналог параметра командной строки --data-dir (или --app-dir) + // пустая строка: использовать значение по умолчанию - /.inpx-web + // где execDir - директория файла приложения + "dataDir": "", + + // директория для хранения временных файлов + // пустая строка: использовать значение по умолчанию - /tmp + // специальное значение "${OS}" указывается для использования системного каталога: + // "${OS}" => "/inpx-web" + "tempDir": "", + + // директория для хранения логов + // пустая строка: использовать значение по умолчанию - /logs + "logDir": "", + // директория библиотеки (с zip-архивами), аналог параметра командной строки --lib-dir - // пустая строка: использовать значение по умолчанию - директорию файла приложения + // пустая строка: использовать значение по умолчанию - директорию файла приложения (execDir) "libDir": "", // путь к файлу .inpx, аналог параметра командной строки --inpx // пустая строка: использовать значение по умолчанию - inpx-файл, что найдется в директории библиотеки "inpx": "", + // конфигурационный файл для фильра по авторам и книгам (см. ниже) + // пустая строка: использовать значение по умолчанию - файл filter.json в директории файла конфигурации + "inpxFilterFile": "", + + // разрешить(true)/запретить(false) перезаписывать файл конфигурации, если появились новые параметры для настройки + // файл перезаписывается с сохранением всех предыдущих настроек и с новыми по умолчанию + // бывает полезно при выходе новых версий приложения + "allowConfigRewrite": false, + + // разрешить(true)/запретить(false) использовать небезопасный фильтр (см. ниже) + // аналог параметра командной строки --unsafe-filter + "allowUnsafeFilter": false, + // пароль для ограничения доступа к веб-интерфейсу сервера // пустое значение - доступ без ограничений "accessPassword": "", @@ -210,9 +244,6 @@ Options: } ``` -При необходимости, можно настроить нужный параметр в этом файле вручную. Параметры командной -строки имеют больший приоритет, чем настройки из `config.json`. - ### Удаленная библиотека @@ -247,8 +278,8 @@ Options: ### Фильтр по авторам и книгам При создании поисковой БД, во время загрузки и парсинга .inpx-файла, имеется возможность -отфильтровать авторов и книги, задав определенные критерии. Для этого небходимо создать -в рабочей директории (там же, где `config.json`) файл `filter.json` следующего вида: +отфильтровать авторов и книги, задав определенные критерии. По умолчанию, для этого небходимо создать +в директории конфигурационного файла (там же, где `config.json`) файл `filter.json` следующего вида: ```json { "info": { @@ -293,8 +324,10 @@ Options: } ``` Использование `filter` небезопасно, т.к. позволяет выполнить произвольный js-код внутри программы, -поэтому запуск приложения в этом случае должен сопровождаться дополнительным параметром командной строки `--unsafe-filter`. +поэтому запуск приложения в этом случае должен сопровождаться дополнительным параметром командной строки `--unsafe-filter` +или разрешением в конфиге `allowUnsafeFilter`. Названия атрибутов inpxRec соответствуют названиям в нижнем регистре из структуры structure.info в .inpx-файле. +Файл `filter.json` можно расположить где угодно, что задается параметром `inpxFilterFile` в конфиге. ### Настройка https с помощью nginx diff --git a/server/config/base.js b/server/config/base.js index 0b36a97..ac76f8d 100644 --- a/server/config/base.js +++ b/server/config/base.js @@ -10,9 +10,15 @@ module.exports = { name: pckg.name, execDir, + dataDir: '', + tempDir: '', + logDir: '', libDir: '', inpx: '', + inpxFilterFile: '', + allowConfigRewrite: false, + allowUnsafeFilter: false, accessPassword: '', accessTimeout: 0, extendedSearch: true, diff --git a/server/config/index.js b/server/config/index.js index 7c8d0e7..fc170e1 100644 --- a/server/config/index.js +++ b/server/config/index.js @@ -5,8 +5,14 @@ const fs = require('fs-extra'); const branchFilename = __dirname + '/application_env'; const propsToSave = [ + 'dataDir', + 'tempDir', + 'logDir', 'libDir', 'inpx', + 'inpxFilterFile', + 'allowConfigRewrite', + 'allowUnsafeFilter', 'accessPassword', 'accessTimeout', 'extendedSearch', @@ -46,7 +52,7 @@ class ConfigManager { return instance; } - async init(dataDir) { + async init(tempDataDir, configFile) { if (this.inited) throw new Error('already inited'); @@ -63,14 +69,16 @@ class ConfigManager { this.branchConfigFile = __dirname + `/${this.branch}.js`; const config = require(this.branchConfigFile); - if (dataDir) { - config.dataDir = path.resolve(dataDir); - } else { - config.dataDir = `${config.execDir}/.${config.name}`; + if (!tempDataDir) { + tempDataDir = `${config.execDir}/.${config.name}`; + } + + if (configFile) { + config.configFile = path.resolve(configFile); + } else { + config.configFile = `${tempDataDir}/config.json`; } - await fs.ensureDir(config.dataDir); - this._userConfigFile = `${config.dataDir}/config.json`; this._config = config; this.inited = true; @@ -86,37 +94,31 @@ class ConfigManager { Object.assign(this._config, value); } - get userConfigFile() { - return this._userConfigFile; - } - - set userConfigFile(value) { - if (value) - this._userConfigFile = value; - } - async load() { try { if (!this.inited) throw new Error('not inited'); - if (await fs.pathExists(this.userConfigFile)) { - const data = JSON.parse(await fs.readFile(this.userConfigFile, 'utf8')); + if (await fs.pathExists(this._config.configFile)) { + const data = JSON.parse(await fs.readFile(this._config.configFile, 'utf8')); const config = _.pick(data, propsToSave); this.config = config; //сохраним конфиг, если не все атрибуты присутствуют в файле конфига - for (const prop of propsToSave) - if (!Object.prototype.hasOwnProperty.call(config, prop)) { - await this.save(); - break; + if (config.allowConfigRewrite) { + for (const prop of propsToSave) { + if (!Object.prototype.hasOwnProperty.call(config, prop)) { + await this.save(); + break; + } } + } } else { await this.save(); } } catch(e) { - throw new Error(`Error while loading "${this.userConfigFile}": ${e.message}`); + throw new Error(`Error while loading "${this._config.configFile}": ${e.message}`); } } @@ -125,7 +127,7 @@ class ConfigManager { throw new Error('not inited'); const dataToSave = _.pick(this._config, propsToSave); - await fs.writeFile(this.userConfigFile, JSON.stringify(dataToSave, null, 4)); + await fs.writeFile(this._config.configFile, JSON.stringify(dataToSave, null, 4)); } } diff --git a/server/index.js b/server/index.js index a083fbe..0a4b847 100644 --- a/server/index.js +++ b/server/index.js @@ -1,5 +1,6 @@ const fs = require('fs-extra'); const path = require('path'); +const os = require('os'); const express = require('express'); const http = require('http'); @@ -13,7 +14,7 @@ let log; let config; let argv; let branch = ''; -const argvStrings = ['host', 'port', 'app-dir', 'lib-dir', 'inpx']; +const argvStrings = ['host', 'port', 'config', 'data-dir', 'app-dir', 'lib-dir', 'inpx']; function showHelp(defaultConfig) { console.log(utils.versionText(defaultConfig)); @@ -21,24 +22,27 @@ function showHelp(defaultConfig) { `Usage: ${defaultConfig.name} [options] Options: - --help Print ${defaultConfig.name} command line options - --host= Set web server host, default: ${defaultConfig.server.host} - --port= Set web server port, default: ${defaultConfig.server.port} - --app-dir= Set application working directory, default: /.${defaultConfig.name} - --lib-dir= Set library directory, default: the same as ${defaultConfig.name} executable's - --inpx= Set INPX collection file, default: the one that found in library dir - --recreate Force recreation of the search database on start + --help Print ${defaultConfig.name} command line options + --host= Set web server host, default: ${defaultConfig.server.host} + --port= Set web server port, default: ${defaultConfig.server.port} + --config= Set config filename, default: /config.json + --data-dir= (or --app-dir) Set application working directory, default: /.${defaultConfig.name} + --lib-dir= Set library directory, default: the same as ${defaultConfig.name} executable's + --inpx= Set INPX collection file, default: the one that found in library dir + --recreate Force recreation of the search database on start + --unsafe-filter Use filter config at your own risk ` ); } async function init() { argv = require('minimist')(process.argv.slice(2), {string: argvStrings}); - const dataDir = argv['app-dir']; + const argvDataDir = argv['data-dir'] || argv['app-dir']; + const configFile = argv['config']; //config const configManager = new (require('./config'))();//singleton - await configManager.init(dataDir); + await configManager.init(argvDataDir, configFile); const defaultConfig = configManager.config; await configManager.load(); @@ -46,8 +50,12 @@ async function init() { branch = config.branch; //dirs - config.tempDir = `${config.dataDir}/tmp`; - config.logDir = `${config.dataDir}/log`; + config.dataDir = config.dataDir || argvDataDir || `${config.execDir}/.${config.name}`; + config.tempDir = config.tempDir || `${config.dataDir}/tmp`; + if (config.tempDir === '${OS}') + config.tempDir = `${os.tmpdir()}/${config.name}` + + config.logDir = config.logDir || `${config.dataDir}/log`; config.publicDir = `${config.dataDir}/public`; config.publicFilesDir = `${config.dataDir}/public-files`; config.rootPathStatic = config.server.root || ''; @@ -127,14 +135,22 @@ async function init() { } config.recreateDb = argv.recreate || false; - config.inpxFilterFile = `${config.dataDir}/filter.json`; - config.allowUnsafeFilter = argv['unsafe-filter'] || false; + config.inpxFilterFile = config.inpxFilterFile || `${path.dirname(config.configFile)}/filter.json`; + config.allowUnsafeFilter = argv['unsafe-filter'] || config.allowUnsafeFilter || false; //web app if (branch !== 'development') { const createWebApp = require('./createWebApp'); await createWebApp(config); } + + //log dirs + for (const prop of ['configFile', 'dataDir', 'tempDir', 'logDir']) { + log(`${prop}: ${config[prop]}`); + } + + if (await fs.pathExists(config.inpxFilterFile)) + log(`inpxFilterFile: ${config.inpxFilterFile}`) } function logQueries(app) {