UNPKG

hlc-server

Version:

Serves real-time real-world context at a human scale by combining RFID, RTLS and M2M with structured, linked data on the web. We believe in an open Internet of Things.

196 lines (165 loc) 6.39 kB
/** * Copyright reelyActive 2014-2020 * We believe in an open Internet of Things */ const http = require('http'); const dgram = require('dgram'); const path = require('path'); const express = require('express'); const bodyParser = require('body-parser'); const cors = require('cors'); const Barnowl = require('barnowl'); const BarnowlMinew = require('barnowl-minew'); const BarnowlReel = require('barnowl-reel'); const Barnacles = require('barnacles'); const BarnaclesSocketIO = require('barnacles-socketio'); const BarnaclesElasticsearch = require('barnacles-elasticsearch'); const Chickadee = require('chickadee'); const DirActDigester = require('diract-digester'); const JSONSilo = require('json-silo'); const Raddec = require('raddec'); const Starling = require('starling'); const StatusManager = require('./statusmanager'); const ElasticManager = require('./elasticmanager'); const PORT = process.env.PORT || 3001; const REEL_PORT = process.env.REEL_PORT || 50000; const RADDEC_PORT = process.env.RADDEC_PORT || 50001; const ELASTICSEARCH_NODE = process.env.ELASTICSEARCH_NODE; const DEFAULT_USE_CORS = true; /** * HLCServer Class * Serves up hyperlocal context (HLC) for the Internet of Things. */ class HLCServer { /** * HLCServer constructor * @param {Object} options The configuration options. * @constructor */ constructor(options) { let self = this; options = options || {}; if(!options.hasOwnProperty('useCors')) { options.useCors = DEFAULT_USE_CORS; } this.app = express(); this.server = http.createServer(this.app); this.router = express.Router(); this.app.use(exceptMinew(express.json())); this.app.use(function(req, res, next) { req.hlcserver = self; next(); }); this.app.use('/status', require('./routes/status')); this.app.use('/interfaces/elasticsearch', require('./routes/interfaces/elasticsearch')); this.app.use('/', express.static(path.resolve(__dirname + '/../web'))); this.app.use('/', this.router); if(options.useCors) { self.app.use(cors()); } this.udpServer = dgram.createSocket('udp4'); this.udpServer.bind(RADDEC_PORT, '0.0.0.0'); this.elastic = new ElasticManager({ node: ELASTICSEARCH_NODE }); this.status = new StatusManager(); this.digester = new DirActDigester({ handleDirActProximity: handleDirActProximity, handleDirActDigest: handleDirActDigest }); this.barnowl = new Barnowl(options.barnowl); this.barnowl.addListener(BarnowlReel, {}, BarnowlReel.UdpListener, { path: '0.0.0.0:' + REEL_PORT }); this.barnowl.addListener(BarnowlMinew, {}, BarnowlMinew.HttpListener, { app: self.app, express: express }); if(!options.hasOwnProperty('barnacles')) { options.barnacles = {}; } options.barnacles.barnowl = this.barnowl; this.barnacles = new Barnacles(options.barnacles); this.barnacles.on('raddec', function(raddec) { self.digester.handleRaddec(raddec); }); this.barnacles.addInterface(BarnaclesSocketIO, { server: this.server }); this.elastic.notifyOnElasticsearchRunning(function(client) { self.barnacles.addInterface(BarnaclesElasticsearch, { client: client }); console.log('reelyActive hlc-server detected Elasticsearch node'); }); if(!options.hasOwnProperty('chickadee')) { options.chickadee = {}; } options.chickadee.app = this.app; this.chickadee = new Chickadee(options.chickadee); if(!options.hasOwnProperty('jsonsilo')) { options.jsonsilo = {}; } options.jsonsilo.app = this.app; this.jsonsilo = new JSONSilo(options.jsonsilo); if(!options.hasOwnProperty('starling')) { options.starling = {}; } options.starling.app = this.app; this.emulator = new Starling(options.starling); this.emulator.on('raddec', function(raddec) { self.barnacles.handleRaddec(raddec); }); this.udpServer.on('message', function(msg) { try { let raddec = new Raddec(msg); if(raddec !== null) { self.barnacles.handleRaddec(raddec); } } catch(error) {}; }); function handleDirActProximity(proximity) { let id = proximity.timestamp + '-' + proximity.instanceId; let esProximity = Object.assign({}, proximity); esProximity.timestamp = new Date(proximity.timestamp).toISOString(); self.elastic.enqueueOperation('create', id, 'diract-proximity', esProximity); } function handleDirActDigest(digest) { let id = digest.timestamp + '-' + digest.instanceId; let esDigest = Object.assign({}, digest); esDigest.timestamp = new Date(digest.timestamp).toISOString(); self.elastic.enqueueOperation('create', id, 'diract-digest', esDigest); } this.server.listen(PORT, function() { console.log('reelyActive hlc-server is listening on port', PORT); }); } /** * Add the given hardware listener to barnowl. * @param {Class} interfaceClass The (uninstantiated) barnowl-x interface. * @param {Object} interfaceOptions The interface options as a JSON object. * @param {Class} listenerClass The (uninstantiated) listener class. * @param {Object} listenerOptions The listener options as a JSON object. */ addListener(interfaceClass, interfaceOptions, listenerClass, listenerOptions) { this.barnowl.addListener(interfaceClass, interfaceOptions, listenerClass, listenerOptions); } /** * Add the given interface to barnacles. * @param {Class} interfaceClass The (uninstantiated) barnacles-x interface. * @param {Object} interfaceOptions The interface options as a JSON object. */ addInterface(interfaceClass, interfaceOptions) { this.barnacles.addInterface(interfaceClass, interfaceOptions); } } /* Temporary function to handle the case where Minew sends binary data */ /* erroneously indicated with Content-Type: "application/json". */ /* TODO: remove if/when Minew update to use application/octet-stream */ function exceptMinew(middleware) { return function(req, res, next) { if(req.path === '/minew') { next(); } else { middleware(req, res, next); } } } module.exports = HLCServer;