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.
123 lines (104 loc) • 3.63 kB
JavaScript
/**
* Copyright reelyActive 2016-2019
* We believe in an open Internet of Things
*/
let beaver = (function() {
// Internal constants
const SIGNATURE_SEPARATOR = '/';
const ALL_EVENTS_INDEX_LIST = [ 0, 1, 2, 3, 4 ];
const DEFAULT_DISAPPEARANCE_MILLISECONDS = 15000;
// Internal variables
let transmitters = {};
let eventCallbacks = [ [], [], [], [], [] ];
let disappearanceMilliseconds = DEFAULT_DISAPPEARANCE_MILLISECONDS;
let purgeTimeout = null;
// Get the given raddec's transmitter signature
function getTransmitterSignature(raddec) {
return raddec.transmitterId + SIGNATURE_SEPARATOR +
raddec.transmitterIdType;
}
// Handle the given raddec
function handleRaddec(raddec) {
let transmitterSignature = getTransmitterSignature(raddec);
let isNewTransmitter = !transmitters.hasOwnProperty(transmitterSignature);
raddec.timestamp = raddec.timestamp || new Date().getTime();
raddec.packets = raddec.packets || [];
raddec.events = raddec.events || [ 3 ];
if(isNewTransmitter) {
transmitters[transmitterSignature] = {};
}
transmitters[transmitterSignature].raddec = raddec;
handleEventCallbacks(raddec);
}
// Handle each registered callback once for the given raddec/event(s)
function handleEventCallbacks(raddec) {
let completedCallbacks = [];
eventCallbacks.forEach(function(callbacks, eventIndex) {
if(raddec.events.includes(eventIndex)) {
callbacks.forEach(function(callback) {
if(callback && (!completedCallbacks.includes(callback))) {
callback(raddec);
}
});
}
});
}
// Purge any stale transmitters as disappearances
function purgeDisappearances() {
let currentTime = new Date().getTime();
let nextPurgeTime = currentTime + disappearanceMilliseconds;
for(transmitterSignature in transmitters) {
let raddec = transmitters[transmitterSignature].raddec;
let stalenessMilliseconds = currentTime - raddec.timestamp;
if(stalenessMilliseconds > disappearanceMilliseconds) {
raddec.events = [ 4 ];
handleEventCallbacks(raddec);
delete transmitters[transmitterSignature]; // TODO: delete only raddec?
}
else {
let purgeTime = raddec.timestamp + disappearanceMilliseconds;
if(purgeTime < nextPurgeTime) {
nextPurgeTime = purgeTime;
}
}
}
let timeoutMilliseconds = Math.max(nextPurgeTime - currentTime, 10);
purgeTimeout = setTimeout(purgeDisappearances, timeoutMilliseconds);
}
// Listen on the given WebSocket
let listen = function(socket, printStatus) {
printStatus = printStatus || false;
socket.on('raddec', handleRaddec);
if(printStatus) {
socket.on('connect', function() {
console.log('beaver connected to socket');
});
socket.on('disconnect', function(message) {
console.log('beaver disconnected from socket:', message);
});
}
if(!purgeTimeout) {
purgeDisappearances();
}
};
// Register a callback for the given event type(s)
let setEventCallback = function(events, callback) {
if(!(callback && (typeof callback === 'function'))) {
return;
}
if(!Array.isArray(events)) {
events = ALL_EVENTS_INDEX_LIST;
}
events.forEach(function(event) {
if(ALL_EVENTS_INDEX_LIST.includes(event)) {
eventCallbacks[event].push(callback);
}
});
}
// Expose the following functions and variables
return {
listen: listen,
on: setEventCallback,
transmitters: transmitters
}
}());