@frangoteam/fuxa
Version:
Web-based Process Visualization (SCADA/HMI/Dashboard) software
348 lines (309 loc) • 10.6 kB
JavaScript
const fs = require('fs');
const path = require('path');
const morgan = require('morgan');
const http = require('http');
const https = require('https');
const socketIO = require('socket.io');
const nopt = require("nopt");
const paths = require('./paths');
const logger = require('./runtime/logger');
const utils = require('./runtime/utils');
var events = require("./runtime/events").create();
const FUXA = require('./fuxa.js');
const express = require('express');
const app = express();
var server;
var settingsFile;
var startTime = new Date();
var knownOpts = {
"help": Boolean,
"port": Number,
"userDir": [path]
};
var shortHands = {
"?":["--help"],
"p":["--port"],
"u":["--userDir"]
};
nopt.invalidHandler = function(k,v,t) {
// TODO: console.log(k,v,t);
}
var parsedArgs = nopt(knownOpts, shortHands, process.argv, 2);
if (parsedArgs.help) {
console.log("FUXA v" + FUXA.version());
console.log("Usage: fuxa [-?] [--port PORT] [--userDir DIR]");
console.log("");
console.log("Options:");
console.log(" -p, --port PORT port to listen on");
console.log(" -u, --userDir DIR use specified user directory");
console.log(" -?, --help show this help");
process.exit();
}
// Define directory
var rootDir = __dirname;
var workDir = path.resolve(process.cwd(), '_appdata');
if (parsedArgs.userDir) {
rootDir = parsedArgs.userDir;
workDir = path.resolve(parsedArgs.userDir, '_appdata');
}
if (!fs.existsSync(workDir)) {
fs.mkdirSync(workDir);
}
// Read app settings
var appSettingsFile = path.join(workDir, 'settings.js');
if (fs.existsSync(appSettingsFile)) {
// _appdata/settings.js exists
settingsFile = appSettingsFile;
} else {
// Not exist, copy from code resource
var defaultSettings = path.join(__dirname, 'settings.default.js');
try {
fs.copyFileSync(defaultSettings, appSettingsFile, fs.constants.COPYFILE_EXCL);
logger.debug('settings.js default created successful!');
} catch (err) {
logger.error(err);
}
settingsFile = appSettingsFile;
}
try {
// load settings and set some app variable
var settings = require(settingsFile);
settings.workDir = workDir;
settings.appDir = __dirname;
settings.packageDir = path.resolve(rootDir, '_pkg');
settings.settingsFile = settingsFile;
settings.environment = process.env.NODE_ENV || 'prod';
settings.uploadFileDir = '_upload_files';
settings.imagesFileDir = path.resolve(rootDir, '_images');
// check new settings from default and merge if not defined
var defSettings = require(path.join(__dirname, 'settings.default.js'));
if (defSettings.version !== settings.version) {
logger.warn("Settings aren't up to date! Please check 'settings.json'.");
// settings = Object.assign(defSettings, settings);
}
} catch (err) {
logger.error('Error loading settings file: ' + settingsFile)
if (err.code == 'MODULE_NOT_FOUND') {
if (err.toString().indexOf(settingsFile) === -1) {
logger.error(err.toString());
}
} else {
logger.error(err);
}
process.exit();
}
// Read user settings
try {
var userSettingsFile = path.join(workDir, 'mysettings.json');
settings.userSettingsFile = userSettingsFile;
if (fs.existsSync(userSettingsFile)) {
var mysettings = JSON.parse(fs.readFileSync(userSettingsFile, 'utf8'));
if (mysettings.language) {
settings.language = mysettings.language;
}
if (mysettings.uiPort) {
settings.uiPort = mysettings.uiPort;
}
if (mysettings.secureEnabled) {
settings.secureEnabled = mysettings.secureEnabled;
settings.tokenExpiresIn = mysettings.tokenExpiresIn;
}
if (mysettings.smtp) {
settings.smtp = mysettings.smtp;
}
}
} catch (err) {
logger.error('Error loading user settings file: ' + userSettingsFile)
}
// Check logger
if (!settings.logDir) {
settings.logDir = path.resolve(rootDir, '_logs');
}
if (!fs.existsSync(settings.logDir)) {
fs.mkdirSync(settings.logDir);
}
logger.init(settings.logDir);
const version = FUXA.version();
if (version.indexOf('beta') > 0) {
logger.warn('FUXA V.' + version);
} else {
logger.info('FUXA V.' + version);
}
// Check storage Database dir
if (!settings.dbDir) {
settings.dbDir = path.resolve(rootDir, '_db');
}
if (!fs.existsSync(settings.dbDir)) {
fs.mkdirSync(settings.dbDir);
}
// Check package folder
if (!fs.existsSync(settings.packageDir)) {
fs.mkdirSync(settings.packageDir);
}
// Check upload file folder
settings.httpUploadFileStatic = 'resources';
settings.uploadFileDir = path.resolve(workDir, settings.uploadFileDir);
if (!fs.existsSync(settings.uploadFileDir)) {
fs.mkdirSync(settings.uploadFileDir);
}
// Check images resources folder
if (!fs.existsSync(settings.imagesFileDir)) {
fs.mkdirSync(settings.imagesFileDir);
}
// Server settings
if (settings.https) {
server = https.createServer(settings.https, function (req, res) { app(req, res); });
} else {
server = http.createServer(function (req, res) { app(req, res); });
}
server.setMaxListeners(0);
const io = socketIO(server);
// Check settings value
var www = path.resolve(__dirname, './dist');
settings.httpStatic = settings.httpStatic || www;
if (parsedArgs.port !== undefined){
settings.uiPort = parsedArgs.port;
} else {
if (settings.uiPort === undefined){
settings.uiPort = 1881;
}
}
settings.uiHost = settings.uiHost || "0.0.0.0";
// Wait ending initialization
events.once('init-runtime-ok', function () {
logger.info('FUXA init in ' + utils.endTime(startTime) + 'ms.');
startFuxa();
});
// Init FUXA
try {
FUXA.init(server, io, settings, logger, events);
} catch(err) {
if (err.code == 'unsupported_version') {
logger.error('Unsupported version of node.js:', process.version);
logger.error('FUXA requires node.js v6 or later');
} else if (err.code == 'not_built') {
logger.error('FUXA has not been built. See README.md for details');
} else {
logger.error('Failed to start server:');
if (err.stack) {
logger.error(err.stack);
} else {
logger.error(err);
}
}
process.exit(1);
}
// Http Server for client UI
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'x-access-token, x-auth-user, Origin, Content-Type, Accept');
next();
try {
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
// logger.info("Client: " + ip, false);
} catch (err) {
}
}
app.use(allowCrossDomain);
app.use('/', express.static(settings.httpStatic));
app.use('/home', express.static(settings.httpStatic));
app.use('/lab', express.static(settings.httpStatic));
app.use('/editor', express.static(settings.httpStatic));
app.use('/device', express.static(settings.httpStatic));
app.use('/rodevice', express.static(settings.httpStatic));
app.use('/users', express.static(settings.httpStatic));
app.use('/view', express.static(settings.httpStatic));
app.use('/' + settings.httpUploadFileStatic, express.static(settings.uploadFileDir));
app.use('/_images', express.static(settings.imagesFileDir));
var accessLogStream = fs.createWriteStream(settings.logDir + '/api.log', {flags: 'a'});
app.use(morgan('combined', { stream: accessLogStream }));
app.use(morgan('dev', {
skip: function (req, res) {
return res.statusCode < 400
}, stream: process.stderr
}));
app.use(morgan('dev', {
skip: function (req, res) {
return res.statusCode >= 400
}, stream: process.stdout
}));
// app.get('/', function (req, res) {
// res.sendFile('/index.html');
// try {
// var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
// logger.info("Client connected: " + ip);
// } catch (err) {
// }
// })
// set api to listen
if (settings.disableServer !== false) {
app.use('/', FUXA.httpApi);
}
function getListenPath() {
var port = settings.serverPort;
if (port === undefined) {
port = settings.uiPort;
}
var listenPath = 'http' + (settings.https ? 's' : '') + '://' +
(settings.uiHost == '::' ? 'localhost' : (settings.uiHost == '0.0.0.0' ? '127.0.0.1' : settings.uiHost)) +
':' + port;
if (settings.httpStatic) {
listenPath += '/';
}
return listenPath;
}
// Start FUXA
function startFuxa() {
FUXA.start().then(function () {
if (settings.httpStatic) {
server.on('error', function (err) {
if (err.errno === 'EADDRINUSE') {
logger.error('server.port-in-use');
logger.error('server.unable-to-listen ', { listenpath: getListenPath() });
} else {
if (err.stack) {
logger.error(err.stack);
} else {
logger.error('server.error ' + err);
}
}
process.exit(1);
});
server.listen(settings.uiPort, settings.uiHost, function () {
settings.serverPort = server.address().port;
process.title = 'FUXA';
logger.info('WebServer is running ' + getListenPath());
});
} else {
logger.info('server.headless-mode');
}
}).catch(function (err) {
logger.error('server.failed-to-start');
if (err.stack) {
logger.error(err.stack);
} else {
logger.error(err);
}
});
}
// Don't wait any more
setTimeout(() => {
events.emit('init-runtime-ok');
}, 60000);
process.on('uncaughtException', function (err) {
if (err.stack) {
logger.error(err.stack);
} else {
logger.error(err);
}
process.exit(1);
});
process.on('SIGINT', function () {
FUXA.stop().then(function() {
process.exit();
});
logger.info('FUXA end!');
process.exit();
});