瀏覽代碼

Работа над RemoteLib

Book Pauk 2 年之前
父節點
當前提交
e6dfe4d221

+ 10 - 5
server/config/base.js

@@ -2,7 +2,6 @@ const path = require('path');
 const pckg = require('../../package.json');
 const pckg = require('../../package.json');
 
 
 const execDir = path.resolve(__dirname, '..');
 const execDir = path.resolve(__dirname, '..');
-const dataDir = `${execDir}/.${pckg.name}`;
 
 
 module.exports = {
 module.exports = {
     branch: 'unknown',
     branch: 'unknown',
@@ -10,10 +9,6 @@ module.exports = {
     name: pckg.name,
     name: pckg.name,
 
 
     execDir,
     execDir,
-    dataDir,
-    tempDir: `${dataDir}/tmp`,
-    logDir: `${dataDir}/log`,
-    publicDir: `${dataDir}/public`,
 
 
     accessPassword: '',
     accessPassword: '',
     bookReadLink: '',
     bookReadLink: '',
@@ -27,6 +22,16 @@ module.exports = {
 
 
     webConfigParams: ['name', 'version', 'branch', 'bookReadLink'],
     webConfigParams: ['name', 'version', 'branch', 'bookReadLink'],
 
 
+    allowRemoteLib: false,
+    remoteLib: false,
+    /*
+    allowRemoteLib: true, // на сервере
+    remoteLib: { // на клиенте
+        accessPassword: '',
+        url: 'wss://remoteInpxWeb.ru',
+    },
+    */
+
     server: {
     server: {
         ip: '0.0.0.0',
         ip: '0.0.0.0',
         port: '22380',
         port: '22380',

+ 14 - 4
server/config/index.js

@@ -1,4 +1,5 @@
 const _ = require('lodash');
 const _ = require('lodash');
+const path = require('path');
 const fs = require('fs-extra');
 const fs = require('fs-extra');
 
 
 const branchFilename = __dirname + '/application_env';
 const branchFilename = __dirname + '/application_env';
@@ -12,6 +13,8 @@ const propsToSave = [
     'cacheCleanInterval',
     'cacheCleanInterval',
     'inpxCheckInterval',
     'inpxCheckInterval',
     'lowMemoryMode',
     'lowMemoryMode',
+    'allowRemoteLib',
+    'remoteLib',
     'server',
     'server',
 ];
 ];
 
 
@@ -29,7 +32,7 @@ class ConfigManager {
         return instance;
         return instance;
     }
     }
 
 
-    async init() {
+    async init(dataDir) {
         if (this.inited)
         if (this.inited)
             throw new Error('already inited');
             throw new Error('already inited');
 
 
@@ -44,10 +47,17 @@ class ConfigManager {
         process.env.NODE_ENV = this.branch;
         process.env.NODE_ENV = this.branch;
 
 
         this.branchConfigFile = __dirname + `/${this.branch}.js`;
         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;
         this.inited = true;
     }
     }

+ 0 - 6
server/config/production.js

@@ -1,18 +1,12 @@
 const path = require('path');
 const path = require('path');
-const pckg = require('../../package.json');
 const base = require('./base');
 const base = require('./base');
 
 
 const execDir = path.dirname(process.execPath);
 const execDir = path.dirname(process.execPath);
-const dataDir = `${execDir}/.${pckg.name}`;
 
 
 module.exports = Object.assign({}, base, {
 module.exports = Object.assign({}, base, {
     branch: 'production',
     branch: 'production',
 
 
     execDir,
     execDir,
-    dataDir,
-    tempDir: `${dataDir}/tmp`,
-    logDir: `${dataDir}/log`,
-    publicDir: `${dataDir}/public`,
 
 
     server: {
     server: {
         ip: '0.0.0.0',
         ip: '0.0.0.0',

+ 15 - 1
server/controllers/WebSocketController.js

@@ -1,5 +1,6 @@
-const WebSocket = require ('ws');
+const fs = require('fs-extra');
 const _ = require('lodash');
 const _ = require('lodash');
+const WebSocket = require ('ws');
 
 
 const WorkerState = require('../core/WorkerState');//singleton
 const WorkerState = require('../core/WorkerState');//singleton
 const WebWorker = require('../core/WebWorker');//singleton
 const WebWorker = require('../core/WebWorker');//singleton
@@ -83,6 +84,9 @@ class WebSocketController {
                 case 'get-book-link':
                 case 'get-book-link':
                     await this.getBookLink(req, ws); break;
                     await this.getBookLink(req, ws); break;
 
 
+                case 'get-inpx-file':
+                    await this.getInpxFile(req, ws); break;
+
                 default:
                 default:
                     throw new Error(`Action not found: ${req.action}`);
                     throw new Error(`Action not found: ${req.action}`);
             }
             }
@@ -162,6 +166,16 @@ class WebSocketController {
 
 
         this.send(result, req, ws);
         this.send(result, req, ws);
     }
     }
+
+    async getInpxFile(req, ws) {
+        if (!this.config.allowRemoteLib)
+            throw new Error('Remote lib access disabled');
+
+        const data = await fs.readFile(this.config.inpxFile, 'base64');
+
+        this.send({data}, req, ws);
+    }
+
 }
 }
 
 
 module.exports = WebSocketController;
 module.exports = WebSocketController;

+ 56 - 0
server/core/RemoteLib.js

@@ -0,0 +1,56 @@
+const fs = require('fs-extra');
+const utils = require('./utils');
+
+const WebSocketConnection = require('./WebSocketConnection');
+
+//singleton
+let instance = null;
+
+class RemoteLib {
+    constructor(config) {
+        if (!instance) {
+            this.config = config;
+
+            this.wsc = new WebSocketConnection(config.remoteLib.url, 10, 30, {rejectUnauthorized: false});
+            if (config.remoteLib.accessPassword)
+                this.accessToken = utils.getBufHash(config.remoteLib.accessPassword, 'sha256', 'hex');
+
+            this.inpxFile = `${config.tempDir}/${utils.randomHexString(20)}`;
+            this.lastUpdateTime = 0;
+
+            instance = this;
+        }
+
+        return instance;
+    }
+
+    async wsRequest(query) {
+        if (this.accessToken)
+            query.accessToken = this.accessToken;
+
+        const response = await this.wsc.message(
+            await this.wsc.send(query, 60),
+            60
+        );
+
+        if (response.error)
+            throw new Error(response.error);
+
+        return response;
+    }
+
+    async getInpxFile(getPeriod = 0) {
+        if (getPeriod && Date.now() - this.lastUpdateTime < getPeriod)
+            return this.inpxFile;
+
+        const response = await this.wsRequest({action: 'get-inpx-file'});
+
+        await fs.writeFile(this.inpxFile, response.data, 'base64');
+
+        this.lastUpdateTime = Date.now();
+
+        return this.inpxFile;
+    }
+}
+
+module.exports = RemoteLib;

+ 7 - 1
server/core/WebWorker.js

@@ -5,11 +5,12 @@ const zlib = require('zlib');
 const _ = require('lodash');
 const _ = require('lodash');
 
 
 const ZipReader = require('./ZipReader');
 const ZipReader = require('./ZipReader');
-const WorkerState = require('./WorkerState');
+const WorkerState = require('./WorkerState');//singleton
 const { JembaDbThread } = require('jembadb');
 const { JembaDbThread } = require('jembadb');
 const DbCreator = require('./DbCreator');
 const DbCreator = require('./DbCreator');
 const DbSearcher = require('./DbSearcher');
 const DbSearcher = require('./DbSearcher');
 const InpxHashCreator = require('./InpxHashCreator');
 const InpxHashCreator = require('./InpxHashCreator');
+const RemoteLib = require('./RemoteLib');//singleton
 
 
 const ayncExit = new (require('./AsyncExit'))();
 const ayncExit = new (require('./AsyncExit'))();
 const log = new (require('./AppLogger'))().log;//singleton
 const log = new (require('./AppLogger'))().log;//singleton
@@ -505,6 +506,11 @@ class WebWorker {
                 while (this.myState != ssNormal)
                 while (this.myState != ssNormal)
                     await utils.sleep(1000);
                     await utils.sleep(1000);
 
 
+                if (this.config.remoteLib) {
+                    const remoteLib = new RemoteLib(this.config);
+                    await remoteLib.getInpxFile(60*1000);
+                }
+
                 const newInpxHash = await inpxHashCreator.getHash();
                 const newInpxHash = await inpxHashCreator.getHash();
 
 
                 const dbConfig = await this.dbConfig();
                 const dbConfig = await this.dbConfig();

+ 50 - 46
server/index.js

@@ -6,16 +6,18 @@ const compression = require('compression');
 const http = require('http');
 const http = require('http');
 const WebSocket = require ('ws');
 const WebSocket = require ('ws');
 
 
-const ayncExit = new (require('./core/AsyncExit'))();
+const RemoteLib = require('./core/RemoteLib');//singleton
 const utils = require('./core/utils');
 const utils = require('./core/utils');
 
 
+const ayncExit = new (require('./core/AsyncExit'))();
+
 const maxPayloadSize = 50;//in MB
 const maxPayloadSize = 50;//in MB
 
 
 let log;
 let log;
 let config;
 let config;
 let argv;
 let argv;
 let branch = '';
 let branch = '';
-const argvStrings = ['lib-dir', 'inpx'];
+const argvStrings = ['lib-dir', 'app-dir', 'inpx'];
 
 
 function showHelp() {
 function showHelp() {
     console.log(utils.versionText(config));
     console.log(utils.versionText(config));
@@ -24,6 +26,7 @@ function showHelp() {
 
 
 Options:
 Options:
   --help              Print ${config.name} command line options
   --help              Print ${config.name} command line options
+  --app-dir=<dirpath> Set application working directory, default: "<execDir>/.${config.name}"
   --lib-dir=<dirpath> Set library directory, default: the same as ${config.name} executable's
   --lib-dir=<dirpath> Set library directory, default: the same as ${config.name} executable's
   --inpx=<filepath>   Set INPX collection file, default: the one that found in library dir
   --inpx=<filepath>   Set INPX collection file, default: the one that found in library dir
   --recreate          Force recreation of the search database on start
   --recreate          Force recreation of the search database on start
@@ -33,25 +36,30 @@ Options:
 
 
 async function init() {
 async function init() {
     argv = require('minimist')(process.argv.slice(2), {string: argvStrings});
     argv = require('minimist')(process.argv.slice(2), {string: argvStrings});
+    const dataDir = argv['app-dir'];
 
 
     //config
     //config
     const configManager = new (require('./config'))();//singleton
     const configManager = new (require('./config'))();//singleton
-    await configManager.init();
-    //configManager.userConfigFile = argv.config;
+    await configManager.init(dataDir);
     await configManager.load();
     await configManager.load();
     config = configManager.config;
     config = configManager.config;
     branch = config.branch;
     branch = config.branch;
 
 
-    //logger
-    const appLogger = new (require('./core/AppLogger'))();//singleton
-    await appLogger.init(config);
-    log = appLogger.log;
-
     //dirs
     //dirs
+    config.tempDir = `${config.dataDir}/tmp`;
+    config.logDir = `${config.dataDir}/log`;
+    config.publicDir = `${config.dataDir}/public`;
+    configManager.config = config;
+
     await fs.ensureDir(config.dataDir);
     await fs.ensureDir(config.dataDir);
     await fs.ensureDir(config.tempDir);
     await fs.ensureDir(config.tempDir);
     await fs.emptyDir(config.tempDir);
     await fs.emptyDir(config.tempDir);
 
 
+    //logger
+    const appLogger = new (require('./core/AppLogger'))();//singleton
+    await appLogger.init(config);
+    log = appLogger.log;
+
     //web app
     //web app
     if (branch !== 'development') {
     if (branch !== 'development') {
         const createWebApp = require('./createWebApp');
         const createWebApp = require('./createWebApp');
@@ -67,52 +75,49 @@ async function init() {
         log('Initializing');
         log('Initializing');
     }
     }
 
 
-    const libDir = argv['lib-dir'];
-    if (libDir) {
-        if (await fs.pathExists(libDir)) {
-            config.libDir = libDir;
+    if (!config.remoteLib) {
+        const libDir = argv['lib-dir'];
+        if (libDir) {
+            if (await fs.pathExists(libDir)) {
+                config.libDir = libDir;
+            } else {
+                throw new Error(`Directory "${libDir}" not exists`);
+            }
         } else {
         } else {
-            throw new Error(`Directory "${libDir}" not exists`);
+            config.libDir = config.execDir;
         }
         }
-    } else {
-        config.libDir = config.execDir;
-    }
 
 
-    if (argv.inpx) {
-        if (await fs.pathExists(argv.inpx)) {
-            config.inpxFile = argv.inpx;
-        } else {
-            throw new Error(`File "${argv.inpx}" not found`);
-        }
-    } else {
-        const inpxFiles = [];
-        await utils.findFiles((file) => {
-            if (path.extname(file) == '.inpx')
-                inpxFiles.push(file);
-        }, config.libDir, false);
-
-        if (inpxFiles.length) {
-            if (inpxFiles.length == 1) {
-                config.inpxFile = inpxFiles[0];
+        if (argv.inpx) {
+            if (await fs.pathExists(argv.inpx)) {
+                config.inpxFile = argv.inpx;
             } else {
             } else {
-                throw new Error(`Found more than one .inpx files: \n${inpxFiles.join('\n')}`);
+                throw new Error(`File "${argv.inpx}" not found`);
             }
             }
         } else {
         } else {
-            throw new Error(`No .inpx files found here: ${config.libDir}`);
+            const inpxFiles = [];
+            await utils.findFiles((file) => {
+                if (path.extname(file) == '.inpx')
+                    inpxFiles.push(file);
+            }, config.libDir, false);
+
+            if (inpxFiles.length) {
+                if (inpxFiles.length == 1) {
+                    config.inpxFile = inpxFiles[0];
+                } else {
+                    throw new Error(`Found more than one .inpx files: \n${inpxFiles.join('\n')}`);
+                }
+            } else {
+                throw new Error(`No .inpx files found here: ${config.libDir}`);
+            }
         }
         }
+    } else {
+        const remoteLib = new RemoteLib(config);
+        config.inpxFile = await remoteLib.getInpxFile();
     }
     }
 
 
     config.recreateDb = argv.recreate || false;
     config.recreateDb = argv.recreate || false;
     config.inpxFilterFile = `${config.execDir}/inpx-web-filter.json`;
     config.inpxFilterFile = `${config.execDir}/inpx-web-filter.json`;
     config.allowUnsafeFilter = argv['unsafe-filter'] || false;
     config.allowUnsafeFilter = argv['unsafe-filter'] || false;
-
-    //app
-    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);
-    }
 }
 }
 
 
 async function main() {
 async function main() {
@@ -124,10 +129,8 @@ async function main() {
     const server = http.createServer(app);
     const server = http.createServer(app);
     const wss = new WebSocket.Server({ server, maxPayload: maxPayloadSize*1024*1024 });
     const wss = new WebSocket.Server({ server, maxPayload: maxPayloadSize*1024*1024 });
 
 
-    const serverConfig = Object.assign({}, config, config.server);
-
     let devModule = undefined;
     let devModule = undefined;
-    if (serverConfig.branch == 'development') {
+    if (branch == 'development') {
         const devFileName = './dev.js'; //require ignored by pkg -50Mb executable size
         const devFileName = './dev.js'; //require ignored by pkg -50Mb executable size
         devModule = require(devFileName);
         devModule = require(devFileName);
         devModule.webpackDevMiddleware(app);
         devModule.webpackDevMiddleware(app);
@@ -152,6 +155,7 @@ async function main() {
         });
         });
     }
     }
 
 
+    const serverConfig = config.server;
     server.listen(serverConfig.port, serverConfig.ip, () => {
     server.listen(serverConfig.port, serverConfig.ip, () => {
         log(`Server is ready on http://${serverConfig.ip}:${serverConfig.port}`);
         log(`Server is ready on http://${serverConfig.ip}:${serverConfig.port}`);
     });
     });