@arisan/data-api
Version:
The Universal Database API Gateway for CLIO's Modules
265 lines (253 loc) • 9.71 kB
JavaScript
; // eslint-disable-line strict
/* Platform Libraries */
const ipaddr = require('ipaddr.js');
const ObjectID = require('mongodb').ObjectID;
/* Project Libraries */
const BaseHandler = require('./base-handler');
const valueOf = require('../Utils').valueOf;
const CLIO_HEARTBEAT_INTERVAL = process.env.CLIO_HEARTBEAT_INTERVAL;
class RecorderHandler extends BaseHandler {
constructor(logger, recorders, cameras) {
super(logger);
this.recorders = recorders;
this.cameras = cameras;
this.debug(`${ this.constructor.name } Constructed`);
}
/**
* @param {Object} req
* @param {string} req.body.publicIp
* @param {string} req.ip
* @param {Object} res
*/
createRecorder(req, res) {
const tag = 'createRecorder> ';
this.debug(`${ tag }Body ${ JSON.stringify(req.body, null, 2) }`);
const now = new Date();
const recorder = {
public_ip: req.body.publicIp,
private_ip: ipaddr.process(req.ip).toString(),
port: req.body.port,
module: req.body.module,
created: now,
updated: now
};
if (!this.checkValidPublicIp(recorder.public_ip)) {
return;
}
if (!this.checkValidPort(recorder.port)) {
return;
}
if (recorder.module !== 'broker' && recorder.module !== 'archive' && recorder.module !== 'live' && recorder.module !== 'event') {
this.handleError(res, 400, `${ tag }Invalid Module Name ${ recorder.module }`);
return;
}
this.recorders.insertOne(recorder, (insertOneErr, insertOneRes) => {
if (insertOneErr) {
this.handleError(res, 500, `${ tag }${ insertOneErr.message }`);
return;
}
this.info(`${ tag }ID ${ insertOneRes.insertedId } Created`);
res.type('text/plain');
res.status(201).send(new Buffer(`${ insertOneRes.insertedId }`));
});
}
readArchiveRecorderInfo(req, res) {
const tag = 'readArchiveRecorderInfo> ';
const cameraId = req.params.cameraId;
const streamIndex = req.params.streamIndex;
this.debug(`${ tag }Stream ${ cameraId }/${ streamIndex }`);
const validDate = new Date(Date.now() - (CLIO_HEARTBEAT_INTERVAL + 3) * 1000);
this.recorders.findOne({
module: 'archive',
updated: { $gt: validDate }
}, { sort: { cpu_load: 1 } }, (findOneErr, findOneRes) => {
if (findOneErr) {
this.handleError(res, 500, `${ tag }${ findOneErr.message }`);
return;
}
if (!findOneRes) {
this.handleError(res, 404, `${ tag }Archive Recorder Not Available`);
return;
}
const reply = {
host: findOneRes.private_ip,
port: parseInt(findOneRes.port, 10)
};
this.info(`${ tag }Stream ${ cameraId }/${ streamIndex } ` + `Reply ${ JSON.stringify(reply, null, 2) }`);
res.status(200).send(reply);
});
}
readLiveRecorderInfo(req, res) {
const tag = 'readLiveRecorderInfo> ';
const cameraId = req.params.cameraId;
const streamIndex = req.params.streamIndex;
this.debug(`${ tag }Stream ${ cameraId }/${ streamIndex }`);
const validDate = new Date(Date.now() - (CLIO_HEARTBEAT_INTERVAL + 3) * 1000);
this.recorders.findOne({
module: 'live',
updated: { $gt: validDate }
}, { sort: { cpu_load: 1 } }, (findOneErr, findOneRes) => {
if (findOneErr) {
this.handleError(res, 500, `${ tag }${ findOneErr.message }`);
return;
}
if (!findOneRes) {
this.handleError(res, 404, `${ tag }Live Recorder Not Available`);
return;
}
const reply = {
host: findOneRes.private_ip,
port: parseInt(findOneRes.port, 10)
};
this.info(`${ tag }Stream ${ cameraId }/${ streamIndex } ` + `Reply ${ JSON.stringify(reply, null, 2) }`);
res.status(200).send(reply);
});
}
readEventRecorderInfo(req, res) {
const tag = 'readEventRecorderInfo> ';
const cameraId = req.params.cameraId;
const streamIndex = req.params.streamIndex;
this.debug(`${ tag }Stream ${ cameraId }/${ streamIndex }`);
const validDate = new Date(Date.now() - (CLIO_HEARTBEAT_INTERVAL + 3) * 1000);
this.recorders.findOne({
module: 'event',
updated: { $gt: validDate }
}, { sort: { cpu_load: 1 } }, (findOneErr, findOneRes) => {
if (findOneErr) {
this.handleError(res, 500, `${ tag }${ findOneErr.message }`);
return;
}
if (!findOneRes) {
this.handleError(res, 404, `${ tag }Event Recorder Not Available`);
return;
}
const reply = {
host: findOneRes.private_ip,
port: parseInt(findOneRes.port, 10)
};
this.info(`${ tag }Stream ${ cameraId }/${ streamIndex } ` + `Reply ${ JSON.stringify(reply, null, 2) }`);
res.status(200).send(reply);
});
}
readEventBrokerInfo(req, res) {
const tag = 'readEventBrokerInfo> ';
const cameraId = req.params.cameraId;
const streamIndex = req.params.streamIndex;
this.debug(`${ tag }Stream ${ cameraId }/${ streamIndex }`);
let objectId;
try {
objectId = new ObjectID(cameraId);
} catch (err) {
this.handleError(res, 400, `${ tag }${ err.message }`);
return;
}
this.cameras.findOne({ _id: objectId }, (findCameraErr, findCameraRes) => {
if (findCameraErr) {
this.handleError(res, 500, `${ tag }${ findCameraErr.message }`);
return;
}
if (!findCameraRes) {
this.handleError(res, 404, `${ tag }ID ${ cameraId }/${ streamIndex } Not Found`);
return;
}
let triggeredStreams = valueOf(findCameraRes, 'streams', streamIndex, 'triggered_streams');
this.debug(JSON.stringify(triggeredStreams, null, 2));
if (!triggeredStreams) {
triggeredStreams = [];
}
const validDate = new Date(Date.now() - (CLIO_HEARTBEAT_INTERVAL + 3) * 1000);
const reply = { recorderInfo: [] };
triggeredStreams.forEach((triggeredStream, index, array) => {
this.debug(JSON.stringify(triggeredStream, null, 2));
const triggeredCameraId = triggeredStream.camera_id;
const triggeredStreamIndex = triggeredStream.stream_index;
const triggeredStreamId = `${ triggeredCameraId }/${ triggeredStreamIndex }`;
this.recorders.findOne({
module: 'broker',
updated: { $gt: validDate }
}, { sort: { cpu_load: 1 } }, (findBrokerErr, findBrokerRes) => {
if (findBrokerErr) {
this.error(`${ tag }ID ${ triggeredStreamId } ${ findBrokerErr.message }`);
return;
}
this.debug(`${ tag } Before push ${ JSON.stringify(reply, null, 2) }`);
reply.recorderInfo.push({
host: findBrokerRes.private_ip,
port: findBrokerRes.port,
cameraId: triggeredCameraId,
streamIndex: triggeredStreamIndex
});
this.debug(`${ tag } After push ${ JSON.stringify(reply, null, 2) }`);
if (index === array.length - 1) {
this.info(`${ tag }Stream ${ cameraId }/${ streamIndex } ` + `Reply ${ JSON.stringify(reply, null, 2) }`);
res.status(200).send(reply);
}
});
});
});
}
/**
* @param {Object} req
* @param {string} req.params.recorderId
* @param {Object[]} req.streamInfos
* @param {boolean} req.streamInfos.archiveStarted;
* @param {boolean} req.streamInfos.liveStarted;
* @param {boolean} req.streamInfos.eventStarted;
* @param {number} req.cpuUsagePercentage
* @param {number} req.memoryUsagePercentage
* @param {number} req.hddUsageKB
* @param {number} req.hddTotalKB
* @param {number} req.netUploadBytesPerSecond
* @param {number} req.netDownloadBytesPerSecond
* @param {Object} res
*/
updateRecorder(req, res) {
const tag = 'updateRecorder> ';
const recorderId = req.params.recorderId;
this.debug(`${ tag }ID ${ recorderId } Body ${ JSON.stringify(req.body, null, 2) }`);
let objectId;
try {
objectId = new ObjectID(recorderId);
} catch (err) {
this.handleError(res, 400, `${ tag }${ err.message }`);
return;
}
if (!this.checkRequestBodyProperties(req.body, res, tag, recorderId, 'cpuUsagePercentage', 'memoryUsagePercentage', 'hddUsageKB', 'hddTotalKB', 'netUploadBytesPerSecond', 'netDownloadBytesPerSecond')) {
return;
}
const diff = {
stream_infos: [],
updated: new Date()
};
if (req.body.streamInfos) {
for (let i = 0; i < req.body.streamInfos.length; i++) {
const streamInfo = req.body.streamInfos[i];
diff.stream_infos.push({
id: streamInfo.id,
archive: streamInfo.archiveStarted,
live: streamInfo.liveStarted,
event: streamInfo.eventStarted
});
}
}
diff.cpu_load = Math.ceil(req.body.cpuUsagePercentage * 100);
diff.mem_load = Math.ceil(req.body.memoryUsagePercentage);
diff.hdd_load = Math.ceil(req.body.hddUsageKB * 100 / req.body.hddTotalKB);
diff.upload_kbps = Math.ceil(req.body.netUploadBytesPerSecond * 8 / 1024);
diff.download_kbps = Math.ceil(req.body.netDownloadBytesPerSecond * 8 / 1024);
this.recorders.updateOne({ _id: objectId }, { $set: diff }, (updateOneErr, updateOneRes) => {
if (updateOneErr) {
this.handleError(res, 500, `${ tag }${ updateOneErr.message }`);
return;
}
if (!updateOneRes.matchedCount) {
this.handleError(res, 404, `${ tag }ID ${ recorderId } Not Found`);
return;
}
this.info(`${ tag }ID ${ objectId } Updated`);
res.sendStatus(200);
});
}
}
module.exports = RecorderHandler;
//# sourceMappingURL=recorder-handler.js.map