iotagent-node-lib
Version:
IoT Agent library to interface with NGSI Context Broker
259 lines (228 loc) • 8.23 kB
JavaScript
/*
* Copyright 2014 Telefonica Investigación y Desarrollo, S.A.U
*
* This file is part of fiware-iotagent-lib
*
* fiware-iotagent-lib is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* fiware-iotagent-lib 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with fiware-iotagent-lib.
* If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by the GNU Affero General Public License
* please contact with::daniel.moranjimenez@telefonica.com
*/
/* eslint-disable no-prototype-builtins */
let registeredDevices = {};
const logger = require('logops');
const errors = require('../../errors');
const _ = require('underscore');
const context = {
op: 'IoTAgentNGSI.InMemoryDeviceRegister'
};
function deepClone(device) {
const initialClone = _.clone(device);
for (const i in device) {
if (device.hasOwnProperty(i) && Array.isArray(device[i])) {
initialClone[i] = device[i].map(_.clone);
}
}
return initialClone;
}
/**
* Create a new register for a device. The device object should contain the id, type and registrationId
*
* @param {Object} newDevice Device object to be stored
*/
function storeDevice(newDevice, callback) {
if (!registeredDevices[newDevice.service]) {
registeredDevices[newDevice.service] = {};
}
if (registeredDevices[newDevice.service][newDevice.id]) {
callback(new errors.DuplicateDeviceId(newDevice));
} else {
registeredDevices[newDevice.service][newDevice.id] = deepClone(newDevice);
registeredDevices[newDevice.service][newDevice.id].creationDate = Date.now();
logger.debug(context, 'Storing device with id [%s] and type [%s]', newDevice.id, newDevice.type);
callback(null, newDevice);
}
}
/**
* Remove the device identified by its id and service.
*
* @param {String} id Device ID of the device to remove.
* @param {String} service Service of the device to remove.
* @param {String} subservice Subservice inside the service for the removed device.
*/
function removeDevice(id, apikey, service, subservice, callback) {
const services = Object.keys(registeredDevices);
for (let i = 0; i < services.length; i++) {
if (registeredDevices[services[i]][id]) {
logger.debug(context, 'Removing device with id [%s] from service [%s].', id, services[i]);
delete registeredDevices[services[i]][id];
}
}
callback(null);
}
/**
* Function to filter all the devices belonging to a service and subservice.
*
* @param {String} service Service name to use in the filtering.
* @param {String} subservice Subservice name to use in the filtering.
* @return {Function} List of all the devices belonging to the given service and subservice.
*/
function getDevicesByService(service, subservice) {
if (registeredDevices[service]) {
return Object.keys(registeredDevices[service]).filter(function filterByService(item) {
if (subservice) {
return registeredDevices[service][item].subservice === subservice;
}
return true;
});
}
return [];
}
/**
* Return the list of currently registered devices (via callback).
*
* @param {String} service Service for which the entries will be returned.
* @param {String} subservice Subservice for which the entries will be listed.
* @param {Number} limit Maximum number of entries to return.
* @param {Number} offset Number of entries to skip for pagination.
*/
function listDevices(type, service, subservice, limit, offset, callback) {
const result = [];
let skipped = 0;
const deviceList = getDevicesByService(service, subservice);
let countNumber = deviceList.length;
for (const i in deviceList) {
if (registeredDevices[service].hasOwnProperty(deviceList[i])) {
if (offset && skipped < parseInt(offset, 10)) {
skipped++;
} else if (type && registeredDevices[service][deviceList[i]].type === type) {
result.push(registeredDevices[service][deviceList[i]]);
} else if (type) {
countNumber--;
} else {
result.push(registeredDevices[service][deviceList[i]]);
}
if (limit && result.length === parseInt(limit, 10)) {
break;
}
}
}
callback(null, {
count: countNumber,
devices: result
});
}
function getDevice(id, apikey, service, subservice, callback) {
if (registeredDevices[service] && registeredDevices[service][id]) {
callback(null, registeredDevices[service][id]);
} else {
callback(new errors.DeviceNotFound(id));
}
}
function getByNameAndType(name, type, service, subservice, callback) {
const devices = _.values(registeredDevices[service]);
let device;
for (let i = 0; i < devices.length; i++) {
if (devices[i].name === name) {
if (type) {
if (devices[i].type === type) {
device = devices[i];
}
} else {
device = devices[i];
}
}
}
if (device) {
callback(null, device);
} else {
callback(new errors.DeviceNotFound(name));
}
}
function getByName(name, service, subservice, callback) {
getByNameAndType(name, null, service, subservice, callback);
}
function update(previousDevice, device, callback) {
registeredDevices[device.service][device.id] = deepClone(device);
callback(null, device);
}
function clear(callback) {
registeredDevices = {};
callback();
}
function getDevicesByAttribute(name, value, service, subservice, callback) {
let devices;
const resultDevices = [];
if (service) {
devices = _.values(registeredDevices[service]);
} else {
devices = _.flatten(_.values(registeredDevices).map(_.values));
}
for (let i = 0; i < devices.length; i++) {
if (devices[i][name] === value) {
resultDevices.push(devices[i]);
}
}
if (resultDevices.length > 0) {
callback(null, resultDevices);
} else {
callback(new errors.DeviceNotFound(''));
}
}
function storeDeviceField(fieldName, fieldValue, typeInformation, callback) {
if (
typeInformation &&
typeInformation.id &&
typeInformation.apikey &&
typeInformation.service &&
typeInformation.subservice
) {
getDevice(
typeInformation.id,
typeInformation.apikey,
typeInformation.service,
typeInformation.subservice,
function (error, data) {
if (!error) {
if (data) {
if (fieldName === 'lastMeasure') {
data.lastMeasure = { timestamp: new Date().toISOString(), measure: fieldValue };
} else {
data[fieldName] = fieldValue;
}
}
if (callback) {
callback(null, data);
}
} else {
callback(error, null);
}
}
);
} else {
callback(null, null);
}
}
exports.getDevicesByAttribute = getDevicesByAttribute;
exports.store = storeDevice;
exports.storeDeviceField = storeDeviceField;
exports.update = update;
exports.remove = removeDevice;
exports.list = listDevices;
exports.get = getDevice;
exports.getSilently = getDevice;
exports.getByName = getByName;
exports.getByNameAndType = getByNameAndType;
exports.clear = clear;