lwm2m
Version:
Library for developing servers and client of OMA Lightweight M2M
252 lines (214 loc) • 5.92 kB
JavaScript
/*
* Copyright 2017 Alexandre Moreno <alex_moreno@tutk.com>
*
* This file is part of node-lwm2m
*
* node-lwm2m 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.
*
* node-lwm2m 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 node-lwm2m.
* If not, see http://www.gnu.org/licenses/.
*
*/
;
var debug = require('debug')('lwm2m');
var errors = require('../errors');
var updated = Symbol();
var EventEmitter = require('events').EventEmitter;
/**
* Registry for clients.
* Default implementation is in-memory.
*
* For production use, extend `Registry` class and
* give new implementations to
* _get, _find, _save, _update and _delete.
*
* See [examples](examples) for a MongoDB-backed registry.
*
* @constructor
* @augments EventEmitter
*/
function Registry() {
EventEmitter.call(this);
if (this.constructor === Registry) {
this.clients = [];
}
}
module.exports = Registry;
Registry.prototype = Object.create(EventEmitter.prototype);
Registry.prototype.constructor = Registry;
/**
* get client by endpoint name
* @param {string} endpoint
* @param {Function} callback - callback is given
* the two arguments `(err, client)`
*/
Registry.prototype._find = function(endpoint, callback) {
var location = this.clients.findIndex(function(elem) {
return elem && elem.ep === endpoint;
});
this._get(location, callback);
};
Registry.prototype.find = function(endpoint) {
var _this = this;
return new Promise(function(resolve, reject) {
_this._find(endpoint, function(err, client) {
if (err) {
reject(err);
} else {
resolve(client);
}
});
});
};
/**
* get client by location in the registry
* @param {string} location
* @param {Function} callback - callback is given
* the two arguments `(err, client)`
*/
Registry.prototype._get = function(location, callback) {
var result = this.clients[location];
if (result) {
callback(null, result);
} else {
callback(new errors.DeviceNotFound());
}
};
Registry.prototype.get = function(location) {
var _this = this;
return new Promise(function(resolve, reject) {
_this._get(location, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
};
/**
* store a new client in the registry
* @param {Object} client
* @param {Function} callback - callback is given
* the two arguments `(err, location)`
*/
Registry.prototype._save = function(client, callback) {
var location = this.clients.findIndex(Object.is.bind(null, undefined));
if (location < 0)
location = this.clients.length;
var obj = Object.assign({
lt: 86400,
location: location,
}, client);
var that = this;
Object.defineProperty(obj, 'timeout', {
value: setInterval(function() {
if (!that.clients[location][updated]) {
that._delete(location, function(err) {
debug(err);
});
} else {
that.clients[location][updated] = false;
}
}, obj.lt * 1000),
});
this.clients[location] = obj;
return callback(null, location);
};
Registry.prototype.save = function(client) {
var _this = this;
return new Promise(function(resolve, reject) {
_this._save(client, function(err, location) {
if (err) {
reject(err);
} else {
resolve(location);
}
});
});
};
/**
* update a client in the registry
* @param {string} location
* @param {Object} params
* @param {Function} callback - callback is given
* the two arguments `(err, location)`
*/
Registry.prototype._update = function(location, params, callback) {
var result = this.clients[location];
if (result) {
this.clients[location] = Object.assign(result, params);
this.clients[location][updated] = true;
callback(null, location);
} else {
callback(new errors.DeviceNotFound());
}
};
Registry.prototype.update = function(location, params) {
var _this = this;
return new Promise(function(resolve, reject) {
_this._update(location, params, function(err, location) {
if (err) {
reject(err);
} else {
_this.emit('update', location);
resolve(location);
}
});
});
};
/**
* delete client from the registry
* @param {string} location
* @param {Function} callback - callback is given
* the two arguments `(err, client)`
*/
Registry.prototype._delete = function(location, callback) {
var result = this.clients[location];
if (result) {
clearTimeout(result.timeout);
delete this.clients[location];
callback(null, result);
} else {
callback(new errors.DeviceNotFound());
}
};
Registry.prototype.unregister = function(location) {
var _this = this;
return new Promise(function(resolve, reject) {
_this._delete(location, function(err, result) {
if (err) {
reject(err);
} else {
_this.emit('deregister', result);
resolve(result);
}
});
});
};
Registry.prototype.register = function(client) {
var _this = this;
if (!client.ep) {
return Promise.reject(new Error('missing `ep` parameter'));
}
return this.find(client.ep)
.then(function(result) {
return _this.update(result.location, client);
})
.catch(function(err) {
if (err instanceof errors.DeviceNotFound) {
return _this.save(client);
} else {
return Promise.reject(err);
}
});
};