瀏覽代碼

Выделение файлов приложения в рабочую директорию

Book Pauk 2 年之前
父節點
當前提交
5d5ad40f4e
共有 8 個文件被更改,包括 158 次插入117 次删除
  1. 3 5
      .gitignore
  2. 2 2
      package.json
  3. 4 8
      server/config/base.js
  4. 33 12
      server/config/index.js
  5. 2 6
      server/config/production.js
  6. 5 8
      server/core/Reader/ReaderWorker.js
  7. 58 17
      server/index.js
  8. 51 59
      server/routes.js

+ 3 - 5
.gitignore

@@ -1,5 +1,3 @@
-/node_modules
-/server/data
-/server/public
-/server/ipfs
-/dist
+/node_modules
+/server/.liberama*
+/dist

+ 2 - 2
package.json

@@ -1,5 +1,5 @@
 {
-  "name": "Liberama",
+  "name": "liberama",
   "version": "0.12.2",
   "author": "Book Pauk <bookpauk@gmail.com>",
   "license": "CC0-1.0",
@@ -8,7 +8,7 @@
     "node": ">=16.16.0"
   },
   "scripts": {
-    "dev": "nodemon --inspect --ignore server/public --ignore server/data --ignore client --exec 'node server'",
+    "dev": "nodemon --inspect --ignore server/.liberama --ignore client --exec 'node server'",
     "build:client": "webpack --config build/webpack.prod.config.js",
     "build:linux": "npm run build:client && node build/linux && pkg -t node16-linux-x64 -C GZip -o dist/linux/liberama .",
     "build:win": "npm run build:client && node build/win && pkg -t node16-win-x64 -C GZip -o dist/win/liberama .",

+ 4 - 8
server/config/base.js

@@ -2,18 +2,14 @@ const path = require('path');
 const pckg = require('../../package.json');
 
 const execDir = path.resolve(__dirname, '..');
-const dataDir = `${execDir}/data`;
 
 module.exports = {
     branch: 'unknown',
     version: pckg.version,
     name: pckg.name,
 
-    dataDir: dataDir,
-    tempDir: `${dataDir}/tmp`,
-    logDir: `${dataDir}/log`,
-    publicDir: `${execDir}/public`,
-    uploadDir: `${execDir}/public/upload`,
+    execDir,
+
     loggingEnabled: true,
 
     maxUploadFileSize: 50*1024*1024,//50Мб
@@ -48,13 +44,13 @@ module.exports = {
     servers: [
         {
             serverName: '1',
-            mode: 'normal', //'none', 'normal', 'site', 'reader', 'omnireader', 'liberama.top', 'book_update_checker'
+            mode: 'reader', //'reader', 'omnireader', 'liberama.top', 'book_update_checker'
             ip: '0.0.0.0',
             port: '33080',
         },
         /*{
             serverName: '2',
-            mode: 'book_update_checker', //'none', 'normal', 'site', 'reader', 'omnireader', 'liberama.top', 'book_update_checker'
+            mode: 'book_update_checker',
             isHttps: true,
             keysFile: 'server',
             ip: '0.0.0.0',

+ 33 - 12
server/config/index.js

@@ -1,4 +1,5 @@
 const _ = require('lodash');
+const path = require('path');
 const fs = require('fs-extra');
 
 const branchFilename = __dirname + '/application_env';
@@ -29,7 +30,7 @@ class ConfigManager {
         return instance;
     }
 
-    async init() {
+    async init(dataDir) {
         if (this.inited)
             throw new Error('already inited');
 
@@ -44,10 +45,17 @@ class ConfigManager {
         process.env.NODE_ENV = this.branch;
 
         this.branchConfigFile = __dirname + `/${this.branch}.js`;
-        this._config = require(this.branchConfigFile);
+        const config = require(this.branchConfigFile);
 
-        await fs.ensureDir(this._config.dataDir);
-        this._userConfigFile = `${this._config.dataDir}/config.json`;
+        if (dataDir) {
+            config.dataDir = path.resolve(dataDir);
+        } else {
+            config.dataDir = `${config.execDir}/.${config.name}`;
+        }
+
+        await fs.ensureDir(config.dataDir);
+        this._userConfigFile = `${config.dataDir}/config.json`;
+        this._config = config;
 
         this.inited = true;
     }
@@ -72,15 +80,28 @@ class ConfigManager {
     }
 
     async load() {
-        if (!this.inited)
-            throw new Error('not inited');
-        if (!await fs.pathExists(this.userConfigFile)) {
-            await this.save();
-            return;
+        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'));
+                const config = _.pick(data, propsToSave);
+
+                this.config = config;
+
+                //сохраним конфиг, если не все атрибуты присутствуют в файле конфига
+                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}`);
         }
-
-        const data = await fs.readFile(this.userConfigFile, 'utf8');
-        this.config = JSON.parse(data);
     }
 
     async save() {

+ 2 - 6
server/config/production.js

@@ -2,15 +2,11 @@ const path = require('path');
 const base = require('./base');
 
 const execDir = path.dirname(process.execPath);
-const dataDir = `${execDir}/data`;
 
 module.exports = Object.assign({}, base, {
     branch: 'production',
-    dataDir: dataDir,
-    tempDir: `${dataDir}/tmp`,
-    logDir: `${dataDir}/log`,
-    publicDir: `${execDir}/public`,
-    uploadDir: `${execDir}/public/upload`,
+
+    execDir,
 
     servers: [
         {

+ 5 - 8
server/core/Reader/ReaderWorker.js

@@ -29,9 +29,6 @@ class ReaderWorker {
             this.config.tempDownloadDir = `${config.tempDir}/download`;
             fs.ensureDirSync(this.config.tempDownloadDir);
 
-            this.config.tempPublicDir = `${config.publicDir}/tmp`;
-            fs.ensureDirSync(this.config.tempPublicDir);
-
             this.workerState = new WorkerState();
             this.down = new FileDownloader(config.maxUploadFileSize);
             this.decomp = new FileDecompressor(3*config.maxUploadFileSize);
@@ -55,7 +52,7 @@ class ReaderWorker {
                     moveToRemote: true,
                 },
                 {
-                    dir: this.config.uploadDir,
+                    dir: this.config.uploadPublicDir,
                     remoteDir: '/upload',
                     maxSize: this.config.maxUploadPublicDirSize,
                     moveToRemote: true,
@@ -119,7 +116,7 @@ class ReaderWorker {
                 await fs.writeFile(downloadedFilename, downdata);
             } else {//uploaded file
                 const fileHash = url.substr(7);
-                downloadedFilename = `${this.config.uploadDir}/${fileHash}`;
+                downloadedFilename = `${this.config.uploadPublicDir}/${fileHash}`;
                 if (!await fs.pathExists(downloadedFilename)) {
                     //если удалено из upload, попробуем восстановить из удаленного хранилища
                     try {
@@ -227,7 +224,7 @@ class ReaderWorker {
 
     async saveFile(file) {
         const hash = await utils.getFileHash(file.path, 'sha256', 'hex');
-        const outFilename = `${this.config.uploadDir}/${hash}`;
+        const outFilename = `${this.config.uploadPublicDir}/${hash}`;
 
         if (!await fs.pathExists(outFilename)) {
             await fs.move(file.path, outFilename);
@@ -242,7 +239,7 @@ class ReaderWorker {
 
     async saveFileBuf(buf) {
         const hash = await utils.getBufHash(buf, 'sha256', 'hex');
-        const outFilename = `${this.config.uploadDir}/${hash}`;
+        const outFilename = `${this.config.uploadPublicDir}/${hash}`;
 
         if (!await fs.pathExists(outFilename)) {
             await fs.writeFile(outFilename, buf);
@@ -255,7 +252,7 @@ class ReaderWorker {
     }
 
     async uploadFileTouch(url) {
-        const outFilename = `${this.config.uploadDir}/${url.replace('disk://', '')}`;
+        const outFilename = `${this.config.uploadPublicDir}/${url.replace('disk://', '')}`;
 
         await utils.touchFile(outFilename);
 

+ 58 - 17
server/index.js

@@ -1,7 +1,6 @@
 require('tls').DEFAULT_MIN_VERSION = 'TLSv1';
 
 const fs = require('fs-extra');
-const argv = require('minimist')(process.argv.slice(2));
 const express = require('express');
 const compression = require('compression');
 const http = require('http');
@@ -11,42 +10,84 @@ const WebSocket = require ('ws');
 const ayncExit = new (require('./core/AsyncExit'))();
 
 let log = null;
+let config;
+let argv;
+let branch = '';
+const argvStrings = ['host', 'port', 'app-dir', 'lib-dir', 'inpx'];
 
 const maxPayloadSize = 50;//in MB
 
+function versionText(config) {
+    return `${config.name} v${config.version}, Node.js ${process.version}`;
+}
+
+function showHelp(defaultConfig) {
+    console.log(versionText(defaultConfig));
+    console.log(
+`Usage: ${defaultConfig.name} [options]
+
+Options:
+  --help              Print ${defaultConfig.name} command line options
+  --app-dir=<dirpath> Set application working directory, default: <execDir>/.${defaultConfig.name}
+  --auto-repair       Force auto repairing of corrupted database on start
+`
+    );
+}
+
 async function init() {
+    argv = require('minimist')(process.argv.slice(2), {string: argvStrings});
+    const dataDir = argv['app-dir'];
+
     //config
     const configManager = new (require('./config'))();//singleton
-    await configManager.init();
-    configManager.userConfigFile = argv.config;
-    await configManager.load();
-    const config = configManager.config;
+    await configManager.init(dataDir);
+    const defaultConfig = configManager.config;
 
-    //logger
-    const appLogger = new (require('./core/AppLogger'))();//singleton
-    await appLogger.init(config);
-    log = appLogger.log;
+    await configManager.load();
+    config = configManager.config;
+    branch = config.branch;
 
     //dirs
-    log(`${config.name} v${config.version}, Node.js ${process.version}`);
-    log('Initializing');
+    config.tempDir = `${config.dataDir}/tmp`;
+    config.logDir = `${config.dataDir}/log`;
+    config.publicDir = `${config.dataDir}/public`;
+    config.publicFilesDir = `${config.dataDir}/public-files`;
+    config.tempPublicDir = `${config.publicFilesDir}/tmp`;
+    config.uploadPublicDir = `${config.publicFilesDir}/upload`;
+
+    configManager.config = config;///!!!
 
     await fs.ensureDir(config.dataDir);
-    await fs.ensureDir(config.uploadDir);
+    await fs.ensureDir(config.publicDir);
+    await fs.ensureDir(config.tempPublicDir);
+    await fs.ensureDir(config.uploadPublicDir);
 
     await fs.ensureDir(config.tempDir);
     await fs.emptyDir(config.tempDir);
 
-    const appDir = `${config.publicDir}/app`;
-    const appNewDir = `${config.publicDir}/app_new`;
-    if (await fs.pathExists(appNewDir)) {
-        await fs.remove(appDir);
-        await fs.move(appNewDir, appDir);
+    //logger
+    const appLogger = new (require('./core/AppLogger'))();//singleton
+    await appLogger.init(config);
+    log = appLogger.log;
+
+    //cli
+    if (argv.help) {
+        showHelp(defaultConfig);
+        ayncExit.exit(0);
+    } else {
+        log(versionText(config));
+        log('Initializing');
     }
 
     //connections
     const jembaConnManager = new (require('./db/JembaConnManager'))();//singleton
     await jembaConnManager.init(config, argv['auto-repair']);
+
+    //web app
+    if (branch !== 'development') {
+        //const createWebApp = require('./createWebApp');
+        //await createWebApp(config);
+    }
 }
 
 async function main() {

+ 51 - 59
server/routes.js

@@ -1,5 +1,4 @@
 const fs = require('fs-extra');
-const path = require('path');
 
 const express = require('express');
 const multer = require('multer');
@@ -19,15 +18,9 @@ function initRoutes(app, wss, config) {
 
     initStatic(app, config);
         
-    const misc = new c.MiscController(config);
     const reader = new c.ReaderController(config);
-    const worker = new c.WorkerController(config);
     new c.WebSocketController(wss, config);
 
-    //access
-    const [aAll, aNormal, aSite, aReader, aOmnireader] = // eslint-disable-line no-unused-vars
-        [config.mode, 'normal', 'site', 'reader', 'omnireader'];
-
     //multer
     const storage = multer.diskStorage({
         destination: (req, file, cb) => {
@@ -41,42 +34,29 @@ function initRoutes(app, wss, config) {
 
     //routes
     const routes = [
-        ['POST', '/api/config', misc.getConfig.bind(misc), [aAll], {}],
-        ['POST', '/api/reader/load-book', reader.loadBook.bind(reader), [aAll], {}],
-        ['POST', '/api/reader/storage', reader.storage.bind(reader), [aAll], {}],
-        ['POST', '/api/reader/upload-file', [upload.single('file'), reader.uploadFile.bind(reader)], [aAll], {}],
-        ['POST', '/api/worker/get-state', worker.getState.bind(worker), [aAll], {}],
+        ['POST', '/api/reader/upload-file', [upload.single('file'), reader.uploadFile.bind(reader)]],
     ];
 
     //to app
     for (let route of routes) {
         let callbacks = [];
-        let [httpMethod, path, controllers, access, options] = route;
+        let [httpMethod, path, controllers] = route;
         let controller = controllers;
         if (Array.isArray(controllers)) {
             controller = controllers[controllers.length - 1];
             callbacks = controllers.slice(0, -1);
         }
 
-        access = new Set(access);
-
-        let callback = () => {};
-        if (access.has(config.mode)) {//allowed
-            callback = async function(req, res) {
-                try {
-                    const result = await controller(req, res, options);
-
-                    if (result !== false)
-                        res.send(result);
-                } catch (e) {
-                    res.status(500).send({error: e.message});
-                }
-            };
-        } else {//forbidden
-            callback = async function(req, res) {
-                res.status(403);
-            };
-        }
+        const callback = async function(req, res) {
+            try {
+                const result = await controller(req, res);
+
+                if (result !== false)
+                    res.send(result);
+            } catch (e) {
+                res.status(500).send({error: e.message});
+            }
+        };
         callbacks.push(callback);
 
         switch (httpMethod) {
@@ -96,42 +76,54 @@ function initStatic(app, config) {
     const readerWorker = new ReaderWorker(config);
 
     //восстановление файлов в /tmp и /upload из webdav-storage, при необходимости
-    app.use(async(req, res, next) => {
-        if ((req.method !== 'GET' && req.method !== 'HEAD') ||
-            !(req.path.indexOf('/tmp/') === 0 || req.path.indexOf('/upload/') === 0)
-            ) {
-            return next();
-        }
+    app.use('/tmp',
+        async(req, res, next) => {
+            if (req.method !== 'GET' && req.method !== 'HEAD') {
+                return next();
+            }
 
-        const filePath = `${config.publicDir}${req.path}`;
+            const filePath = `${config.tempPublicDir}${req.path}`;
 
-        //восстановим
-        try {
-            if (!await fs.pathExists(filePath)) {
-                if (req.path.indexOf('/tmp/') === 0) {
+            //восстановим
+            try {
+                if (!await fs.pathExists(filePath))
                     await readerWorker.restoreRemoteFile(req.path, '/tmp');
-                } else if (req.path.indexOf('/upload/') === 0) {
-                    await readerWorker.restoreRemoteFile(req.path, '/upload');
-                }
+            } catch(e) {
+                log(LM_ERR, `static::restoreRemoteFile ${filePath} > ${e.message}`);
             }
-        } catch(e) {
-            log(LM_ERR, `static::restoreRemoteFile ${req.path} > ${e.message}`);
-        }
-
-        return next();
-    });
 
-    const tmpDir = `${config.publicDir}/tmp`;
-    app.use(express.static(config.publicDir, {
-        maxAge: '30d',
-
-        setHeaders: (res, filePath) => {
-            if (path.dirname(filePath) == tmpDir) {
+            return next();
+        },
+        express.static(config.tempPublicDir, {
+            setHeaders: (res) => {
                 res.set('Content-Type', 'application/xml');
                 res.set('Content-Encoding', 'gzip');
+            },
+        })
+    );
+
+    app.use('/upload',
+        async(req, res, next) => {
+            if (req.method !== 'GET' && req.method !== 'HEAD') {
+                return next();
+            }
+
+            const filePath = `${config.uploadPublicDir}${req.path}`;
+
+            //восстановим
+            try {
+                if (!await fs.pathExists(filePath))
+                    await readerWorker.restoreRemoteFile(req.path, '/upload');
+            } catch(e) {
+                log(LM_ERR, `static::restoreRemoteFile ${filePath} > ${e.message}`);
             }
+
+            return next();
         },
-    }));
+        express.static(config.uploadPublicDir)
+    );
+
+    app.use(express.static(config.publicDir));
 }
 
 module.exports = {