906 lines
47 KiB
JavaScript
906 lines
47 KiB
JavaScript
/* jshint -W097 */
|
|
/* jshint strict:false */
|
|
/*jslint node: true */
|
|
/*jshint -W061 */
|
|
'use strict';
|
|
|
|
/**
|
|
* SimpleAPI class
|
|
*
|
|
* From settings used only secure, auth and crossDomain
|
|
*
|
|
* @class
|
|
* @param {object} server http or https node.js object
|
|
* @param {object} webSettings settings of the web server, like <pre><code>{secure: settings.secure, port: settings.port}</code></pre>
|
|
* @param {object} adapter web adapter object
|
|
* @param {object} instanceSettings instance object with common and native
|
|
* @param {object} app express application
|
|
* @return {object} object instance
|
|
*/
|
|
function SimpleAPI(server, webSettings, adapter, instanceSettings, app) {
|
|
if (!(this instanceof SimpleAPI)) return new SimpleAPI(server, webSettings, adapter, instanceSettings, app);
|
|
|
|
this.server = server;
|
|
this.app = app;
|
|
this.adapter = adapter;
|
|
this.settings = webSettings;
|
|
this.config = instanceSettings ? instanceSettings.native : {};
|
|
this.namespace = instanceSettings ? instanceSettings._id.substring('system.adapter.'.length) : 'simple-api';
|
|
|
|
this.restApiDelayed = {
|
|
timer: null,
|
|
responseType: '',
|
|
response: null,
|
|
waitId: 0
|
|
};
|
|
|
|
var that = this;
|
|
// Cache
|
|
this.users = {};
|
|
|
|
var __construct = (function () {
|
|
that.adapter.log.info((that.settings.secure ? 'Secure ' : '') + 'simpleAPI server listening on port ' + that.settings.port);
|
|
that.adapter.config.defaultUser = that.adapter.config.defaultUser || 'system.user.admin';
|
|
if (!that.adapter.config.defaultUser.match(/^system\.user\./)) {
|
|
that.adapter.config.defaultUser = 'system.user.' + that.adapter.config.defaultUser;
|
|
}
|
|
if (that.adapter.config.onlyAllowWhenUserIsOwner === undefined) that.adapter.config.onlyAllowWhenUserIsOwner = false;
|
|
adapter.log.info('Allow states only when user is owner: ' + that.adapter.config.onlyAllowWhenUserIsOwner);
|
|
|
|
if (that.app) {
|
|
adapter.log.info('Install extension on /' + that.namespace + '/');
|
|
that.app.use('/' + that.namespace + '/', function (req, res, next) {
|
|
that.restApi.call(that, req, res);
|
|
});
|
|
|
|
// let it be accessible under old address too
|
|
for (var c in commandsPermissions) {
|
|
(function (command) {
|
|
adapter.log.info('Install extension on /' + command + '/');
|
|
that.app.use('/' + command + '/', function (req, res, next) {
|
|
req.url = '/' + command + req.url;
|
|
that.restApi.call(that, req, res);
|
|
});
|
|
})(c);
|
|
}
|
|
}
|
|
// Subscribe on user changes to manage the permissions cache
|
|
that.adapter.subscribeForeignObjects('system.group.*');
|
|
that.adapter.subscribeForeignObjects('system.user.*');
|
|
}.bind(this))();
|
|
|
|
this.isAuthenticated = function (values, callback) {
|
|
if (!values.user || !values.pass) {
|
|
that.adapter.log.warn('No password or username!');
|
|
callback(false);
|
|
} else {
|
|
that.adapter.checkPassword(values.user, values.pass, function (res) {
|
|
if (res) {
|
|
that.adapter.log.debug('Logged in: ' + values.user);
|
|
callback(true);
|
|
} else {
|
|
that.adapter.log.warn('Invalid password or user name: ' + values.user);
|
|
callback(false);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
this.stateChange = function (id, state) {
|
|
if (that.restApiDelayed.id === id && state && state.ack) {
|
|
adapter.unsubscribeForeignStates(id);
|
|
that.restApiDelayed.response = state;
|
|
setTimeout(restApiDelayedAnswer, 0);
|
|
}
|
|
};
|
|
|
|
this.userReg = new RegExp('^system\.user\.');
|
|
this.groupReg = new RegExp('^system\.group\.');
|
|
|
|
// if user politics changes, clear cache
|
|
this.objectChange = function (id, state) {
|
|
if (this.userReg.test(id) || this.groupReg.test(id)) {
|
|
this.users = {};
|
|
}
|
|
};
|
|
|
|
function restApiPost(req, res, command, oId, values) {
|
|
var responseType = 'json';
|
|
var status = 500;
|
|
var headers = {'Access-Control-Allow-Origin': '*'};
|
|
|
|
var body = '';
|
|
req.on('data', function (data) {
|
|
body += data;
|
|
});
|
|
req.on('end', function () {
|
|
switch (command) {
|
|
case 'setBulk':
|
|
that.adapter.log.debug('POST-' + command + ': body = ' + body);
|
|
var arr = [];
|
|
if (body) {
|
|
arr = body.split('&');
|
|
}
|
|
|
|
for (var i = 0; i < arr.length; i++) {
|
|
arr[i] = arr[i].split('=');
|
|
try {
|
|
values[arr[i][0].trim()] = (arr[i][1] === undefined) ? null : decodeURIComponent((arr[i][1]+'').replace(/\+/g, '%20'));
|
|
}
|
|
catch (e) {
|
|
values[arr[i][0].trim()] = arr[i][1];
|
|
}
|
|
}
|
|
|
|
if (values.prettyPrint !== undefined) {
|
|
if (values.prettyPrint === 'false') values.prettyPrint = false;
|
|
if (values.prettyPrint === null) values.prettyPrint = true;
|
|
}
|
|
|
|
var cnt = 0;
|
|
var response = [];
|
|
that.adapter.log.debug('POST-' + command + ': values = ' + JSON.stringify(values));
|
|
for (var _id in values) {
|
|
if (!values.hasOwnProperty(_id) || _id === 'prettyPrint' || _id === 'user' || _id === 'pass') continue;
|
|
cnt++;
|
|
that.adapter.log.debug('"' + _id + '"');
|
|
findState(_id, values.user, function (err, id, originId) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
cnt = 0;
|
|
} else if (!id) {
|
|
response.push({error: 'error: datapoint "' + originId + '" not found'});
|
|
if (!--cnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
} else {
|
|
var usedId = (values[originId]?originId:id);
|
|
that.adapter.log.debug('POST-' + command + ' for id=' + id + ', oid=' + originId + ', used=' + usedId + ', value='+values[usedId]);
|
|
if (values[usedId] === 'true') {
|
|
values[usedId] = true;
|
|
} else if (values[usedId] === 'false') {
|
|
values[usedId] = false;
|
|
} else if (!isNaN(values[usedId]) && values[usedId] == parseFloat(values[usedId])) {
|
|
values[usedId] = parseFloat(values[usedId]);
|
|
}
|
|
|
|
adapter.setForeignState(id, values[usedId], false, {user: values.user, limitToOwnerRights: that.adapter.config.onlyAllowWhenUserIsOwner}, function (err, id) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
cnt = 0;
|
|
} else {
|
|
adapter.log.debug('Add to Response: ' + JSON.stringify({id: id, val: values[usedId]}));
|
|
response.push({id: id, val: values[usedId]});
|
|
if (!--cnt) {
|
|
status = 200;
|
|
doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
if (!cnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
break;
|
|
|
|
case 'setValueFromBody':
|
|
//that.adapter.log.debug('POST-' + command + ': body = ' + JSON.stringify(body)); // "{0123456xx}"
|
|
//that.adapter.log.debug('POST-' + command + ': req.url = ' + JSON.stringify(req.url)); // "/setValueFromBody?javascript.0.Nuki.Devices.NukiSL1.NukiBridgeResponse&prettyPrint"
|
|
//that.adapter.log.debug('POST-' + command + ': valuesAA = ' + JSON.stringify(values)); // {"javascript.0.Nuki.Devices.NukiSL1.NukiBridgeResponse":null,"prettyPrint":true,"user":"system.user.admin"}
|
|
|
|
for (var _id2 in oId) {
|
|
if (oId.hasOwnProperty(_id2)) {
|
|
values[oId[_id2]] = body;
|
|
}
|
|
}
|
|
|
|
if (values.prettyPrint !== undefined) {
|
|
if (values.prettyPrint === 'false') values.prettyPrint = false;
|
|
if (values.prettyPrint === null) values.prettyPrint = true;
|
|
}
|
|
|
|
if (!oId.length || !oId[0]) {
|
|
doResponse(res, responseType, status, headers, {error: 'no object/datapoint given'}, values.prettyPrint);
|
|
break;
|
|
}
|
|
|
|
|
|
var response = [];
|
|
that.adapter.log.debug('POST-' + command + ': values = ' + JSON.stringify(values));
|
|
var cnt = oId.length;
|
|
for (var k = 0; k < oId.length; k++) {
|
|
that.adapter.log.debug('"' + oId[k] + '"');
|
|
findState(oId[k], values.user, function (err, id, originId) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
cnt = 0;
|
|
} else if (!id) {
|
|
response.push({error: 'error: datapoint "' + originId + '" not found'});
|
|
if (!--cnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
} else {
|
|
var usedId = (values[originId]?originId:id);
|
|
that.adapter.log.debug('POST-' + command + ' for id=' + id + ', oid=' + originId + ', used=' + usedId + ', value='+values[usedId]);
|
|
if (values[usedId] === 'true') {
|
|
values[usedId] = true;
|
|
} else if (values[usedId] === 'false') {
|
|
values[usedId] = false;
|
|
} else if (!isNaN(values[usedId]) && values[usedId] == parseFloat(values[usedId])) {
|
|
values[usedId] = parseFloat(values[usedId]);
|
|
}
|
|
|
|
adapter.setForeignState(id, values[usedId], false, {user: values.user, limitToOwnerRights: that.adapter.config.onlyAllowWhenUserIsOwner}, function (err, id) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
cnt = 0;
|
|
} else {
|
|
status = 200;
|
|
adapter.log.debug('Add to Response: ' + JSON.stringify({id: id, val: values[usedId]}));
|
|
response.push({id: id, val: values[usedId]});
|
|
if (!--cnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
if (!cnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
break;
|
|
|
|
default:
|
|
doResponse(res, responseType, status, headers, {error: 'command ' + command + ' unknown'}, values.prettyPrint);
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
function restApiDelayedAnswer() {
|
|
if (that.restApiDelayed.timer) {
|
|
clearTimeout(that.restApiDelayed.timer);
|
|
that.restApiDelayed.timer = null;
|
|
|
|
doResponse(that.restApiDelayed.res, that.restApiDelayed.responseType, 200, {'Access-Control-Allow-Origin': '*'}, that.restApiDelayed.response, that.restApiDelayed.prettyPrint);
|
|
that.restApiDelayed.id = null;
|
|
that.restApiDelayed.res = null;
|
|
that.restApiDelayed.response = null;
|
|
that.restApiDelayed.prettyPrint = false;
|
|
}
|
|
}
|
|
|
|
function findState(idOrName, user, type, callback) {
|
|
if (typeof type === 'function') {
|
|
callback = type;
|
|
type = null;
|
|
}
|
|
adapter.findForeignObject(idOrName, type, {user: user, checked: true}, callback);
|
|
}
|
|
|
|
function getState(idOrName, user, type, callback) {
|
|
if (typeof type === 'function') {
|
|
callback = type;
|
|
type = null;
|
|
}
|
|
findState(idOrName, user, type, function (err, id, originId) {
|
|
if (err) {
|
|
if (callback) callback(err, undefined, null, originId);
|
|
} else
|
|
if (id) {
|
|
that.adapter.getForeignState(id, {user: user, limitToOwnerRights: that.adapter.config.onlyAllowWhenUserIsOwner}, function (err, obj) {
|
|
if (err || !obj) {
|
|
obj = undefined;
|
|
}
|
|
if (callback) callback (err, obj, id, originId);
|
|
});
|
|
} else {
|
|
if (callback) callback (null, undefined, null, originId);
|
|
}
|
|
});
|
|
}
|
|
|
|
function doResponse(res, type, status, headers, content, pretty) {
|
|
if (!headers) headers = {};
|
|
|
|
status = parseInt(status, 10) || 200;
|
|
|
|
if (pretty && typeof content === 'object') {
|
|
type = 'plain';
|
|
content = JSON.stringify(content, null, 2);
|
|
}
|
|
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
|
|
|
|
switch (type) {
|
|
case 'json':
|
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
res.statusCode = status;
|
|
res.end(JSON.stringify(content), 'utf8');
|
|
break;
|
|
|
|
case 'plain':
|
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
res.statusCode = status;
|
|
if (typeof content === 'object') {
|
|
content = JSON.stringify(content);
|
|
}
|
|
|
|
res.end(content, 'utf8');
|
|
break;
|
|
}
|
|
}
|
|
|
|
// static information
|
|
var commandsPermissions = {
|
|
getPlainValue: {type: 'state', operation: 'read'},
|
|
get: {type: 'state', operation: 'read'},
|
|
getBulk: {type: 'state', operation: 'read'},
|
|
set: {type: 'state', operation: 'write'},
|
|
toggle: {type: 'state', operation: 'write'},
|
|
setBulk: {type: 'state', operation: 'write'},
|
|
setValueFromBody: {type: 'state', operation: 'write'},
|
|
getObjects: {type: 'object', operation: 'list'},
|
|
objects: {type: 'object', operation: 'list'},
|
|
states: {type: 'state', operation: 'list'},
|
|
getStates: {type: 'state', operation: 'list'},
|
|
help: {type: '', operation: ''}
|
|
};
|
|
|
|
this.commands = [];
|
|
for (var c in commandsPermissions) {
|
|
this.commands.push(c);
|
|
}
|
|
// Register api by express
|
|
this.checkRequest = function (url) {
|
|
var parts = url.split('/', 2);
|
|
return (parts[1] && this.commands.indexOf(parts[1]) !== -1);
|
|
};
|
|
|
|
this.checkPermissions = function (user, command, callback) {
|
|
adapter.calculatePermissions(user, commandsPermissions, function (acl) {
|
|
if (user !== 'system.user.admin') {
|
|
// type: file, object, state, other
|
|
// operation: create, read, write, list, delete, sendto, execute, sendto
|
|
if (commandsPermissions[command]) {
|
|
// If permission required
|
|
if (commandsPermissions[command].type) {
|
|
if (acl[commandsPermissions[command].type] &&
|
|
acl[commandsPermissions[command].type][commandsPermissions[command].operation]) {
|
|
return callback(null);
|
|
}
|
|
} else {
|
|
return callback(null);
|
|
}
|
|
}
|
|
|
|
that.adapter.log.warn('No permission for "' + user + '" to call ' + command);
|
|
|
|
if (callback) callback('permissionError');
|
|
} else {
|
|
return callback(null);
|
|
}
|
|
});
|
|
};
|
|
|
|
this.restApi = function (req, res, isAuth, isChecked) {
|
|
var values = {};
|
|
var oId = [];
|
|
var wait = 0;
|
|
var responseType = 'json';
|
|
var status = 500;
|
|
var headers = {'Access-Control-Allow-Origin': '*'};
|
|
var response;
|
|
|
|
var url;
|
|
try {
|
|
url = decodeURI(req.url);
|
|
}
|
|
catch (e) {
|
|
url = req.url;
|
|
that.adapter.log.warn('Malformed URL encoding: ' + e);
|
|
}
|
|
var pos = url.indexOf('?');
|
|
if (pos !== -1) {
|
|
var arr = url.substring(pos + 1).split('&');
|
|
url = url.substring(0, pos);
|
|
|
|
for (var i = 0; i < arr.length; i++) {
|
|
arr[i] = arr[i].split('=');
|
|
//that.adapter.log.debug('Try Decode ' + i + ': ' + arr[i][1]);
|
|
try {
|
|
values[arr[i][0].trim()] = (arr[i][1] === undefined) ? null : decodeURIComponent((arr[i][1]+'').replace(/\+/g, '%20'));
|
|
}
|
|
catch(e) {
|
|
values[arr[i][0].trim()] = arr[i][1];
|
|
}
|
|
//that.adapter.log.debug(' Decode Result ' + i + ': ' + values[arr[i][0].trim()]);
|
|
}
|
|
if (values.prettyPrint !== undefined) {
|
|
if (values.prettyPrint === 'false') values.prettyPrint = false;
|
|
if (values.prettyPrint === null) values.prettyPrint = true;
|
|
}
|
|
// Default value for wait
|
|
if (values.wait === null) values.wait = 2000;
|
|
}
|
|
|
|
var parts = url.split('/');
|
|
var command = parts[1];
|
|
|
|
// Analyse system.adapter.socketio.0.uptime,system.adapter.history.0.memRss?value=78&wait=300
|
|
if (parts[2]) {
|
|
oId = parts[2].split(',');
|
|
for (var j = oId.length - 1; j >= 0; j--) {
|
|
oId[j] = oId[j].trim();
|
|
if (!oId[j]) oId.splice(j, 1);
|
|
}
|
|
}
|
|
|
|
// If authentication check is required
|
|
if (that.settings.auth) {
|
|
if (!isAuth) {
|
|
this.isAuthenticated(values, function (isAuth) {
|
|
if (isAuth) {
|
|
that.restApi(req, res, true);
|
|
} else {
|
|
doResponse(res, 'plain', 401, headers, 'error: authentication failed. Please write "http' + (that.settings.secure ? 's' : '') + '://' + req.headers.host + '?user=UserName&pass=Password"');
|
|
}
|
|
});
|
|
return;
|
|
} else
|
|
if (!isChecked) {
|
|
if (!values.user.match(/^system\.user\./)) values.user = 'system.user.' + values.user;
|
|
that.checkPermissions(values.user, command, function (err) {
|
|
if (!err) {
|
|
that.restApi(req, res, true, true);
|
|
} else {
|
|
doResponse(res, 'plain', 401, headers, 'error: ' + err, values.prettyPrint);
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
} else {
|
|
req.user = req.user || that.adapter.config.defaultUser;
|
|
values.user = req.user;
|
|
if (!values.user.match(/^system\.user\./)) values.user = 'system.user.' + values.user;
|
|
if (!isChecked && command) {
|
|
that.checkPermissions(req.user || that.adapter.config.defaultUser, command, function (err) {
|
|
if (!err) {
|
|
that.restApi(req, res, true, true);
|
|
} else {
|
|
doResponse(res, 'plain', 401, headers, 'error: ' + err, values.prettyPrint);
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
if (!values.user.match(/^system\.user\./)) values.user = 'system.user.' + values.user;
|
|
|
|
if (req.method === 'POST') {
|
|
restApiPost(req, res, command, oId, values);
|
|
return;
|
|
}
|
|
|
|
switch (command) {
|
|
case 'getPlainValue':
|
|
responseType = 'plain';
|
|
if (!oId.length || !oId[0]) {
|
|
doResponse(res, 'plain', status, headers, 'error: no datapoint given', values.prettyPrint);
|
|
break;
|
|
}
|
|
|
|
var pcnt = oId.length;
|
|
response = '';
|
|
for (var g = 0; g < oId.length; g++) {
|
|
getState(oId[g], values.user, function (err, obj, id, originId) {
|
|
if (err) {
|
|
status = 500;
|
|
response = 'error: ' + err;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
pcnt = 1;
|
|
} else if ((!id && originId) || obj === undefined) {
|
|
response += (response ? '\n' : '') + 'error: datapoint "' + originId + '" not found';
|
|
} else {
|
|
response += (response ? '\n' : '') + JSON.stringify(obj.val);
|
|
status = 200;
|
|
}
|
|
if (!--pcnt) doResponse(res, ((status === 500)?'plain':responseType), status, headers, response, values.prettyPrint);
|
|
});
|
|
}
|
|
break;
|
|
|
|
case 'get':
|
|
if (!oId.length || !oId[0]) {
|
|
doResponse(res, responseType, status, headers, {error: 'no object/datapoint given'}, values.prettyPrint);
|
|
break;
|
|
}
|
|
|
|
var gcnt = oId.length;
|
|
for (var k = 0; k < oId.length; k++) {
|
|
that.adapter.log.debug('work for ID ' + oId[k]);
|
|
getState(oId[k], values.user, function (err, state, id, originId) {
|
|
that.adapter.log.debug('return err ' + err);
|
|
that.adapter.log.debug('return state ' + state);
|
|
that.adapter.log.debug('return id ' + JSON.stringify(id));
|
|
that.adapter.log.debug('return originId' + originId);
|
|
if (err) {
|
|
gcnt = 0;
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
} else
|
|
if (!id && originId) {
|
|
if (!response || obj === undefined) {
|
|
response = 'error: datapoint "' + originId + '" not found';
|
|
} else {
|
|
if (typeof response !== 'object' || response.constructor !== Array) {
|
|
response = [response];
|
|
}
|
|
response.push('error: datapoint "' + originId + '" not found');
|
|
}
|
|
if (!--gcnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
} else {
|
|
var vObj = state || {};
|
|
status = 200;
|
|
that.adapter.getForeignObject(id, function (err, obj) {
|
|
if (obj) {
|
|
for (var attr in obj) {
|
|
if (obj.hasOwnProperty(attr)) {
|
|
vObj[attr] = obj[attr];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!response) {
|
|
response = vObj;
|
|
} else {
|
|
if (typeof response !== 'object' || response.constructor !== Array) response = [response];
|
|
response.push(vObj);
|
|
}
|
|
|
|
if (!--gcnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
|
|
case 'getBulk':
|
|
if (!oId.length || !oId[0]) {
|
|
doResponse(res, responseType, status, headers, {error: 'no datapoints given'}, values.prettyPrint);
|
|
break;
|
|
}
|
|
var bcnt = oId.length;
|
|
response = [];
|
|
for (var b = 0; b < oId.length; b++) {
|
|
getState(oId[b], values.user, function (err, state, id, originId) {
|
|
if (err) {
|
|
bcnt = 0;
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, responseType, status, headers, 'error: ' + err, values.prettyPrint);
|
|
} else {
|
|
if (id) status = 200;
|
|
state = state || {};
|
|
response.push({val: state.val, ts: state.ts});
|
|
if (!--bcnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
}
|
|
});
|
|
}
|
|
if (!bcnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
break;
|
|
|
|
case 'set':
|
|
if (!oId.length || !oId[0]) {
|
|
doResponse(res, responseType, status, headers, {error: "object/datapoint not given"}, values.prettyPrint);
|
|
break;
|
|
}
|
|
if (values.value === undefined && values.val === undefined) {
|
|
doResponse(res, responseType, status, headers, 'error: no value found for "' + oId[0] + '". Use /set/id?value=1 or /set/id?value=1&wait=1000', values.prettyPrint);
|
|
} else {
|
|
findState(oId[0], values.user, function (err, id, originId) {
|
|
if (err) {
|
|
wait = 0;
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err);
|
|
} else
|
|
if (id) {
|
|
wait = values.wait || 0;
|
|
if (wait) wait = parseInt(wait, 10);
|
|
if (values.val === undefined) values.val = values.value;
|
|
|
|
if (values.val === 'true') {
|
|
values.val = true;
|
|
} else if (values.val === 'false') {
|
|
values.val = false;
|
|
} else if (!isNaN(values.val)) {
|
|
values.val = parseFloat(values.val);
|
|
}
|
|
|
|
if (wait) adapter.subscribeForeignStates(id);
|
|
|
|
adapter.setForeignState(id, values.val, false, {user: values.user, limitToOwnerRights: that.adapter.config.onlyAllowWhenUserIsOwner}, function (err) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
wait = 0;
|
|
} else
|
|
if (!wait) {
|
|
status = 200;
|
|
response = {id: id, value: values.val, val: values.val};
|
|
doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
}
|
|
});
|
|
|
|
if (wait) {
|
|
that.restApiDelayed.responseType = responseType;
|
|
that.restApiDelayed.response = null;
|
|
that.restApiDelayed.id = id;
|
|
that.restApiDelayed.res = res;
|
|
that.restApiDelayed.prettyPrint = values.prettyPrint;
|
|
that.restApiDelayed.timer = setTimeout(restApiDelayedAnswer, wait);
|
|
}
|
|
} else {
|
|
doResponse(res, responseType, status, headers, 'error: datapoint "' + originId + '" not found', values.prettyPrint);
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
|
|
case 'toggle':
|
|
if (!oId.length || !oId[0]) {
|
|
doResponse(res, responseType, status, headers, {error: "state not given"}, values.prettyPrint);
|
|
break;
|
|
}
|
|
|
|
findState(oId[0], values.user, function (err, id, originId) {
|
|
if (err) {
|
|
doResponse(res, 'plain', 500, headers, 'error: ' + err, values.prettyPrint);
|
|
wait = 0;
|
|
} else if (id) {
|
|
wait = values.wait || 0;
|
|
if (wait) wait = parseInt(wait, 10);
|
|
|
|
// Read type of object
|
|
adapter.getForeignObject(id, {user: values.user, checked: true}, function (err, obj) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
wait = 0;
|
|
} else {
|
|
// Read actual value
|
|
adapter.getForeignState(id, {user: values.user, checked: true}, function (err, state) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
wait = 0;
|
|
} else
|
|
if (state) {
|
|
if (obj && obj.common && obj.common.type) {
|
|
if (obj.common.type === 'bool' || obj.common.type === 'boolean') {
|
|
if (state.val === 'true') {
|
|
state.val = true;
|
|
} else if (state.val === 'false') {
|
|
state.val = false;
|
|
}
|
|
state.val = !state.val;
|
|
} else
|
|
if (obj.common.type === 'number') {
|
|
state.val = parseFloat(state.val);
|
|
if (obj.common.max !== undefined) {
|
|
if (obj.common.min === undefined) obj.common.min = 0;
|
|
if (state.val > obj.common.max) state.val = obj.common.max;
|
|
if (state.val < obj.common.min) state.val = obj.common.min;
|
|
// Invert
|
|
state.val = obj.common.max + obj.common.min - state.val;
|
|
} else {
|
|
// default number is from 0 to 100
|
|
if (state.val > 100) state.val = 100;
|
|
if (state.val < 0) state.val = 0;
|
|
state.val = 100 - state.val;
|
|
}
|
|
} else {
|
|
if (state.val === 'true' || state.val === true) {
|
|
state.val = false;
|
|
} else if (state.val === 'false' || state.val === false) {
|
|
state.val = true;
|
|
} else if (parseInt(state.val, 10) == state.val) {
|
|
state.val = parseInt(state.val, 10) ? 0 : 1;
|
|
} else {
|
|
doResponse(res, responseType, status, headers, {error: 'state is neither number nor boolean'}, values.prettyPrint);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
if (state.val === 'true') {
|
|
state.val = true;
|
|
} else if (state.val === 'false') {
|
|
state.val = false;
|
|
} else if (!isNaN(state.val)) {
|
|
state.val = parseFloat(state.val);
|
|
}
|
|
|
|
if (state.val === true) state.val = 1;
|
|
if (state.val === false) state.val = 0;
|
|
state.val = 1 - parseInt(state.val, 10);
|
|
}
|
|
|
|
if (wait) adapter.subscribeForeignStates(id);
|
|
|
|
adapter.setForeignState(id, state.val, false, {user: values.user, limitToOwnerRights: that.adapter.config.onlyAllowWhenUserIsOwner}, function (err) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
wait = 0;
|
|
} else
|
|
if (!wait) {
|
|
status = 200;
|
|
doResponse(res, responseType, status, headers, {id: id, value: state.val, val: state.val}, values.prettyPrint);
|
|
}
|
|
});
|
|
|
|
if (wait) {
|
|
that.restApiDelayed.responseType = responseType;
|
|
that.restApiDelayed.response = null;
|
|
that.restApiDelayed.id = id;
|
|
that.restApiDelayed.res = res;
|
|
that.restApiDelayed.prettyPrint = values.prettyPrint;
|
|
that.restApiDelayed.timer = setTimeout(restApiDelayedAnswer, wait);
|
|
}
|
|
} else {
|
|
doResponse(res, responseType, status, headers, {error: 'object has no state'}, values.prettyPrint);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
doResponse(res, responseType, status, headers, {error: 'error: datapoint "' + originId + '" not found'}, values.prettyPrint);
|
|
}
|
|
});
|
|
|
|
break;
|
|
|
|
// /setBulk?BidCos-RF.FEQ1234567:1.LEVEL=0.7&Licht-Küche/LEVEL=0.7&Anwesenheit=0&950=1
|
|
case 'setBulk':
|
|
var cnt = 0;
|
|
response = [];
|
|
adapter.log.debug('Values: ' + JSON.stringify(values));
|
|
for (var _id in values) {
|
|
if (_id === 'prettyPrint' || _id === 'user' || _id === 'pass') continue;
|
|
cnt++;
|
|
findState(_id, values.user, function (err, id, originId) {
|
|
// id is "name", originId is the yunkong2-ID of the datapoint
|
|
if (err) {
|
|
adapter.log.debug('Error on ID lookup: ' + err);
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
cnt = 0;
|
|
} else if (!id) {
|
|
response.push({error: 'error: datapoint "' + originId + '" not found'});
|
|
if (!--cnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
} else {
|
|
var usedId = (values[originId]?originId:id);
|
|
that.adapter.log.debug('GET-' + command + ' for id=' + id + ', oid=' + originId + 'used=' + usedId + ', value=' + values[usedId]);
|
|
if (values[usedId] === 'true') {
|
|
values[usedId] = true;
|
|
} else if (values[usedId] === 'false') {
|
|
values[usedId] = false;
|
|
} else if (!isNaN(values[usedId]) && values[usedId] == parseFloat(values[usedId])) {
|
|
values[usedId] = parseFloat(values[usedId]);
|
|
}
|
|
|
|
adapter.setForeignState(id, values[usedId], false, {user: values.user, limitToOwnerRights: that.adapter.config.onlyAllowWhenUserIsOwner}, function (err, id) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, 'plain', status, headers, 'error: ' + err, values.prettyPrint);
|
|
cnt = 0;
|
|
} else {
|
|
adapter.log.debug('Add to Response-Get: ' + JSON.stringify({id: id, val: values[usedId], value: values[usedId]}));
|
|
response.push({id: id, val: values[usedId], value: values[usedId]});
|
|
if (!--cnt) {
|
|
status = 200;
|
|
doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
if (!cnt) doResponse(res, responseType, status, headers, response, values.prettyPrint);
|
|
break;
|
|
|
|
case 'getObjects':
|
|
case 'objects':
|
|
adapter.getForeignObjects(values.pattern || parts[2] || '*', values.type, {user: values.user, limitToOwnerRights: that.adapter.config.onlyAllowWhenUserIsOwner}, function (err, list) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, responseType, status, headers, {error: JSON.stringify(err)}, values.prettyPrint);
|
|
} else {
|
|
status = 200;
|
|
doResponse(res, responseType, status, headers, list, values.prettyPrint);
|
|
}
|
|
});
|
|
break;
|
|
|
|
case 'getStates':
|
|
case 'states':
|
|
adapter.getForeignStates(values.pattern || parts[2] || '*', {user: values.user, limitToOwnerRights: that.adapter.config.onlyAllowWhenUserIsOwner}, function (err, list) {
|
|
if (err) {
|
|
status = 500;
|
|
if (err.indexOf('permissionError') !== -1) {
|
|
status = 401;
|
|
}
|
|
doResponse(res, responseType, status, headers, {error: JSON.stringify(err)}, values.prettyPrint);
|
|
} else {
|
|
status = 200;
|
|
doResponse(res, responseType, status, headers, list, values.prettyPrint);
|
|
}
|
|
});
|
|
break;
|
|
|
|
case 'help':
|
|
// is default behaviour too
|
|
default:
|
|
var obj = (command === 'help') ? {} : {error: 'command ' + command + ' unknown'};
|
|
var request = 'http' + (that.settings.secure ? 's' : '') + '://' + req.headers.host;
|
|
if (this.app) request += '/' + this.namespace + '/';
|
|
var auth = '';
|
|
if (that.settings.auth) auth = 'user=UserName&pass=Password';
|
|
obj.getPlainValue = request + '/getPlainValue/stateID' + (auth ? '?' + auth : '');
|
|
obj.get = request + '/get/stateID/?prettyPrint' + (auth ? '&' + auth : '');
|
|
obj.getBulk = request + '/getBulk/stateID1,stateID2/?prettyPrint' + (auth ? '&' + auth : '');
|
|
obj.set = request + '/set/stateID?value=1&prettyPrint' + (auth ? '&' + auth : '');
|
|
obj.toggle = request + '/toggle/stateID&prettyPrint' + (auth ? '&' + auth : '');
|
|
obj.setBulk = request + '/setBulk?stateID1=0.7&stateID2=0&prettyPrint' + (auth ? '&' + auth : '');
|
|
obj.setValueFromBody = request + '/setValueFromBody?stateID1' + (auth ? '&' + auth : '');
|
|
obj.objects = request + '/objects?pattern=system.adapter.admin.0*&prettyPrint' + (auth ? '&' + auth : '');
|
|
obj.states = request + '/states?pattern=system.adapter.admin.0*&prettyPrint' + (auth ? '&' + auth : '');
|
|
|
|
doResponse(res, responseType, status, headers, obj, true);
|
|
break;
|
|
}
|
|
};
|
|
}
|
|
|
|
module.exports = SimpleAPI;
|