domotz-remote-pawn
Version:
Domotz Agent
251 lines (210 loc) • 8.46 kB
JavaScript
/** This file is part of Domotz Agent.
* Copyright (C) 2016 Domotz Ltd
*
* Domotz Agent is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Domotz Agent is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Domotz Agent. If not, see <http://www.gnu.org/licenses/>.
**/
/**
*
* Created by Iacopo Papalini <ipapalini@domotz.com> on 08/09/15.
*/
/**
* If the agent is not configured, the local web interface must be enabled
* If the box registration outcome is 'failure', the local web interface must be enabled
* @returns {boolean} True if the web app is enabled, false otherwise.
*/
function isWebAppEnabled(resourceLocator, myConsole) {
if (process.env.BOX_REGISTRATION_OUTCOME === 'failure') {
return true;
}
var isNotConfigured = !resourceLocator.status.isConfigured();
var isPassive = resourceLocator.status.isPassive();
var devMode = process.env.ENABLE_HTTP_TEST_API !== undefined;
var webAppEnabledOverride = isNotConfigured || isPassive || devMode;
var settingHttpLocalInterface = resourceLocator.lodash.get(resourceLocator, 'configuration.settings.http_local_interface', true);
var webAppEnable = webAppEnabledOverride || settingHttpLocalInterface;
myConsole.debug('isWebAppEnabled:%s', webAppEnable);
return webAppEnable;
}
// Starts up an HTTP server that enables the hub setup
var createApp = function (fs, http, express, event, bodyParser, favicon, path, routes, resourceLocator) {
var myConsole = resourceLocator.log.decorateLogs();
var httpLocalInterfaceEnabled = isWebAppEnabled(resourceLocator, myConsole);
var app = express();
app.disable('x-powered-by');
/**
* Listening port: if not available, it will be increased until a free one is found
* @type {number}
*/
var registrationFailedPort = 80;
var boxRegistrationFailed = process.env.BOX_REGISTRATION_OUTCOME === 'failure';
var port = boxRegistrationFailed ? registrationFailedPort : process.env.LISTEN_PORT || '3000';
var portFile = process.env.DOMOTZ_LISTENER_PORT_FILE;
if (process.platform === 'win32') {
portFile = require('path').join(process.env.TEMP, 'domotz_listener.port');
}
/**
* The HTTP server
* @type {null}
*/
var server = null;
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, X-API-Minor-Version, Authorization');
next();
});
if (boxRegistrationFailed) {
initializeEmergencyRouting(app, fs, http, express, event, bodyParser, favicon, path, routes);
} else if (httpLocalInterfaceEnabled) {
initializeStandardRouting(app, fs, http, express, event, bodyParser, favicon, path, routes, myConsole);
} else {
myConsole.info('Agent local web interface disabled');
initializeRestrictedRouting(app, express, resourceLocator);
}
app.startServing = function () {
app.set('port', port);
server = http.createServer(app);
app.set('server', server);
myConsole.debug('WEBAPP - Try start domotz webapp on port ' + port);
server.on('error', onError);
server.on('listening', onListening);
server.listen(port);
};
/**
* Event listener for HTTP server "listening" event.
*/
var onListening = function () {
var port = app.get('port');
myConsole.info('WEBAPP - Domotz is listening on port ' + port + '... ' + 'Writing port number on ' + portFile);
if (!boxRegistrationFailed) {
setTimeout(event.onListeningWebapp, 2000);
}
myConsole.info('Triggering updatePkgInfo event');
resourceLocator.event.updatePkgInfo();
fs.writeFileSync(portFile, port);
};
/**
* Error handler: starts from
* @param error
*/
var onError = function onError(error) {
if (error.syscall !== 'listen') {
myConsole.error('Error on System call ' + error.syscall);
throw error;
}
var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
signalCriticalFailureAndExit(bind + ' requires elevated privileges');
break;
case 'EADDRINUSE':
port += 1;
if (port < 65535) {
app.startServing();
} else {
signalCriticalFailureAndExit('Cannot find a free port to listen to');
}
break;
default:
throw error;
}
};
/**
* Logs a critical error and waits 30s then exit abnormally.
* The wait is a cool down period before a possible restart.
* @param message
*/
function signalCriticalFailureAndExit(message) {
myConsole.error('signalCriticalFailureAndExit - ' + message);
setTimeout(function () {
process.exit(1);
}, 30000);
}
return app;
};
function initializeRestrictedRouting(app, express, resourceLocator) {
app.get('/', function (req, res) {
res.send(
'The Network Collector local Web Interface has been disabled. To re-enable it, please login into the WebApp and enable the "Network Collector Local Web Interface" in the Collector Settings page.'
);
});
var router = express.Router();
var handler = require('./request_handlers/api/status')['get'](resourceLocator);
var routes = router['get']('/api/v1/status', handler);
app.use('/', routes);
}
function initializeEmergencyRouting(app, fs, http, express, event, bodyParser, favicon, path) {
/**
* Resource path
*/
var webappRootPath = path.join(__dirname, '..', '..', 'webapp', 'emergency');
app.use(express.static(webappRootPath));
}
function initializeStandardRouting(app, fs, http, express, event, bodyParser, favicon, path, routes, myConsole) {
var defaultTenant = 'domotz';
var tenant = process.env.TENANT || defaultTenant;
/**
* Resource path
*/
var viewsPath = path.join(__dirname, '..', '..', 'webapp', 'views');
var faviconPath = path.join(__dirname, '..', '..', 'webapp', 'resources', tenant, 'images', 'favicon.ico');
var webappRootPath = path.join(__dirname, '..', '..', 'webapp');
var resourcesPath = '/resources/';
var tenantResourcesPath = path.join(__dirname, '..', '..', 'webapp', 'resources', tenant, '/');
var varCssPath = '/node_modules/domotz-angular-widgets/resources/css/var.css';
var tenantVarCssPath = path.join(
__dirname,
'..',
'..',
'webapp',
'node_modules',
'domotz-angular-widgets',
'resources',
'css',
'var.' + tenant + '.css'
);
// view engine setup
app.set('views', viewsPath);
app.set('view engine', 'ejs');
app.use(favicon(faviconPath));
app.use(bodyParser.json({ limit: '10mb' })); // for parsing application/json
app.use(
bodyParser.raw({
limit: '100kb',
type: '*/*',
})
);
app.use(resourcesPath, express.static(tenantResourcesPath));
app.use(varCssPath, express.static(tenantVarCssPath));
app.use(express.static(webappRootPath));
app.use(function (req, res, next) {
myConsole.info('API - (%s): %s', req.method, req.url);
next();
});
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
app.use(function (err, req, res) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err,
});
});
}
module.exports.createApp = createApp;