"use strict"; const _ = require('underscore') const co = require('co'); const fs = require('fs'); const bodyParser = require('body-parser'); const http = require('http'); const express = require('express'); const path = require('path'); const cors = require('cors'); const fileUpload = require('express-fileupload'); const webminController = require('./server/controller/webmin.js'); // Inject 'webstart' command if no argument was given if (process.argv.length === 2) { process.argv.push('direct_webstart'); } module.exports = { duniter: { cliOptions: [ // Webmin options { value: '--webmhost <host>', desc: 'Local network interface to connect to (IP)' }, { value: '--webmport <port>', desc: 'Local network port to connect', parser: parseInt } ], cli: [{ name: 'webstart', desc: 'Starts Duniter as a daemon (background task).', logs: false, onConfiguredExecute: (server, conf, program, params) => co(function*() { yield server.checkConfig() const daemon = server.getDaemon('direct_webstart', 'webstart') yield startDaemon(program, daemon) }) }, { name: 'webrestart', desc: 'Stops Duniter daemon and restart it with its web interface.', logs: false, onConfiguredExecute: (server, conf, program, params) => co(function*() { yield server.checkConfig() const daemon = server.getDaemon('direct_webstart', 'webrestart') yield stopDaemon(daemon) yield startDaemon(program, daemon) }) }, { name: 'direct_webstart', desc: 'Do a webstart', onDatabaseExecute: (server, conf, program, params, startServices, stopServices, stack) => co(function*(){ try { /**************************************** * SPECIALISATION ***************************************/ const app = express(); const HOTE = program.webmhost || 'localhost'; const PORT = program.webmport || 9220; /** * Sur appel de l'URL /abc */ app.use(express.static(path.join(__dirname, '..', 'duniter-ui', 'public'))); app.use(cors()); // File upload for backup API app.use(fileUpload()); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); const wbmin = webminController(server, startServices, stopServices, listDuniterPlugins, stack); const httpServer = http.createServer(app); httpServer.listen(PORT, HOTE); server.logger.info("Web administration accessible at following address: http://%s:%s", HOTE, PORT); require('./server/lib/routes').webmin(wbmin, app); require('./server/lib/routes').webminWS(wbmin)(httpServer); const uiDeps = listDuniterUIPlugins() for (const dep of uiDeps) { // Eventual HTTP routing if (dep.required.duniterUI.route) { const subApp = express() dep.required.duniterUI.route(subApp, server, conf, program, params) app.use('/modules/', subApp) } } const currentBlock = yield server.dal.getCurrentBlockOrNull() if (currentBlock) { yield wbmin.startAllServices() } // Never ending promise return new Promise((resolve) => {}); /****************************************/ } catch (e) { console.error(e); process.exit(1); } }) }] } }; function startDaemon(program, daemon) { return co(function*() { const PORT = program.webmport || 9220 const isPortAlreadyTaken = yield new Promise((resolve) => { isPortTaken(PORT, (err, taken) => err ? reject(err) : resolve(taken)) }) if (isPortAlreadyTaken) { console.error('Port ' + PORT + ' already used.') process.exit(3) } return new Promise((resolve, reject) => daemon.start((err) => { if (err) return reject(err) resolve() })) }) } /** * Checks if a port is already taken by another app. * * Source: https://gist.github.com/timoxley/1689041 * @param port * @param fn */ function isPortTaken(port, fn) { const net = require('net') const tester = net.createServer() .once('error', function (err) { if (err.code != 'EADDRINUSE') return fn(err) fn(null, true) }) .once('listening', function() { tester.once('close', function() { fn(null, false) }) .close() }) .listen(port) } function stopDaemon(daemon) { return new Promise((resolve, reject) => daemon.stop((err) => { err && console.error(err); if (err) return reject(err) resolve() })) } function listDuniterPlugins() { return listPlugins(r => !!r.duniter || !!r.duniterUI) } function listDuniterUIPlugins() { return listPlugins(r => !!r.duniterUI) } function listPlugins(conditionTest) { const uiDependencies = [] const pathToPackageJSON = path.resolve('./package.json') const pkgJSON = JSON.parse(fs.readFileSync(pathToPackageJSON, 'utf8')) const peerDeps = pkgJSON.peerDependencies || {} const allDeps = _.extend(pkgJSON.dependencies || {}, pkgJSON.devDependencies || {}) const deps = Object.keys(allDeps) for (const dep of deps) { try { const required = require(dep) if (required && conditionTest(required)) { uiDependencies.push({ name: dep, version: allDeps[dep], locked: !!peerDeps[dep], required }) } } catch (e) {} } // Special: self dependency (if local package is also a module) if (pkgJSON.main && pkgJSON.main.match(/\.js/)) { // With NW.js, the main is an index.html file, which causes a bug const dep = pkgJSON.name const required = require(path.resolve('./' + pkgJSON.main)) if (required && conditionTest(required)) { uiDependencies.push({ name: dep, version: 'local', locked: true, required }) } } return uiDependencies }