2016-07-16 09:35:15 +00:00
|
|
|
var moment = require('moment');
|
2016-08-07 09:02:21 +00:00
|
|
|
var fs = require('fs');
|
|
|
|
var chokidar = require('chokidar');
|
2016-07-16 09:35:15 +00:00
|
|
|
var express = require('express');
|
2016-07-10 17:34:49 +00:00
|
|
|
var capture = require('./capture');
|
2016-08-07 09:02:21 +00:00
|
|
|
var logger = require('./logger');
|
2016-07-16 09:35:15 +00:00
|
|
|
|
2016-07-10 17:34:49 +00:00
|
|
|
var app = express();
|
|
|
|
|
2016-08-07 09:02:21 +00:00
|
|
|
var server = null;
|
|
|
|
var serverPort = 0;
|
|
|
|
var config = null;
|
|
|
|
var configError = null;
|
|
|
|
|
2016-08-07 10:31:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
function loadConfig()
|
2016-08-07 09:02:21 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Unload existing config
|
|
|
|
if (config !== null)
|
|
|
|
{
|
|
|
|
var name = require.resolve('./config');
|
|
|
|
delete require.cache[name];
|
|
|
|
}
|
2016-07-10 17:34:49 +00:00
|
|
|
|
2016-08-07 09:02:21 +00:00
|
|
|
config = require('./config');
|
|
|
|
|
|
|
|
// Some sanity checking to avoid issues later on
|
|
|
|
if (!config.cams)
|
|
|
|
config.cams = [];
|
|
|
|
|
|
|
|
capture.init(config.cams);
|
|
|
|
configError = null;
|
|
|
|
|
|
|
|
if (server === null || config.port !== serverPort)
|
|
|
|
{
|
|
|
|
if (server !== null)
|
|
|
|
{
|
|
|
|
server.close();
|
|
|
|
server = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
serverPort = config.port;
|
|
|
|
server = app.listen(config.port, function()
|
|
|
|
{
|
|
|
|
logger.info('SecurityCam.js running on port ' + config.port);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e)
|
|
|
|
{
|
|
|
|
config = null;
|
|
|
|
configError = e.message;
|
|
|
|
|
|
|
|
// Don't close the server if it was running before. The port is
|
|
|
|
// unlikely to change, and this will allow the status page to
|
|
|
|
// report the error.
|
|
|
|
|
|
|
|
logger.error('Error loading configuration:');
|
|
|
|
|
|
|
|
// Tried to use e.stack to get more information about where the syntax
|
|
|
|
// error is, but it seems SyntaxError doesn't provide it yet:
|
|
|
|
// http://stackoverflow.com/questions/20570477/line-number-of-syntaxerror-in-node-js
|
|
|
|
logger.error(e);
|
|
|
|
}
|
|
|
|
}
|
2016-07-10 17:34:49 +00:00
|
|
|
|
2016-07-16 09:35:15 +00:00
|
|
|
|
2016-08-07 10:31:21 +00:00
|
|
|
function inGroup(groupId, cam)
|
|
|
|
{
|
|
|
|
if (cam.group === groupId)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (cam.groups && cam.groups.indexOf(groupId) > -1)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-10 17:34:49 +00:00
|
|
|
|
|
|
|
app.get('/', function(req, res)
|
|
|
|
{
|
2016-08-07 09:02:21 +00:00
|
|
|
if (config !== null)
|
|
|
|
{
|
|
|
|
res.send(JSON.stringify(
|
|
|
|
{
|
|
|
|
status: 'running',
|
|
|
|
cams: Object.keys(config.cams)
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
else if (configError !== null)
|
|
|
|
{
|
|
|
|
res.send(JSON.stringify(
|
|
|
|
{
|
|
|
|
status: 'error',
|
|
|
|
error: configError
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
else
|
2016-07-10 17:34:49 +00:00
|
|
|
{
|
2016-08-07 09:02:21 +00:00
|
|
|
res.send(JSON.stringify(
|
|
|
|
{
|
|
|
|
status: 'error',
|
|
|
|
error: 'An unhandled error has occured. See the console for more information, hopefully.'
|
|
|
|
}));
|
|
|
|
}
|
2016-07-10 17:34:49 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
app.get('/capture', function(req, res)
|
|
|
|
{
|
2016-08-07 09:02:21 +00:00
|
|
|
if (config !== null)
|
2016-07-10 17:34:49 +00:00
|
|
|
{
|
2016-08-07 09:02:21 +00:00
|
|
|
var now = moment();
|
|
|
|
var cams = [];
|
2016-08-07 09:19:33 +00:00
|
|
|
var alreadyRunning = [];
|
2016-08-07 09:02:21 +00:00
|
|
|
|
|
|
|
for (var camId in config.cams)
|
2016-07-16 09:35:15 +00:00
|
|
|
{
|
2016-08-07 09:02:21 +00:00
|
|
|
if (config.cams.hasOwnProperty(camId))
|
|
|
|
{
|
2016-08-07 09:19:33 +00:00
|
|
|
if (capture.start(camId, config.cams[camId], now))
|
|
|
|
cams.push(camId);
|
|
|
|
else
|
|
|
|
alreadyRunning.push(camId);
|
2016-08-07 09:02:21 +00:00
|
|
|
}
|
2016-07-16 09:35:15 +00:00
|
|
|
}
|
2016-07-10 17:34:49 +00:00
|
|
|
|
2016-08-07 09:19:33 +00:00
|
|
|
if (cams.length > 0)
|
|
|
|
logger.info('Started capture for: ' + cams.join(', '));
|
|
|
|
|
|
|
|
if (alreadyRunning.length > 0)
|
|
|
|
logger.info('Capture already running for: ' + alreadyRunning.join(', '));
|
2016-07-16 09:35:15 +00:00
|
|
|
|
2016-08-07 10:31:21 +00:00
|
|
|
res.send(JSON.stringify(
|
|
|
|
{
|
|
|
|
started: cams,
|
|
|
|
alreadyRunning: alreadyRunning
|
|
|
|
}));
|
2016-08-07 09:02:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-08-07 10:31:21 +00:00
|
|
|
res.status(500).send({ error: 'Error loading configuration. See status page for more information' });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
app.get('/capture/group/:groupId', function(req, res)
|
|
|
|
{
|
|
|
|
if (config !== null)
|
|
|
|
{
|
|
|
|
var groupId = req.params.groupId;
|
|
|
|
var now = moment();
|
|
|
|
var cams = [];
|
|
|
|
var alreadyRunning = [];
|
|
|
|
|
|
|
|
for (var camId in config.cams)
|
|
|
|
{
|
|
|
|
if (config.cams.hasOwnProperty(camId) && inGroup(groupId, config.cams[camId]))
|
|
|
|
{
|
|
|
|
if (capture.start(camId, config.cams[camId], now))
|
|
|
|
cams.push(camId);
|
|
|
|
else
|
|
|
|
alreadyRunning.push(camId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cams.length > 0)
|
|
|
|
logger.info('Started capture for: ' + cams.join(', '));
|
|
|
|
|
|
|
|
if (alreadyRunning.length > 0)
|
|
|
|
logger.info('Capture already running for: ' + alreadyRunning.join(', '));
|
|
|
|
|
|
|
|
res.send(JSON.stringify(
|
|
|
|
{
|
|
|
|
started: cams,
|
|
|
|
alreadyRunning: alreadyRunning
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
res.status(500).send({ error: 'Error loading configuration. See status page for more information' });
|
2016-08-07 09:02:21 +00:00
|
|
|
}
|
2016-07-10 17:34:49 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
app.get('/capture/:camId', function(req, res)
|
|
|
|
{
|
2016-08-07 09:02:21 +00:00
|
|
|
if (config !== null)
|
2016-07-10 17:34:49 +00:00
|
|
|
{
|
2016-08-07 09:02:21 +00:00
|
|
|
var camId = req.params.camId;
|
|
|
|
|
|
|
|
if (config.cams.hasOwnProperty(camId))
|
|
|
|
{
|
2016-08-07 09:19:33 +00:00
|
|
|
if (capture.start(camId, config.cams[camId], moment()))
|
2016-08-07 10:31:21 +00:00
|
|
|
{
|
2016-08-07 09:19:33 +00:00
|
|
|
logger.info('Started capture for: ' + camId);
|
2016-08-07 10:31:21 +00:00
|
|
|
|
|
|
|
res.send(JSON.stringify(
|
|
|
|
{
|
|
|
|
started: [camId]
|
|
|
|
}));
|
|
|
|
}
|
2016-08-07 09:19:33 +00:00
|
|
|
else
|
2016-08-07 10:31:21 +00:00
|
|
|
{
|
2016-08-07 09:19:33 +00:00
|
|
|
logger.info('Capture already running for: ' + camId);
|
|
|
|
|
2016-08-07 10:31:21 +00:00
|
|
|
res.send(JSON.stringify(
|
|
|
|
{
|
|
|
|
alreadyRunning: [camId]
|
|
|
|
}));
|
|
|
|
}
|
2016-08-07 09:02:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
logger.warning('Cam not found: ' + camId);
|
|
|
|
res.sendStatus(404);
|
|
|
|
}
|
2016-07-10 17:34:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-08-07 10:31:21 +00:00
|
|
|
res.status(500).send({ error: 'Error loading configuration. See status page for more information' });
|
2016-07-10 17:34:49 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-08-07 09:02:21 +00:00
|
|
|
var watcher = chokidar.watch('./config.js');
|
|
|
|
var firstLoad = true;
|
|
|
|
|
|
|
|
watcher.on('all', function()
|
|
|
|
{
|
|
|
|
if (!firstLoad)
|
|
|
|
logger.verbose('Configuration change detected, reloading...');
|
|
|
|
|
|
|
|
loadConfig();
|
|
|
|
firstLoad = false;
|
|
|
|
});
|
|
|
|
|
2016-07-10 17:34:49 +00:00
|
|
|
|
2016-08-07 09:02:21 +00:00
|
|
|
// It looks like the add event from chokidar will always be fired immediately,
|
|
|
|
// at least on Windows, but I couldn't find anything in the documentation so
|
|
|
|
// let's not make that assumption and double-check.
|
|
|
|
setTimeout(function()
|
2016-07-10 17:34:49 +00:00
|
|
|
{
|
2016-08-07 09:02:21 +00:00
|
|
|
if (firstLoad)
|
|
|
|
{
|
|
|
|
loadConfig();
|
|
|
|
firstLoad = false;
|
|
|
|
}
|
|
|
|
}, 1000);
|