lwm2m
Version:
Library for developing servers and client of OMA Lightweight M2M
231 lines (196 loc) • 5.46 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, seehttp://www.gnu.org/licenses/.
*
* For those usages not covered by the GNU Affero General Public License
* please contact with::[contacto@tid.es]
*/
;
var errors = require('./errors');
var senml = require('./senml');
var tlv = require('./tlv');
var content = require('./contentFormats');
var url = require('url');
var coap = require('coap');
var Readable = require('readable-stream').Readable;
exports.invoke = function(callback, promise) {
promise
.then(callback.bind(null, null), callback)
.catch(function(err) {
setTimeout(function() {
throw err;
});
});
};
exports.setTimeoutPromise = function(delay, arg) {
return new Promise(function(resolve) {
setTimeout(resolve, delay, arg);
});
};
function splitPath(path) {
return path
.replace(/^\//g, '')
.split('/')
.filter(Boolean); // remove empty strings
}
exports.splitPath = splitPath;
exports.validatePath = function(path) {
var path_ = splitPath(path).map(Number);
function inRange(val) {
return val < 65535 && val >= 0;
}
return path_.every(inRange) &&
[1,2,3].indexOf(path_.length) >= 0;
};
exports.objectId = function(path) {
return splitPath(path)[0];
};
function isObject(path) {
return splitPath(path).length === 1;
}
exports.isObject = isObject;
exports.instanceId = function(path) {
return splitPath(path)[1];
};
function isInstance(path) {
return splitPath(path).length === 2;
}
exports.isInstance = isInstance;
exports.resourceId = function(path) {
return splitPath(path)[2];
};
function isResource(path) {
return splitPath(path).length === 3;
}
exports.isResource = isResource;
exports.query = function(req) {
var obj = url.parse(req.url, true);
return Object.assign({}, obj.query);
};
exports.validateQuery = function(query, mandatory, optional) {
var params = Object.keys(query);
var ok = mandatory.every(function(param) {
return params.indexOf(param) >= 0;
});
return ok && params.every(function(param) {
return mandatory.indexOf(param) >= 0 ||
optional.indexOf(param) >= 0;
});
};
exports.getOption = function(res, name) {
var index = res.options.findIndex(function(option) {
return option.name === name;
});
if (index < 0)
return;
return res.options[index].value;
};
exports.parsePayload = function(payload, contentFormat, schema) {
var body;
switch (contentFormat) {
case content.json:
if (schema) {
body = senml.parse(payload, schema);
} else {
body = JSON.parse(payload.toString('utf8'));
}
break;
case content.tlv:
if (schema) {
body = tlv.parse(payload, schema);
} else {
body = payload;
}
break;
case content.opaque:
body = payload;
break;
case content.text:
body = payload.toString('utf8');
break;
default:
throw new Error('Unknown content format: ' + contentFormat);
}
return body;
};
exports.generatePayload = function(value, schema, mediaType) {
if (!schema) {
throw new Error('missing schema');
}
schema.validate(value);
var payload;
switch (mediaType) {
case content.json:
payload = senml.serialize(value, schema);
break;
case content.tlv:
payload = tlv.serialize(value, schema);
break;
default:
throw new Error('Uknwown media type: ' + mediaType);
}
return payload;
};
exports.getMediaType = function(path, value, format) {
if (format) {
if (format.match(/json/)) {
return content.json;
} else if (format.match(/tlv/)) {
return content.tlv;
} else if (format.match(/text/)) {
return content.text;
} else if (format.match(/opaque/)) {
return content.opaque;
}
} else if (isInstance(path) || isObject(path)) {
if (typeof value === 'string') {
return content.json;
} else if (Buffer.isBuffer(value)) {
return content.tlv;
} else if (typeof value === 'object') {
return content.tlv; // give it a default
}
} else if (isResource(path)) {
if (Buffer.isBuffer(value)) {
return content.opaque;
} else {
return content.text;
}
} else {
throw new Error('Cannot get media type for ' +
JSON.stringify(value) + ' at path ' + path);
}
};
exports.send = function(request, type) {
var agent = new coap.Agent({ type: type });
var req = agent.request(request);
var rs = new Readable();
return new Promise(function(resolve, reject) {
req.on('response', resolve);
req.on('error', function(error) {
reject(new errors.ClientConnectionError(error));
});
if (request.payload) {
rs.push(request.payload);
rs.push(null);
rs.pipe(req);
} else {
req.end();
}
});
};