Initial commit
This commit is contained in:
commit
f645903d19
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
.idea
|
||||||
|
tmp
|
||||||
|
admin/i18n/flat.txt
|
||||||
|
admin/i18n/*/flat.txt
|
||||||
|
iob_npm.done
|
||||||
|
package-lock.json
|
9
.npmignore
Normal file
9
.npmignore
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
gulpfile.js
|
||||||
|
tasks
|
||||||
|
tmp
|
||||||
|
test
|
||||||
|
.travis.yml
|
||||||
|
appveyor.yml
|
||||||
|
admin/i18n
|
||||||
|
iob_npm.done
|
||||||
|
package-lock.json
|
23
.travis.yml
Normal file
23
.travis.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- '4'
|
||||||
|
- '6'
|
||||||
|
- '8'
|
||||||
|
- '10'
|
||||||
|
before_script:
|
||||||
|
- export NPMVERSION=$(echo "$($(which npm) -v)"|cut -c1)
|
||||||
|
- 'if [[ $NPMVERSION == 5 ]]; then npm install -g npm@5; fi'
|
||||||
|
- npm -v
|
||||||
|
- npm install winston@2.3.1
|
||||||
|
- 'npm install https://git.spacen.net/yunkong2/yunkong2.js-controller/tarball/master --production'
|
||||||
|
env:
|
||||||
|
- CXX=g++-4.8
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- g++-4.8
|
22
LICENSE
Normal file
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015-2017 bluefox <dogafox@gmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
498
README.md
Normal file
498
README.md
Normal file
@ -0,0 +1,498 @@
|
|||||||
|
![Logo](admin/simple-api.png)
|
||||||
|
yunkong2 simple-api adapter
|
||||||
|
=================
|
||||||
|
[![NPM version](http://img.shields.io/npm/v/yunkong2.simple-api.svg)](https://www.npmjs.com/package/yunkong2.simple-api)
|
||||||
|
[![Downloads](https://img.shields.io/npm/dm/yunkong2.simple-api.svg)](https://www.npmjs.com/package/yunkong2.simple-api)
|
||||||
|
[![Tests](https://travis-ci.org/yunkong2/yunkong2.simple-api.svg?branch=master)](https://travis-ci.org/yunkong2/yunkong2.simple-api)
|
||||||
|
|
||||||
|
[![NPM](https://nodei.co/npm/yunkong2.simple-api.png?downloads=true)](https://nodei.co/npm/yunkong2.simple-api/)
|
||||||
|
|
||||||
|
This is RESTFul interface to read the objects and states from yunkong2 and to write/control the states over HTTP Get/Post requests.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Call in browser ```http://ipaddress:8087/help``` to get the help about API. The result is:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"getPlainValue": "http://ipaddress:8087/getPlainValue/stateID",
|
||||||
|
"get": "http://ipaddress:8087/get/stateID/?prettyPrint",
|
||||||
|
"getBulk": "http://ipaddress:8087/getBulk/stateID1,stateID2/?prettyPrint",
|
||||||
|
"set": "http://ipaddress:8087/set/stateID?value=1&prettyPrint",
|
||||||
|
"toggle": "http://ipaddress:8087/toggle/stateID&prettyPrint",
|
||||||
|
"setBulk": "http://ipaddress:8087/setBulk?stateID1=0.7&stateID2=0&prettyPrint",
|
||||||
|
"objects": "http://ipaddress:8087/objects?pattern=system.adapter.admin.0*&prettyPrint",
|
||||||
|
"objects": "http://ipaddress:8087/objects?pattern=system.adapter.admin.0*&type=adapter&prettyPrint",
|
||||||
|
"states": "http://ipaddress:8087/states?pattern=system.adapter.admin.0*&prettyPrint"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### getPlainValue
|
||||||
|
Call e.g.:
|
||||||
|
```
|
||||||
|
http://ipaddress:8087/getPlainValue/system.adapter.admin.0.alive
|
||||||
|
```
|
||||||
|
Result:
|
||||||
|
```
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
### get
|
||||||
|
Call e.g.:
|
||||||
|
```
|
||||||
|
http://ipaddress:8087/get/system.adapter.admin.0.alive
|
||||||
|
```
|
||||||
|
Result:
|
||||||
|
```
|
||||||
|
{"val":true,"ack":true,"ts":1442432193,"from":"system.adapter.admin.0","lc":1442431190,"expire":23437,"_id":"system.adapter.admin.0.alive","type":"state","common":{"name":"admin.0.alive","type":"boolean","role":"indicator.state"},"native":{}}
|
||||||
|
```
|
||||||
|
or call e.g.:
|
||||||
|
```
|
||||||
|
http://ipaddress:8087/get/system.adapter.admin.0.alive?prettyPrint
|
||||||
|
```
|
||||||
|
Result:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"val": true,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1442432238,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1442431190,
|
||||||
|
"expire": 28494,
|
||||||
|
"_id": "system.adapter.admin.0.alive",
|
||||||
|
"type": "state",
|
||||||
|
"common": {
|
||||||
|
"name": "admin.0.alive",
|
||||||
|
"type": "boolean",
|
||||||
|
"role": "indicator.state"
|
||||||
|
},
|
||||||
|
"native": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### getBulk
|
||||||
|
get many states with one request, returned as object with ID as key and val/ts as subobject
|
||||||
|
|
||||||
|
### set
|
||||||
|
Call e.g.:
|
||||||
|
```
|
||||||
|
http://ipaddress:8087/set/javascript.0.test?value=1
|
||||||
|
```
|
||||||
|
Result:
|
||||||
|
```
|
||||||
|
{"id":"javascript.0.test","value":1}
|
||||||
|
```
|
||||||
|
or call e.g.:
|
||||||
|
```
|
||||||
|
http://ipaddress:8087/set/javascript.0.test?value=1&prettyPrint
|
||||||
|
```
|
||||||
|
Result:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"id": "javascript.0.test",
|
||||||
|
"value": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Of course the data point *javascript.0.test* must exist.
|
||||||
|
|
||||||
|
### toggle
|
||||||
|
toggles value:
|
||||||
|
- boolean: true => false, false => true
|
||||||
|
- number without limits: x => 100-x
|
||||||
|
- number with limits: x => max - (x - min)
|
||||||
|
|
||||||
|
### setBulk
|
||||||
|
Set many states with one request. This request supports POST method too, for POST data should be in body and not URL.
|
||||||
|
|
||||||
|
### setValueFromBody
|
||||||
|
Allows to set the value of a given State be set by the POST body content.
|
||||||
|
|
||||||
|
### objects
|
||||||
|
|
||||||
|
### states
|
||||||
|
|
||||||
|
### help
|
||||||
|
Gives [this](#usage) output back
|
||||||
|
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```node yunkong2.js add simple-api```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Assume, we have no security and the server runs on default port 8087.
|
||||||
|
|
||||||
|
For all queries the name or id of the state can be specified.
|
||||||
|
|
||||||
|
For every requiest that returns JSON you can set parameter *prettyPrint* to get the output in human readable form.
|
||||||
|
|
||||||
|
If authentication is enabled, two other fields are mandatory: <pre>?user=admin&pass=yunkong2</pre>
|
||||||
|
|
||||||
|
### getPlainValue
|
||||||
|
Read state value as text. You can specify more ids divided by semicolon
|
||||||
|
|
||||||
|
<pre>http://ip:8087/getPlainValue/admin.0.memHeapTotal</pre>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
31.19
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<pre>http://ip:8087/getPlainValue/admin.0.memHeapTotal, admin.0.memHeapUsed</pre>
|
||||||
|
<pre>
|
||||||
|
31.19
|
||||||
|
17.52
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
### get
|
||||||
|
Read state and object data of state as json. You can specify more ids divided by semicolon.
|
||||||
|
If more than one ID requested, the JSON array will be returned.
|
||||||
|
|
||||||
|
<pre>http://localhost:8087/get/admin.0.memHeapTotal/?prettyPrint</pre>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
{
|
||||||
|
"val": 31.19,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423154619,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423153989,
|
||||||
|
"_id": "system.adapter.admin.0.memHeapTotal",
|
||||||
|
"type": "state",
|
||||||
|
"common": {
|
||||||
|
"name": "admin.0.memHeapTotal",
|
||||||
|
"type": "number",
|
||||||
|
"role": "indicator.state",
|
||||||
|
"unit": "MB",
|
||||||
|
"history": {
|
||||||
|
"enabled": true,
|
||||||
|
"changesOnly": true,
|
||||||
|
"minLength": 480,
|
||||||
|
"maxLength": 960,
|
||||||
|
"retention": 604800,
|
||||||
|
"debounce": 10000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"native": {}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<pre>http://ip:8087/get/admin.0.memHeapTotal,admin.0.memHeapUsed/?prettyPrint</pre>
|
||||||
|
<pre>
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"val": 31.19,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423154544,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423153989,
|
||||||
|
"_id": "system.adapter.admin.0.memHeapTotal",
|
||||||
|
"type": "state",
|
||||||
|
"common": {
|
||||||
|
"name": "admin.0.memHeapTotal",
|
||||||
|
"type": "number",
|
||||||
|
"role": "indicator.state",
|
||||||
|
"unit": "MB",
|
||||||
|
"history": {
|
||||||
|
"enabled": true,
|
||||||
|
"changesOnly": true,
|
||||||
|
"minLength": 480,
|
||||||
|
"maxLength": 960,
|
||||||
|
"retention": 604800,
|
||||||
|
"debounce": 10000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"native": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"val": 16.25,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423154544,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423154544,
|
||||||
|
"_id": "system.adapter.admin.0.memHeapUsed",
|
||||||
|
"type": "state",
|
||||||
|
"common": {
|
||||||
|
"name": "admin.0.memHeapUsed",
|
||||||
|
"type": "number",
|
||||||
|
"role": "indicator.state",
|
||||||
|
"unit": "MB",
|
||||||
|
"history": {
|
||||||
|
"enabled": true,
|
||||||
|
"changesOnly": true,
|
||||||
|
"minLength": 480,
|
||||||
|
"maxLength": 960,
|
||||||
|
"retention": 604800,
|
||||||
|
"debounce": 10000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"native": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
### getBulk
|
||||||
|
Read the states of more IDs with timestamp. You can specify more ids divided by semicolon.
|
||||||
|
Always the JSON array will be returned.
|
||||||
|
|
||||||
|
<pre>http://ip:8087/getBulk/admin.0.memHeapTotal,admin.0.memHeapUsed/?prettyPrint</pre>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
{
|
||||||
|
"admin.0.memHeapTotal": {
|
||||||
|
"val": 31.19,
|
||||||
|
"ts": 1423154754
|
||||||
|
},
|
||||||
|
"admin.0.memHeapUsed": {
|
||||||
|
"val": 15.6,
|
||||||
|
"ts": 1423154754
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
### set
|
||||||
|
Write the states with specified IDs. You can specifiy *wait* option in milliseconds to wait for answer from driver.
|
||||||
|
|
||||||
|
<pre>http://ip:8087/set/hm-rpc.0.IEQ12345.LEVEL?value=1&prettyPrint</pre>
|
||||||
|
<pre>{
|
||||||
|
"id": "hm-rpc.0.IEQ12345.LEVEL",
|
||||||
|
"value": 1
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<pre>http://ip:8087/set/hm-rpc.0.IEQ12345.LEVEL?value=1&wait=5000&prettyPrint</pre>
|
||||||
|
<pre>{
|
||||||
|
"val": 1,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423155399,
|
||||||
|
"from": "hm-rpc.0.IEQ12345.LEVEL",
|
||||||
|
"lc": 1423155399
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
If no answer will be recieved in specified time, the *null* value will be returned.
|
||||||
|
In the first case the answer will be returned immediately and *ack* is false. In the second case *ack* is true. That means it was response from driver.
|
||||||
|
|
||||||
|
### setBulk
|
||||||
|
- write bulk of IDs in one request.
|
||||||
|
|
||||||
|
<pre>http://ip:8087/setBulk?hm-rpc.0.FEQ1234567:1.LEVEL=0.7&Anwesenheit=0&prettyPrint</pre>
|
||||||
|
<pre>
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "hm-rpc.0.FEQ1234567:1.LEVEL",
|
||||||
|
"val": "0.7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"error": "error: datapoint \"Anwesenheit\" not found"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</pre>
|
||||||
|
You can send this request as POST too.
|
||||||
|
|
||||||
|
### objects
|
||||||
|
Get the list of all objects for pattern. If no pattern specified all objects as JSON array will be returned.
|
||||||
|
|
||||||
|
<pre>http://ip:8087/objects?prettyPrint</pre>
|
||||||
|
<pre>
|
||||||
|
{
|
||||||
|
"system.adapter.admin.0.uptime": {
|
||||||
|
"_id": "system.adapter.admin.0.uptime",
|
||||||
|
"type": "state",
|
||||||
|
"common": {
|
||||||
|
"name": "admin.0.uptime",
|
||||||
|
"type": "number",
|
||||||
|
"role": "indicator.state",
|
||||||
|
"unit": "seconds"
|
||||||
|
},
|
||||||
|
"native": {}
|
||||||
|
},
|
||||||
|
"system.adapter.admin.0.memRss": {
|
||||||
|
"_id": "system.adapter.admin.0.memRss",
|
||||||
|
"type": "state",
|
||||||
|
"common": {
|
||||||
|
"name": "admin.0.memRss",
|
||||||
|
"desc": "Resident set size",
|
||||||
|
"type": "number",
|
||||||
|
"role": "indicator.state",
|
||||||
|
"unit": "MB",
|
||||||
|
"history": {
|
||||||
|
"enabled": true,
|
||||||
|
"changesOnly": true,
|
||||||
|
"minLength": 480,
|
||||||
|
"maxLength": 960,
|
||||||
|
"retention": 604800,
|
||||||
|
"debounce": 10000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"native": {}
|
||||||
|
},
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Get all control objects of adapter system.adapter.admin.0:
|
||||||
|
<pre>http://ip:8087/objects?pattern=system.adapter.admin.0*&prettyPrint</pre>
|
||||||
|
<pre>
|
||||||
|
{
|
||||||
|
"system.adapter.admin.0.uptime": {
|
||||||
|
"_id": "system.adapter.admin.0.uptime",
|
||||||
|
"type": "state",
|
||||||
|
"common": {
|
||||||
|
"name": "admin.0.uptime",
|
||||||
|
"type": "number",
|
||||||
|
"role": "indicator.state",
|
||||||
|
"unit": "seconds"
|
||||||
|
},
|
||||||
|
"native": {}
|
||||||
|
},
|
||||||
|
...
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
### states
|
||||||
|
Get the list of all states for pattern. If no pattern specified all states as JSON array will be returned.
|
||||||
|
|
||||||
|
<pre>http://ip:8087/states?prettyPrint</pre>
|
||||||
|
<pre>
|
||||||
|
{
|
||||||
|
"system.adapter.admin.0.uptime": {
|
||||||
|
"val": 32176,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423156164,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423156164
|
||||||
|
},
|
||||||
|
"system.adapter.admin.0.memRss": {
|
||||||
|
"val": 41.14,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423156164,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423156119
|
||||||
|
},
|
||||||
|
"system.adapter.admin.0.memHeapTotal": {
|
||||||
|
"val": 31.19,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423156164,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423155084
|
||||||
|
},
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Get all control objects of adapter system.adapter.admin.0:
|
||||||
|
|
||||||
|
<pre>http://ip:8087/states?pattern=system.adapter.admin.0*&prettyPrint</pre>
|
||||||
|
<pre>
|
||||||
|
{
|
||||||
|
"system.adapter.admin.0.uptime": {
|
||||||
|
"val": 32161,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423156149,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423156149
|
||||||
|
},
|
||||||
|
"system.adapter.admin.0.memRss": {
|
||||||
|
"val": 41.14,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423156149,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423156119
|
||||||
|
},
|
||||||
|
"system.adapter.admin.0.memHeapTotal": {
|
||||||
|
"val": 31.19,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423156149,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423155084
|
||||||
|
},
|
||||||
|
"system.adapter.admin.0.memHeapUsed": {
|
||||||
|
"val": 19.07,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423156149,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423156149
|
||||||
|
},
|
||||||
|
"system.adapter.admin.0.connected": {
|
||||||
|
"val": true,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423156149,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423128324,
|
||||||
|
"expire": 28100
|
||||||
|
},
|
||||||
|
"system.adapter.admin.0.alive": {
|
||||||
|
"val": true,
|
||||||
|
"ack": true,
|
||||||
|
"ts": 1423156149,
|
||||||
|
"from": "system.adapter.admin.0",
|
||||||
|
"lc": 1423128324,
|
||||||
|
"expire": 28115
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
### 2.0.0 (2018-06-29)
|
||||||
|
* (Giermann) BREAKING CHANGE: getBulk is returning data in a different structure
|
||||||
|
|
||||||
|
### 1.6.3 (2018-04-15)
|
||||||
|
* (Apollon77) Return used character encoding (UTF-8)
|
||||||
|
|
||||||
|
### 1.6.2 (2017-11-27)
|
||||||
|
* (Apollon77) Fix decoding problems
|
||||||
|
|
||||||
|
### 1.6.1 (2017-09-25)
|
||||||
|
* (Apollon77) Fix statuscode for setBulk and optimize permission errors
|
||||||
|
|
||||||
|
### 1.6.0 (2017-07-10)
|
||||||
|
* (Apollon77) Fix handling of URL-encoded values, they are now decoded properly
|
||||||
|
* (Apollon77) Optimize Permission handling
|
||||||
|
* (Apollon77) add possibility to only allow access to states where user is also owner, finally works correct with js-controller 1.1.1!
|
||||||
|
|
||||||
|
### 1.5.0 (2017-03-10)
|
||||||
|
* (greyhound) Add new POST method setValueFromBody
|
||||||
|
|
||||||
|
### 1.4.0 (2017-01-05)
|
||||||
|
* (bluefox) new web server plugin support
|
||||||
|
|
||||||
|
### 1.3.0 (2016-08-30)
|
||||||
|
* (bluefox) сompatible only with new admin
|
||||||
|
|
||||||
|
### 1.2.0 (2016-08-27)
|
||||||
|
* (bluefox) support of letsencrypt certificates
|
||||||
|
|
||||||
|
### 1.1.1 (2016-07-06)
|
||||||
|
* (bluefox) support of chained certificates
|
||||||
|
|
||||||
|
### 1.1.0 (2016-02-09)
|
||||||
|
* (bluefox) fix toggle, objects, states, setBulk, POST
|
||||||
|
* (bluefox) add tests
|
||||||
|
|
||||||
|
### 1.0.0 (2015-09-30)
|
||||||
|
* (bluefox) stop adapter before update
|
||||||
|
|
||||||
|
### 0.1.2 (2015-06-28)
|
||||||
|
* (bluefox) add description in readme.md
|
||||||
|
* (bluefox) change "toggle" for boolean and numbers
|
||||||
|
|
||||||
|
### 0.1.1 (2015-06-28)
|
||||||
|
* (bluefox) change setForeignState api
|
||||||
|
* (bluefox) add type to io-package.json
|
||||||
|
* (bluefox) enable run from "web"
|
||||||
|
* (bluefox) add default user
|
||||||
|
|
||||||
|
### 0.1.0 (2015-06-10)
|
||||||
|
* (bluefox) change setForeignState api
|
||||||
|
* (bluefox) support of user permissions
|
||||||
|
|
||||||
|
### 0.0.4 (2015-03-11)
|
||||||
|
* (bluefox) remove socket.io from file
|
||||||
|
|
||||||
|
### 0.0.3 (2015-02-13)
|
||||||
|
* (bluefox) remove socket.io from dependencies
|
||||||
|
|
||||||
|
### 0.0.2 (2015-02-12)
|
||||||
|
* (bluefox) enable be a part of "web"
|
||||||
|
|
||||||
|
### 0.0.1 (2015-02-06)
|
||||||
|
* (bluefox) initial commit
|
176
admin/index.html
Normal file
176
admin/index.html
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../lib/css/themes/jquery-ui/redmond/jquery-ui.min.css"/>
|
||||||
|
<script type="text/javascript" src="../../lib/js/jquery-1.11.1.min.js"></script>
|
||||||
|
<script type="text/javascript" src="../../socket.io/socket.io.js"></script>
|
||||||
|
<script type="text/javascript" src="../../lib/js/jquery-ui-1.10.3.full.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../css/adapter.css"/>
|
||||||
|
<script type="text/javascript" src="../../js/translate.js"></script>
|
||||||
|
<script type="text/javascript" src="../../js/adapter-settings.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.number {
|
||||||
|
width: 70px
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="words.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function showHideSettings() {
|
||||||
|
if ($('#webInstance').val()) {
|
||||||
|
$('.no-if-extend').hide();
|
||||||
|
} else {
|
||||||
|
$('.no-if-extend').show();
|
||||||
|
if ($('#secure').prop('checked')) {
|
||||||
|
$('#_certPublic').show();
|
||||||
|
$('#_certPrivate').show();
|
||||||
|
$('#_certChained').show();
|
||||||
|
$('.le-settings').show();
|
||||||
|
|
||||||
|
if ($('#leEnabled').prop('checked')) {
|
||||||
|
$('.le-sub-settings').show();
|
||||||
|
if ($('#leUpdate').prop('checked')) {
|
||||||
|
$('.le-sub-settings-update').show();
|
||||||
|
} else {
|
||||||
|
$('.le-sub-settings-update').hide();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$('.le-sub-settings').hide();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$('#_certPublic').hide();
|
||||||
|
$('#_certPrivate').hide();
|
||||||
|
$('#_certChained').hide();
|
||||||
|
$('#auth').prop('checked', false);
|
||||||
|
$('.le-settings').hide();
|
||||||
|
}
|
||||||
|
if ($('#auth').prop('checked')) {
|
||||||
|
$('#defaultUser').val('admin');
|
||||||
|
$('.defaultUser').hide();
|
||||||
|
} else {
|
||||||
|
$('.defaultUser').show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the function loadSettings has to exist ...
|
||||||
|
function load(settings, onChange) {
|
||||||
|
if (!settings) return;
|
||||||
|
|
||||||
|
if (!settings.lePort) settings.lePort = 80;
|
||||||
|
|
||||||
|
getIPs(function(ips) {
|
||||||
|
for (var i = 0; i < ips.length; i++) {
|
||||||
|
$('#bind').append('<option value="' + ips[i].address + '">' + ips[i].name + '</option>');
|
||||||
|
}
|
||||||
|
$('#bind.value').val(settings.bind);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.value').each(function () {
|
||||||
|
var key = $(this).attr('id');
|
||||||
|
// example: select elements with id=key and class=value and insert value
|
||||||
|
if ($('#' + key + '.value').attr('type') == 'checkbox') {
|
||||||
|
$('#' + key + '.value').prop('checked', settings[key]).change(function() {
|
||||||
|
if ($('#auth').prop('checked')) {
|
||||||
|
$('#secure').prop('checked', true);
|
||||||
|
}
|
||||||
|
showHideSettings();
|
||||||
|
onChange();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$('#' + key + '.value').val(settings[key]).change(function() {
|
||||||
|
if (key === 'webInstance') showHideSettings();
|
||||||
|
onChange();
|
||||||
|
}).keyup(function() {
|
||||||
|
onChange();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
fillSelectCertificates('#certPublic', 'public', settings.certPublic);
|
||||||
|
fillSelectCertificates('#certPublic', 'public', settings.certPublic);
|
||||||
|
fillSelectCertificates('#certPrivate', 'private', settings.certPrivate);
|
||||||
|
fillSelectCertificates('#certChained', 'chained', settings.certChained);
|
||||||
|
fillUsers('#defaultUser', settings.defaultUser);
|
||||||
|
|
||||||
|
if (typeof getExtendableInstances !== 'undefined') {
|
||||||
|
getExtendableInstances(function (result) {
|
||||||
|
if (result) {
|
||||||
|
var text = '';
|
||||||
|
for (var r = 0; r < result.length; r++) {
|
||||||
|
var name = result[r]._id.substring('system.adapter.'.length);
|
||||||
|
text += '<option value="' + name + '" ' + (settings.webInstance === name ? 'selected' : '') + '>' + name + '</option>';
|
||||||
|
}
|
||||||
|
$('#webInstance').append(text);
|
||||||
|
showHideSettings();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showHideSettings();
|
||||||
|
}
|
||||||
|
onChange(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... and the function save has to exist.
|
||||||
|
// you have to make sure the callback is called with the settings object as first param!
|
||||||
|
function save(callback) {
|
||||||
|
// example: select elements with class=value and build settings object
|
||||||
|
var obj = {};
|
||||||
|
$('.value').each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
if ($this.attr('type') == 'checkbox') {
|
||||||
|
obj[$this.attr('id')] = $this.prop('checked');
|
||||||
|
} else {
|
||||||
|
obj[$this.attr('id')] = $this.val();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($('#secure').prop('checked') && (!$('#certPrivate').val() || !$('#certPublic').val())) {
|
||||||
|
showMessage(_('Set certificates or load it first in the system settings (right top).'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(obj);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- you have to put your config page in a div with id adapter-container -->
|
||||||
|
<div id="adapter-container">
|
||||||
|
|
||||||
|
<table><tr><td><img src="simple-api.png"></td><td><h3 class="translate">simpleAPI adapter settings</h3></td></tr></table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><td><label for="webInstance" class="translate">Extend WEB adapter:</label></td><td><select class="value" id="webInstance">
|
||||||
|
<option value="" class="translate">none</option>
|
||||||
|
<option value="*" class="translate">all</option>
|
||||||
|
</select></td></tr>
|
||||||
|
<tr class="no-if-extend"><td><label for="bind" class="translate">IP:</label></td><td> <select class="value" id="bind"></select></td></tr>
|
||||||
|
<tr class="no-if-extend"><td><label for="port" class="translate">Port:</label></td><td> <input class="value" id="port" size="5" maxlength="5"/></td></tr>
|
||||||
|
<tr class="no-if-extend"><td><label for="secure" class="translate">Secure(HTTPS):</label></td><td> <input class="value" id="secure" type="checkbox" /></td></tr>
|
||||||
|
<tr class="no-if-extend" id="_certPublic">
|
||||||
|
<td><label for="certPublic" class="translate">Public certificate:</label></td>
|
||||||
|
<td><select id="certPublic" class="value"></select></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="no-if-extend" id="_certPrivate">
|
||||||
|
<td><label for="certPrivate" class="translate">Private certificate:</label></td>
|
||||||
|
<td><select id="certPrivate" class="value"></select></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="no-if-extend" id="_certChained">
|
||||||
|
<td><label for="certChained" class="translate">Chained certificate:</label></td>
|
||||||
|
<td><select id="certChained" class="value"></select></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="no-if-extend"><td><label for="auth" class="translate">Authentication:</label></td><td><input class="value" id="auth" type="checkbox" /></td></tr>
|
||||||
|
<tr class="no-if-extend defaultUser"><td><label for="defaultUser" class="translate">Run as:</label></td><td><select class="value" id="defaultUser"></select></td></tr>
|
||||||
|
<tr class="no-if-extend defaultUser"><td><label for="onlyAllowWhenUserIsOwner" class="translate">Allow only when User is Owner:</label></td><td><input class="value" id="onlyAllowWhenUserIsOwner" type="checkbox" /></td></tr>
|
||||||
|
<tr class="no-if-extend"><td colspan="2"> </td></tr>
|
||||||
|
<tr class="no-if-extend le-settings"><td colspan="2"><h3 class="translate">Let's Encrypt settings</h3></tr>
|
||||||
|
<tr class="no-if-extend le-settings"><td><label for="leEnabled" class="translate">Use Lets Encrypt certificates:</label></td><td><input class="value" id="leEnabled" type="checkbox" /></td></tr>
|
||||||
|
<tr class="no-if-extend le-settings le-sub-settings"><td><label for="leUpdate" class="translate">Use this instance for automatic update:</label></td><td><input class="value" id="leUpdate" type="checkbox" /></td></tr>
|
||||||
|
<tr class="no-if-extend le-settings le-sub-settings le-sub-settings-update"><td><label for="lePort" class="translate">Port to check the domain:</label></td><td><input class="value number" id="lePort" type="number" size="5" maxlength="5" /></td></tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</html>
|
BIN
admin/simple-api.png
Normal file
BIN
admin/simple-api.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
43
admin/words.js
Normal file
43
admin/words.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
systemDictionary = {
|
||||||
|
"simpleAPI adapter settings": {
|
||||||
|
"de": "simpleAPI adapter settings",
|
||||||
|
"ru": "simpleAPI adapter settings"
|
||||||
|
},
|
||||||
|
"Run as:": {"de": "Laufen unter Anwender:", "ru": "Запустить от пользователя:"},
|
||||||
|
"Allow only when User is Owner:": {"de": "Nue erlauben wenn Anwender auch Besitzer ist:", "ru": "Allow only when User is Owner:"},
|
||||||
|
"IP:": {"de": "IP:", "ru": "IP:"},
|
||||||
|
"Port:": {"de": "Port:", "ru": "Порт:"},
|
||||||
|
"Secure(HTTPS):": {"de": "Verschlüsselung(HTTPS):", "ru": "Шифрование(HTTPS):"},
|
||||||
|
"Authentication:": {"de": "Authentifikation:", "ru": "Аутентификация:"},
|
||||||
|
"Public certificate:": {"en": "Public certificate:", "de": "Publikzertifikat:", "ru": "'Public' сертификат:"},
|
||||||
|
"Private certificate:": {"en": "Private certificate:", "de": "Privatzertifikat:", "ru": "'Private' сертификат:"},
|
||||||
|
"Chained certificate:": {"en": "Chained certificate:", "de": "Kettenzertifikat:", "ru": "'Chained' сертификат:"},
|
||||||
|
"Extend WEB adapter:": {"en": "Extend WEB adapter:", "de": "Erweitere WEB Adapter:", "ru": "Подключить к WEB драйверу:"},
|
||||||
|
"all": {"en": "all", "de": "alle", "ru": "все"},
|
||||||
|
"Listen on all IPs": {"en": "Listen on all IPs", "de": "Alle IPs zulassen", "ru": "Открыть для всех IP адресов"},
|
||||||
|
"Let's Encrypt settings": {
|
||||||
|
"en": "Let's Encrypt settings",
|
||||||
|
"de": "Einstellungen Let's Encrypt",
|
||||||
|
"ru": "Настройкт Let's Encrypt"
|
||||||
|
},
|
||||||
|
"Use Lets Encrypt certificates:": {
|
||||||
|
"en": "Use Let's Encrypt certificates:",
|
||||||
|
"de": "Benutzen Let's Encrypt Zertifikate:",
|
||||||
|
"ru": "Использовать сертификаты Let's Encrypt:"
|
||||||
|
},
|
||||||
|
"Use this instance for automatic update:": {
|
||||||
|
"en": "Use this instance for automatic update:",
|
||||||
|
"de": "Benutze diese Instanz für automatische Updates:",
|
||||||
|
"ru": "Обновлять сертификаты в этом драйвере:"
|
||||||
|
},
|
||||||
|
"Port to check the domain:": {
|
||||||
|
"en": "Port to check the domain:",
|
||||||
|
"de": "Port um die Domain zu prüfen:",
|
||||||
|
"ru": "Порт для проверки доменного имени:"
|
||||||
|
},
|
||||||
|
"Set certificates or load it first in the system settings (right top).": {
|
||||||
|
"en": "Set certificates or load it first in the system settings (right top).",
|
||||||
|
"de": "Setze Zertificate oder lade die erst unter System/Einstellungen (oben rechts).",
|
||||||
|
"ru": "Нужно выбрать сертификаты или сначала загрузить их в системных настройках (вверху справа)."
|
||||||
|
}
|
||||||
|
};
|
25
appveyor.yml
Normal file
25
appveyor.yml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
version: 'test-{build}'
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- nodejs_version: '4'
|
||||||
|
- nodejs_version: '6'
|
||||||
|
- nodejs_version: '8'
|
||||||
|
- nodejs_version: '10'
|
||||||
|
platform:
|
||||||
|
- x86
|
||||||
|
- x64
|
||||||
|
clone_folder: 'c:\projects\%APPVEYOR_PROJECT_NAME%'
|
||||||
|
install:
|
||||||
|
- ps: 'Install-Product node $env:nodejs_version $env:platform'
|
||||||
|
- ps: '$NpmVersion = (npm -v).Substring(0,1)'
|
||||||
|
- ps: 'if($NpmVersion -eq 5) { npm install -g npm@5 }'
|
||||||
|
- ps: npm --version
|
||||||
|
- npm install
|
||||||
|
- npm install winston@2.3.1
|
||||||
|
- 'npm install https://git.spacen.net/yunkong2/yunkong2.js-controller/tarball/master --production'
|
||||||
|
test_script:
|
||||||
|
- echo %cd%
|
||||||
|
- node --version
|
||||||
|
- npm --version
|
||||||
|
- npm test
|
||||||
|
build: 'off'
|
401
gulpfile.js
Normal file
401
gulpfile.js
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var gulp = require('gulp');
|
||||||
|
var fs = require('fs');
|
||||||
|
var pkg = require('./package.json');
|
||||||
|
var iopackage = require('./io-package.json');
|
||||||
|
var version = (pkg && pkg.version) ? pkg.version : iopackage.common.version;
|
||||||
|
/*var appName = getAppName();
|
||||||
|
|
||||||
|
function getAppName() {
|
||||||
|
var parts = __dirname.replace(/\\/g, '/').split('/');
|
||||||
|
return parts[parts.length - 1].split('.')[0].toLowerCase();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const fileName = 'words.js';
|
||||||
|
var languages = {
|
||||||
|
en: {},
|
||||||
|
de: {},
|
||||||
|
ru: {},
|
||||||
|
pt: {},
|
||||||
|
nl: {},
|
||||||
|
fr: {},
|
||||||
|
it: {},
|
||||||
|
es: {},
|
||||||
|
pl: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
function lang2data(lang, isFlat) {
|
||||||
|
var str = isFlat ? '' : '{\n';
|
||||||
|
var count = 0;
|
||||||
|
for (var w in lang) {
|
||||||
|
if (lang.hasOwnProperty(w)) {
|
||||||
|
count++;
|
||||||
|
if (isFlat) {
|
||||||
|
str += (lang[w] === '' ? (isFlat[w] || w) : lang[w]) + '\n';
|
||||||
|
} else {
|
||||||
|
var key = ' "' + w.replace(/"/g, '\\"') + '": ';
|
||||||
|
str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!count) return isFlat ? '' : '{\n}';
|
||||||
|
if (isFlat) {
|
||||||
|
return str;
|
||||||
|
} else {
|
||||||
|
return str.substring(0, str.length - 2) + '\n}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readWordJs(src) {
|
||||||
|
try {
|
||||||
|
var words;
|
||||||
|
if (fs.existsSync(src + 'js/' + fileName)) {
|
||||||
|
words = fs.readFileSync(src + 'js/' + fileName).toString();
|
||||||
|
} else {
|
||||||
|
words = fs.readFileSync(src + fileName).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines = words.split(/\r\n|\r|\n/g);
|
||||||
|
var i = 0;
|
||||||
|
while (!lines[i].match(/^systemDictionary = {/)) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
lines.splice(0, i);
|
||||||
|
|
||||||
|
// remove last empty lines
|
||||||
|
i = lines.length - 1;
|
||||||
|
while (!lines[i]) {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if (i < lines.length - 1) {
|
||||||
|
lines.splice(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines[0] = lines[0].replace('systemDictionary = ', '');
|
||||||
|
lines[lines.length - 1] = lines[lines.length - 1].trim().replace(/};$/, '}');
|
||||||
|
words = lines.join('\n');
|
||||||
|
var resultFunc = new Function('return ' + words + ';');
|
||||||
|
|
||||||
|
return resultFunc();
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function padRight(text, totalLength) {
|
||||||
|
return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : '');
|
||||||
|
}
|
||||||
|
function writeWordJs(data, src) {
|
||||||
|
var text = '// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n\n';
|
||||||
|
text += '/*global systemDictionary:true */\n';
|
||||||
|
text += '\'use strict\';\n\n';
|
||||||
|
|
||||||
|
text += 'systemDictionary = {\n';
|
||||||
|
for (var word in data) {
|
||||||
|
if (data.hasOwnProperty(word)) {
|
||||||
|
text += ' ' + padRight('"' + word.replace(/"/g, '\\"') + '": {', 50);
|
||||||
|
var line = '';
|
||||||
|
for (var lang in data[word]) {
|
||||||
|
if (data[word].hasOwnProperty(lang)) {
|
||||||
|
line += '"' + lang + '": "' + padRight(data[word][lang].replace(/"/g, '\\"') + '",', 50) + ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line) {
|
||||||
|
line = line.trim();
|
||||||
|
line = line.substring(0, line.length - 1);
|
||||||
|
}
|
||||||
|
text += line + '},\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text = text.replace(/},\n$/, '}\n');
|
||||||
|
text += '};';
|
||||||
|
|
||||||
|
if (fs.existsSync(src + 'js/' + fileName)) {
|
||||||
|
fs.writeFileSync(src + 'js/' + fileName, text);
|
||||||
|
} else {
|
||||||
|
fs.writeFileSync(src + '' + fileName, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const EMPTY = '';
|
||||||
|
|
||||||
|
function words2languages(src) {
|
||||||
|
var langs = Object.assign({}, languages);
|
||||||
|
var data = readWordJs(src);
|
||||||
|
if (data) {
|
||||||
|
for (var word in data) {
|
||||||
|
if (data.hasOwnProperty(word)) {
|
||||||
|
for (var lang in data[word]) {
|
||||||
|
if (data[word].hasOwnProperty(lang)) {
|
||||||
|
langs[lang][word] = data[word][lang];
|
||||||
|
// pre-fill all other languages
|
||||||
|
for (var j in langs) {
|
||||||
|
if (langs.hasOwnProperty(j)) {
|
||||||
|
langs[j][word] = langs[j][word] || EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(src + 'i18n/')) {
|
||||||
|
fs.mkdirSync(src + 'i18n/');
|
||||||
|
}
|
||||||
|
for (var l in langs) {
|
||||||
|
if (!langs.hasOwnProperty(l)) continue;
|
||||||
|
var keys = Object.keys(langs[l]);
|
||||||
|
//keys.sort();
|
||||||
|
var obj = {};
|
||||||
|
for (var k = 0; k < keys.length; k++) {
|
||||||
|
obj[keys[k]] = langs[l][keys[k]];
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(src + 'i18n/' + l)) {
|
||||||
|
fs.mkdirSync(src + 'i18n/' + l);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(src + 'i18n/' + l + '/translations.json', lang2data(obj));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('Cannot read or parse ' + fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function words2languagesFlat(src) {
|
||||||
|
var langs = Object.assign({}, languages);
|
||||||
|
var data = readWordJs(src);
|
||||||
|
if (data) {
|
||||||
|
for (var word in data) {
|
||||||
|
if (data.hasOwnProperty(word)) {
|
||||||
|
for (var lang in data[word]) {
|
||||||
|
if (data[word].hasOwnProperty(lang)) {
|
||||||
|
langs[lang][word] = data[word][lang];
|
||||||
|
// pre-fill all other languages
|
||||||
|
for (var j in langs) {
|
||||||
|
if (langs.hasOwnProperty(j)) {
|
||||||
|
langs[j][word] = langs[j][word] || EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var keys = Object.keys(langs.en);
|
||||||
|
//keys.sort();
|
||||||
|
for (var l in langs) {
|
||||||
|
if (!langs.hasOwnProperty(l)) continue;
|
||||||
|
var obj = {};
|
||||||
|
for (var k = 0; k < keys.length; k++) {
|
||||||
|
obj[keys[k]] = langs[l][keys[k]];
|
||||||
|
}
|
||||||
|
langs[l] = obj;
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(src + 'i18n/')) {
|
||||||
|
fs.mkdirSync(src + 'i18n/');
|
||||||
|
}
|
||||||
|
for (var ll in langs) {
|
||||||
|
if (!langs.hasOwnProperty(ll)) continue;
|
||||||
|
if (!fs.existsSync(src + 'i18n/' + ll)) {
|
||||||
|
fs.mkdirSync(src + 'i18n/' + ll);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(src + 'i18n/' + ll + '/flat.txt', lang2data(langs[ll], langs.en));
|
||||||
|
}
|
||||||
|
fs.writeFileSync(src + 'i18n/flat.txt', keys.join('\n'));
|
||||||
|
} else {
|
||||||
|
console.error('Cannot read or parse ' + fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function languagesFlat2words(src) {
|
||||||
|
var dirs = fs.readdirSync(src + 'i18n/');
|
||||||
|
var langs = {};
|
||||||
|
var bigOne = {};
|
||||||
|
var order = Object.keys(languages);
|
||||||
|
dirs.sort(function (a, b) {
|
||||||
|
var posA = order.indexOf(a);
|
||||||
|
var posB = order.indexOf(b);
|
||||||
|
if (posA === -1 && posB === -1) {
|
||||||
|
if (a > b) return 1;
|
||||||
|
if (a < b) return -1;
|
||||||
|
return 0;
|
||||||
|
} else if (posA === -1) {
|
||||||
|
return -1;
|
||||||
|
} else if (posB === -1) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
if (posA > posB) return 1;
|
||||||
|
if (posA < posB) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var keys = fs.readFileSync(src + 'i18n/flat.txt').toString().split('\n');
|
||||||
|
|
||||||
|
for (var l = 0; l < dirs.length; l++) {
|
||||||
|
if (dirs[l] === 'flat.txt') continue;
|
||||||
|
var lang = dirs[l];
|
||||||
|
var values = fs.readFileSync(src + 'i18n/' + lang + '/flat.txt').toString().split('\n');
|
||||||
|
langs[lang] = {};
|
||||||
|
keys.forEach(function (word, i) {
|
||||||
|
langs[lang][word] = values[i].replace(/<\/ i>/g, '</i>').replace(/<\/ b>/g, '</b>').replace(/<\/ span>/g, '</span>').replace(/% s/g, ' %s');
|
||||||
|
});
|
||||||
|
|
||||||
|
var words = langs[lang];
|
||||||
|
for (var word in words) {
|
||||||
|
if (words.hasOwnProperty(word)) {
|
||||||
|
bigOne[word] = bigOne[word] || {};
|
||||||
|
if (words[word] !== EMPTY) {
|
||||||
|
bigOne[word][lang] = words[word];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// read actual words.js
|
||||||
|
var aWords = readWordJs();
|
||||||
|
|
||||||
|
var temporaryIgnore = ['pt', 'fr', 'nl', 'flat.txt'];
|
||||||
|
if (aWords) {
|
||||||
|
// Merge words together
|
||||||
|
for (var w in aWords) {
|
||||||
|
if (aWords.hasOwnProperty(w)) {
|
||||||
|
if (!bigOne[w]) {
|
||||||
|
console.warn('Take from actual words.js: ' + w);
|
||||||
|
bigOne[w] = aWords[w]
|
||||||
|
}
|
||||||
|
dirs.forEach(function (lang) {
|
||||||
|
if (temporaryIgnore.indexOf(lang) !== -1) return;
|
||||||
|
if (!bigOne[w][lang]) {
|
||||||
|
console.warn('Missing "' + lang + '": ' + w);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
writeWordJs(bigOne, src);
|
||||||
|
}
|
||||||
|
function languages2words(src) {
|
||||||
|
var dirs = fs.readdirSync(src + 'i18n/');
|
||||||
|
var langs = {};
|
||||||
|
var bigOne = {};
|
||||||
|
var order = Object.keys(languages);
|
||||||
|
dirs.sort(function (a, b) {
|
||||||
|
var posA = order.indexOf(a);
|
||||||
|
var posB = order.indexOf(b);
|
||||||
|
if (posA === -1 && posB === -1) {
|
||||||
|
if (a > b) return 1;
|
||||||
|
if (a < b) return -1;
|
||||||
|
return 0;
|
||||||
|
} else if (posA === -1) {
|
||||||
|
return -1;
|
||||||
|
} else if (posB === -1) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
if (posA > posB) return 1;
|
||||||
|
if (posA < posB) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (var l = 0; l < dirs.length; l++) {
|
||||||
|
if (dirs[l] === 'flat.txt') continue;
|
||||||
|
var lang = dirs[l];
|
||||||
|
langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString();
|
||||||
|
langs[lang] = JSON.parse(langs[lang]);
|
||||||
|
var words = langs[lang];
|
||||||
|
for (var word in words) {
|
||||||
|
if (words.hasOwnProperty(word)) {
|
||||||
|
bigOne[word] = bigOne[word] || {};
|
||||||
|
if (words[word] !== EMPTY) {
|
||||||
|
bigOne[word][lang] = words[word];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// read actual words.js
|
||||||
|
var aWords = readWordJs();
|
||||||
|
|
||||||
|
var temporaryIgnore = ['pt', 'fr', 'nl', 'it'];
|
||||||
|
if (aWords) {
|
||||||
|
// Merge words together
|
||||||
|
for (var w in aWords) {
|
||||||
|
if (aWords.hasOwnProperty(w)) {
|
||||||
|
if (!bigOne[w]) {
|
||||||
|
console.warn('Take from actual words.js: ' + w);
|
||||||
|
bigOne[w] = aWords[w]
|
||||||
|
}
|
||||||
|
dirs.forEach(function (lang) {
|
||||||
|
if (temporaryIgnore.indexOf(lang) !== -1) return;
|
||||||
|
if (!bigOne[w][lang]) {
|
||||||
|
console.warn('Missing "' + lang + '": ' + w);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
writeWordJs(bigOne, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('adminWords2languages', function (done) {
|
||||||
|
words2languages('./admin/');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('adminWords2languagesFlat', function (done) {
|
||||||
|
words2languagesFlat('./admin/');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('adminLanguagesFlat2words', function (done) {
|
||||||
|
languagesFlat2words('./admin/');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('adminLanguages2words', function (done) {
|
||||||
|
languages2words('./admin/');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
gulp.task('updatePackages', function (done) {
|
||||||
|
iopackage.common.version = pkg.version;
|
||||||
|
iopackage.common.news = iopackage.common.news || {};
|
||||||
|
if (!iopackage.common.news[pkg.version]) {
|
||||||
|
var news = iopackage.common.news;
|
||||||
|
var newNews = {};
|
||||||
|
|
||||||
|
newNews[pkg.version] = {
|
||||||
|
en: 'news',
|
||||||
|
de: 'neues',
|
||||||
|
ru: 'новое'
|
||||||
|
};
|
||||||
|
iopackage.common.news = Object.assign(newNews, news);
|
||||||
|
}
|
||||||
|
fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('updateReadme', function (done) {
|
||||||
|
var readme = fs.readFileSync('README.md').toString();
|
||||||
|
var pos = readme.indexOf('## Changelog\n');
|
||||||
|
if (pos !== -1) {
|
||||||
|
var readmeStart = readme.substring(0, pos + '## Changelog\n'.length);
|
||||||
|
var readmeEnd = readme.substring(pos + '## Changelog\n'.length);
|
||||||
|
|
||||||
|
if (readme.indexOf(version) === -1) {
|
||||||
|
var timestamp = new Date();
|
||||||
|
var date = timestamp.getFullYear() + '-' +
|
||||||
|
('0' + (timestamp.getMonth() + 1).toString(10)).slice(-2) + '-' +
|
||||||
|
('0' + (timestamp.getDate()).toString(10)).slice(-2);
|
||||||
|
|
||||||
|
var news = '';
|
||||||
|
if (iopackage.common.news && iopackage.common.news[pkg.version]) {
|
||||||
|
news += '* ' + iopackage.common.news[pkg.version].en;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync('README.md', readmeStart + '### ' + version + ' (' + date + ')\n' + (news ? news + '\n\n' : '\n') + readmeEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('default', ['updatePackages', 'updateReadme']);
|
BIN
img/favicon.ico
Normal file
BIN
img/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
106
io-package.json
Normal file
106
io-package.json
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
"common": {
|
||||||
|
"name": "simple-api",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"news": {
|
||||||
|
"2.0.0": {
|
||||||
|
"en": "BREAKING CHANGE: getBulk is returning data in a different structure",
|
||||||
|
"de": "BREAKING CHANGE: getBulk gibt Daten in einer anderen Struktur zurück",
|
||||||
|
"ru": "BREAKING CHANGE: getBulk возвращает данные в другой структуре",
|
||||||
|
"pt": "BREAKING CHANGE: o getBulk está retornando dados em uma estrutura diferente",
|
||||||
|
"nl": "BREAKING CHANGE: getBulk retourneert gegevens in een andere structuur",
|
||||||
|
"fr": "BREAKING CHANGE: getBulk renvoie des données dans une structure différente",
|
||||||
|
"it": "BREAKING CHANGE: getBulk restituisce i dati in una struttura diversa",
|
||||||
|
"es": "BREAKING CHANGE: getBulk está devolviendo datos en una estructura diferente",
|
||||||
|
"pl": "ZMIANA ZMIAN: getBulk zwraca dane w innej strukturze"
|
||||||
|
},
|
||||||
|
"1.6.3": {
|
||||||
|
"en": "Return used character encoding (UTF-8)",
|
||||||
|
"de": "Zeichencodierung zurückgegeben (UTF-8)",
|
||||||
|
"ru": "Возвращаемое кодирование символов (UTF-8)",
|
||||||
|
"pt": "Retornar a codificação de caracteres usados (UTF-8)",
|
||||||
|
"nl": "Gebruikte tekencodering retourneren (UTF-8)",
|
||||||
|
"fr": "Renvoie le codage de caractères utilisé (UTF-8)",
|
||||||
|
"it": "Restituisci codifica caratteri usati (UTF-8)",
|
||||||
|
"es": "Devuelve la codificación de caracteres usados (UTF-8)",
|
||||||
|
"pl": "Zwróć używane kodowanie znaków (UTF-8)"
|
||||||
|
},
|
||||||
|
"1.6.2": {
|
||||||
|
"en": "Fix decoding problems",
|
||||||
|
"de": "Dekodierungsprobleme behoben",
|
||||||
|
"ru": "Fix decoding problems"
|
||||||
|
},
|
||||||
|
"1.6.1": {
|
||||||
|
"en": "Fix statuscode for setBulk and optimize permission errors",
|
||||||
|
"de": "Statuscode für setBulk korrigiert und Rechte-Fehler optimiert",
|
||||||
|
"ru": "Fix statuscode for setBulk and optimize permission errors"
|
||||||
|
},
|
||||||
|
"1.6.0": {
|
||||||
|
"en": "Optimize Permission handling and add possibility to only allow access to states where user is also owner (needs js-contrioller 1.1.1!), fix handling of url-encoded values",
|
||||||
|
"de": "Berechtigungsbehandlung optimiert und Möglichkeit eingebaut nur den Zugriff auf Zustände zu erlauben wo der Benutzer auch Besitzer ist (benötigt js-controller 1.1.1), Behandlung von URL-kodierten Werten korrigiert",
|
||||||
|
"ru": "Optimize Permission handling and add possibility to only allow access to states where user is also owner (needs js-contrioller 1.1.1!), fix handling of url-encoded values"
|
||||||
|
},
|
||||||
|
"1.5.1": {
|
||||||
|
"en": "Add new POST method setValueFromBody",
|
||||||
|
"de": "Neue POST-Methode setValueFromBody hinzugefügt",
|
||||||
|
"ru": "Add new POST method setValueFromBody"
|
||||||
|
},
|
||||||
|
"1.4.0": {
|
||||||
|
"en": "can be used as web-extension",
|
||||||
|
"de": "Kann als Web-Extension benutzt werden",
|
||||||
|
"ru": "Может использоватся, как Web-плагин"
|
||||||
|
},
|
||||||
|
"1.3.0": {
|
||||||
|
"en": "сompatible only with new admin",
|
||||||
|
"de": "Nur mit neuem Admin kompatibel",
|
||||||
|
"ru": "Совместимо только с новым админ-драйвером"
|
||||||
|
},
|
||||||
|
"1.2.0": {
|
||||||
|
"en": "support of letsencrypt certificates",
|
||||||
|
"de": "Unterstützung von letsencrypt Zertifikaten",
|
||||||
|
"ru": "Поддержка letsencrypt сертификатов"
|
||||||
|
},
|
||||||
|
"1.1.1": {
|
||||||
|
"en": "support of chained certificates",
|
||||||
|
"de": "support of chained certificates",
|
||||||
|
"ru": "support of chained certificates"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "simpleAPI Adapter",
|
||||||
|
"desc": "This adapter allows to read and write yunkong2 objects and state with web RESTful API",
|
||||||
|
"authors": [
|
||||||
|
"bluefox <dogafox@gmail.com>",
|
||||||
|
"Apollon77 <ingo@fischer-ka.de>"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"platform": "Javascript/Node.js",
|
||||||
|
"mode": "daemon",
|
||||||
|
"loglevel": "info",
|
||||||
|
"icon": "simple-api.png",
|
||||||
|
"webExtension": "lib/simpleapi.js",
|
||||||
|
"readme": "https://git.spacen.net/yunkong2/yunkong2.simple-api/blob/master/README.md",
|
||||||
|
"keywords": ["web", "simpleAPI", "RESTful", "communication"],
|
||||||
|
"enabled": true,
|
||||||
|
"extIcon": "https://git.spacen.net/yunkong2/yunkong2.simple-api/master/admin/simple-api.png",
|
||||||
|
"type": "communication",
|
||||||
|
"stopBeforeUpdate": true,
|
||||||
|
"localLink": "%protocol%://%ip%:%port%/get/system.adapter.simple-api.%instance%.uptime?prettyPrint",
|
||||||
|
"dependencies": [{"js-controller": ">=0.15.0"}]
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"port": 8087,
|
||||||
|
"auth": false,
|
||||||
|
"secure": false,
|
||||||
|
"bind": "0.0.0.0",
|
||||||
|
"certPublic": "",
|
||||||
|
"certPrivate": "",
|
||||||
|
"certChained": "",
|
||||||
|
"defaultUser": "admin",
|
||||||
|
"onlyAllowWhenUserIsOwner": false,
|
||||||
|
"webInstance": "",
|
||||||
|
|
||||||
|
"leEnabled": false,
|
||||||
|
"leUpdate": false,
|
||||||
|
"leCheckPort": 80
|
||||||
|
}
|
||||||
|
}
|
905
lib/simpleapi.js
Normal file
905
lib/simpleapi.js
Normal file
@ -0,0 +1,905 @@
|
|||||||
|
/* 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;
|
83
lib/utils.js
Normal file
83
lib/utils.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
let controllerDir;
|
||||||
|
let appName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns application name
|
||||||
|
*
|
||||||
|
* The name of the application can be different and this function finds it out.
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function getAppName() {
|
||||||
|
const parts = __dirname.replace(/\\/g, '/').split('/');
|
||||||
|
return parts[parts.length - 2].split('.')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* looks for js-controller home folder
|
||||||
|
*
|
||||||
|
* @param {boolean} isInstall
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function getControllerDir(isInstall) {
|
||||||
|
// Find the js-controller location
|
||||||
|
const possibilities = [
|
||||||
|
'yunkong2.js-controller',
|
||||||
|
'yunkong2.js-controller',
|
||||||
|
];
|
||||||
|
/** @type {string} */
|
||||||
|
let controllerPath;
|
||||||
|
for (const pkg of possibilities) {
|
||||||
|
try {
|
||||||
|
const possiblePath = require.resolve(pkg);
|
||||||
|
if (fs.existsSync(possiblePath)) {
|
||||||
|
controllerPath = possiblePath;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) { /* not found */ }
|
||||||
|
}
|
||||||
|
if (controllerPath == null) {
|
||||||
|
if (!isInstall) {
|
||||||
|
console.log('Cannot find js-controller');
|
||||||
|
process.exit(10);
|
||||||
|
} else {
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we found the controller
|
||||||
|
return path.dirname(controllerPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reads controller base settings
|
||||||
|
*
|
||||||
|
* @alias getConfig
|
||||||
|
* @returns {object}
|
||||||
|
*/
|
||||||
|
function getConfig() {
|
||||||
|
let configPath;
|
||||||
|
if (fs.existsSync(
|
||||||
|
configPath = path.join(controllerDir, 'conf', appName + '.json')
|
||||||
|
)) {
|
||||||
|
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||||
|
} else if (fs.existsSync(
|
||||||
|
configPath = path.join(controllerDir, 'conf', + appName.toLowerCase() + '.json')
|
||||||
|
)) {
|
||||||
|
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||||
|
} else {
|
||||||
|
throw new Error('Cannot find ' + controllerDir + '/conf/' + appName + '.json');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appName = getAppName();
|
||||||
|
controllerDir = getControllerDir(typeof process !== 'undefined' && process.argv && process.argv.indexOf('--install') !== -1);
|
||||||
|
const adapter = require(path.join(controllerDir, 'lib/adapter.js'));
|
||||||
|
|
||||||
|
exports.controllerDir = controllerDir;
|
||||||
|
exports.getConfig = getConfig;
|
||||||
|
exports.Adapter = adapter;
|
||||||
|
exports.appName = appName;
|
133
main.js
Normal file
133
main.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/* jshint -W097 */// jshint strict:false
|
||||||
|
/*jslint node: true */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var utils = require(__dirname + '/lib/utils'); // Get common adapter utils
|
||||||
|
var SimpleAPI = require(__dirname + '/lib/simpleapi.js');
|
||||||
|
var LE = require(utils.controllerDir + '/lib/letsencrypt.js');
|
||||||
|
|
||||||
|
var webServer = null;
|
||||||
|
var fs = null;
|
||||||
|
|
||||||
|
var adapter = new utils.Adapter({
|
||||||
|
name: 'simple-api',
|
||||||
|
stateChange: function (id, state) {
|
||||||
|
if (webServer && webServer.api) {
|
||||||
|
webServer.api.stateChange(id, state);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
objectChange: function (id, obj) {
|
||||||
|
if (webServer && webServer.api) {
|
||||||
|
webServer.api.objectChange(id, obj);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unload: function (callback) {
|
||||||
|
try {
|
||||||
|
adapter.log.info('terminating http' + (webServer.settings.secure ? 's' : '') + ' server on port ' + webServer.settings.port);
|
||||||
|
//if (webServer.api) webServer.api.close();
|
||||||
|
|
||||||
|
callback();
|
||||||
|
} catch (e) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ready: function () {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
if (adapter.config.webInstance) {
|
||||||
|
console.log('Adapter runs as a part of web service');
|
||||||
|
adapter.log.warn('Adapter runs as a part of web service');
|
||||||
|
adapter.setForeignState('system.adapter.' + adapter.namespace + '.alive', false, true, function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
process.exit();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adapter.config.secure) {
|
||||||
|
// subscribe on changes of permissions
|
||||||
|
adapter.subscribeForeignObjects('system.group.*');
|
||||||
|
adapter.subscribeForeignObjects('system.user.*');
|
||||||
|
|
||||||
|
// Load certificates
|
||||||
|
adapter.getCertificates(function (err, certificates, leConfig) {
|
||||||
|
adapter.config.certificates = certificates;
|
||||||
|
adapter.config.leConfig = leConfig;
|
||||||
|
webServer = initWebServer(adapter.config);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
webServer = initWebServer(adapter.config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestProcessor(req, res) {
|
||||||
|
if (req.url.indexOf('favicon.ico') !== -1) {
|
||||||
|
if (!fs) fs = require('fs');
|
||||||
|
var stat = fs.statSync(__dirname + '/img/favicon.ico');
|
||||||
|
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': 'image/x-icon',
|
||||||
|
'Content-Length': stat.size
|
||||||
|
});
|
||||||
|
|
||||||
|
var readStream = fs.createReadStream(__dirname + '/img/favicon.ico');
|
||||||
|
// We replaced all the event handlers with a simple call to readStream.pipe()
|
||||||
|
readStream.pipe(res);
|
||||||
|
} else {
|
||||||
|
webServer.api.restApi(req, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//settings: {
|
||||||
|
// "port": 8080,
|
||||||
|
// "auth": false,
|
||||||
|
// "secure": false,
|
||||||
|
// "bind": "0.0.0.0", // "::"
|
||||||
|
// "cache": false
|
||||||
|
//}
|
||||||
|
function initWebServer(settings) {
|
||||||
|
|
||||||
|
var server = {
|
||||||
|
app: null,
|
||||||
|
server: null,
|
||||||
|
api: null,
|
||||||
|
io: null,
|
||||||
|
settings: settings
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.port = parseInt(settings.port, 10);
|
||||||
|
|
||||||
|
if (settings.port) {
|
||||||
|
|
||||||
|
if (settings.secure && !adapter.config.certificates) return null;
|
||||||
|
|
||||||
|
server.server = LE.createServer(requestProcessor, settings, adapter.config.certificates, adapter.config.leConfig, adapter.log);
|
||||||
|
server.server.__server = server;
|
||||||
|
} else {
|
||||||
|
adapter.log.error('port missing');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server.server) {
|
||||||
|
adapter.getPort(settings.port, function (port) {
|
||||||
|
if (port !== settings.port && !adapter.config.findNextPort) {
|
||||||
|
adapter.log.error('port ' + settings.port + ' already in use');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
server.server.listen(port);
|
||||||
|
adapter.log.info('http' + (settings.secure ? 's' : '') + ' server listening on port ' + port);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
server.api = new SimpleAPI(server.server, settings, adapter);
|
||||||
|
|
||||||
|
if (server.server) {
|
||||||
|
return server;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
39
package.json
Normal file
39
package.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"name": "yunkong2.simple-api",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"description": "RESTful interface for yunkong2.",
|
||||||
|
"author": {
|
||||||
|
"name": "bluefox",
|
||||||
|
"email": "dogafox@gmail.com"
|
||||||
|
},
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Apollon77",
|
||||||
|
"email": "ingo@fischer-ka.de"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"homepage": "https://git.spacen.net/yunkong2/yunkong2.simple-api",
|
||||||
|
"keywords": [
|
||||||
|
"yunkong2",
|
||||||
|
"web"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.spacen.net/yunkong2/yunkong2.simple-api"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"gulp": "^3.9.1",
|
||||||
|
"mocha": "^5.0.1",
|
||||||
|
"chai": "^4.1.2",
|
||||||
|
"request": "^2.83.0"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://git.spacen.net/yunkong2/yunkong2.simple-api/issues"
|
||||||
|
},
|
||||||
|
"main": "main.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "node node_modules/mocha/bin/mocha --exit"
|
||||||
|
},
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
728
test/lib/setup.js
Normal file
728
test/lib/setup.js
Normal file
@ -0,0 +1,728 @@
|
|||||||
|
/* jshint -W097 */// jshint strict:false
|
||||||
|
/*jslint node: true */
|
||||||
|
// check if tmp directory exists
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var child_process = require('child_process');
|
||||||
|
var rootDir = path.normalize(__dirname + '/../../');
|
||||||
|
var pkg = require(rootDir + 'package.json');
|
||||||
|
var debug = typeof v8debug === 'object';
|
||||||
|
pkg.main = pkg.main || 'main.js';
|
||||||
|
|
||||||
|
var adapterName = path.normalize(rootDir).replace(/\\/g, '/').split('/');
|
||||||
|
adapterName = adapterName[adapterName.length - 2];
|
||||||
|
var adapterStarted = false;
|
||||||
|
|
||||||
|
function getAppName() {
|
||||||
|
var parts = __dirname.replace(/\\/g, '/').split('/');
|
||||||
|
return parts[parts.length - 3].split('.')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var appName = getAppName().toLowerCase();
|
||||||
|
|
||||||
|
var objects;
|
||||||
|
var states;
|
||||||
|
|
||||||
|
var pid = null;
|
||||||
|
|
||||||
|
function copyFileSync(source, target) {
|
||||||
|
|
||||||
|
var targetFile = target;
|
||||||
|
|
||||||
|
//if target is a directory a new file with the same name will be created
|
||||||
|
if (fs.existsSync(target)) {
|
||||||
|
if ( fs.lstatSync( target ).isDirectory() ) {
|
||||||
|
targetFile = path.join(target, path.basename(source));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.writeFileSync(targetFile, fs.readFileSync(source));
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log("file copy error: " +source +" -> " + targetFile + " (error ignored)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyFolderRecursiveSync(source, target, ignore) {
|
||||||
|
var files = [];
|
||||||
|
|
||||||
|
var base = path.basename(source);
|
||||||
|
if (base === adapterName) {
|
||||||
|
base = pkg.name;
|
||||||
|
}
|
||||||
|
//check if folder needs to be created or integrated
|
||||||
|
var targetFolder = path.join(target, base);
|
||||||
|
if (!fs.existsSync(targetFolder)) {
|
||||||
|
fs.mkdirSync(targetFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
//copy
|
||||||
|
if (fs.lstatSync(source).isDirectory()) {
|
||||||
|
files = fs.readdirSync(source);
|
||||||
|
files.forEach(function (file) {
|
||||||
|
if (ignore && ignore.indexOf(file) !== -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var curSource = path.join(source, file);
|
||||||
|
var curTarget = path.join(targetFolder, file);
|
||||||
|
if (fs.lstatSync(curSource).isDirectory()) {
|
||||||
|
// ignore grunt files
|
||||||
|
if (file.indexOf('grunt') !== -1) return;
|
||||||
|
if (file === 'chai') return;
|
||||||
|
if (file === 'mocha') return;
|
||||||
|
copyFolderRecursiveSync(curSource, targetFolder, ignore);
|
||||||
|
} else {
|
||||||
|
copyFileSync(curSource, curTarget);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(rootDir + 'tmp')) {
|
||||||
|
fs.mkdirSync(rootDir + 'tmp');
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeOriginalFiles() {
|
||||||
|
console.log('Store original files...');
|
||||||
|
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
|
||||||
|
var f = fs.readFileSync(dataDir + 'objects.json');
|
||||||
|
var objects = JSON.parse(f.toString());
|
||||||
|
if (objects['system.adapter.admin.0'] && objects['system.adapter.admin.0'].common) {
|
||||||
|
objects['system.adapter.admin.0'].common.enabled = false;
|
||||||
|
}
|
||||||
|
if (objects['system.adapter.admin.1'] && objects['system.adapter.admin.1'].common) {
|
||||||
|
objects['system.adapter.admin.1'].common.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(dataDir + 'objects.json.original', JSON.stringify(objects));
|
||||||
|
try {
|
||||||
|
f = fs.readFileSync(dataDir + 'states.json');
|
||||||
|
fs.writeFileSync(dataDir + 'states.json.original', f);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log('no states.json found - ignore');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreOriginalFiles() {
|
||||||
|
console.log('restoreOriginalFiles...');
|
||||||
|
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
|
||||||
|
var f = fs.readFileSync(dataDir + 'objects.json.original');
|
||||||
|
fs.writeFileSync(dataDir + 'objects.json', f);
|
||||||
|
try {
|
||||||
|
f = fs.readFileSync(dataDir + 'states.json.original');
|
||||||
|
fs.writeFileSync(dataDir + 'states.json', f);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log('no states.json.original found - ignore');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkIsAdapterInstalled(cb, counter, customName) {
|
||||||
|
customName = customName || pkg.name.split('.').pop();
|
||||||
|
counter = counter || 0;
|
||||||
|
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
console.log('checkIsAdapterInstalled...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
var f = fs.readFileSync(dataDir + 'objects.json');
|
||||||
|
var objects = JSON.parse(f.toString());
|
||||||
|
if (objects['system.adapter.' + customName + '.0']) {
|
||||||
|
console.log('checkIsAdapterInstalled: ready!');
|
||||||
|
setTimeout(function () {
|
||||||
|
if (cb) cb();
|
||||||
|
}, 100);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.warn('checkIsAdapterInstalled: still not ready');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (counter > 20) {
|
||||||
|
console.error('checkIsAdapterInstalled: Cannot install!');
|
||||||
|
if (cb) cb('Cannot install');
|
||||||
|
} else {
|
||||||
|
console.log('checkIsAdapterInstalled: wait...');
|
||||||
|
setTimeout(function() {
|
||||||
|
checkIsAdapterInstalled(cb, counter + 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkIsControllerInstalled(cb, counter) {
|
||||||
|
counter = counter || 0;
|
||||||
|
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
|
||||||
|
console.log('checkIsControllerInstalled...');
|
||||||
|
try {
|
||||||
|
var f = fs.readFileSync(dataDir + 'objects.json');
|
||||||
|
var objects = JSON.parse(f.toString());
|
||||||
|
if (objects['system.adapter.admin.0']) {
|
||||||
|
console.log('checkIsControllerInstalled: installed!');
|
||||||
|
setTimeout(function () {
|
||||||
|
if (cb) cb();
|
||||||
|
}, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (counter > 20) {
|
||||||
|
console.log('checkIsControllerInstalled: Cannot install!');
|
||||||
|
if (cb) cb('Cannot install');
|
||||||
|
} else {
|
||||||
|
console.log('checkIsControllerInstalled: wait...');
|
||||||
|
setTimeout(function() {
|
||||||
|
checkIsControllerInstalled(cb, counter + 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function installAdapter(customName, cb) {
|
||||||
|
if (typeof customName === 'function') {
|
||||||
|
cb = customName;
|
||||||
|
customName = null;
|
||||||
|
}
|
||||||
|
customName = customName || pkg.name.split('.').pop();
|
||||||
|
console.log('Install adapter...');
|
||||||
|
var startFile = 'node_modules/' + appName + '.js-controller/' + appName + '.js';
|
||||||
|
// make first install
|
||||||
|
if (debug) {
|
||||||
|
child_process.execSync('node ' + startFile + ' add ' + customName + ' --enabled false', {
|
||||||
|
cwd: rootDir + 'tmp',
|
||||||
|
stdio: [0, 1, 2]
|
||||||
|
});
|
||||||
|
checkIsAdapterInstalled(function (error) {
|
||||||
|
if (error) console.error(error);
|
||||||
|
console.log('Adapter installed.');
|
||||||
|
if (cb) cb();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// add controller
|
||||||
|
var _pid = child_process.fork(startFile, ['add', customName, '--enabled', 'false'], {
|
||||||
|
cwd: rootDir + 'tmp',
|
||||||
|
stdio: [0, 1, 2, 'ipc']
|
||||||
|
});
|
||||||
|
|
||||||
|
waitForEnd(_pid, function () {
|
||||||
|
checkIsAdapterInstalled(function (error) {
|
||||||
|
if (error) console.error(error);
|
||||||
|
console.log('Adapter installed.');
|
||||||
|
if (cb) cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForEnd(_pid, cb) {
|
||||||
|
if (!_pid) {
|
||||||
|
cb(-1, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_pid.on('exit', function (code, signal) {
|
||||||
|
if (_pid) {
|
||||||
|
_pid = null;
|
||||||
|
cb(code, signal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_pid.on('close', function (code, signal) {
|
||||||
|
if (_pid) {
|
||||||
|
_pid = null;
|
||||||
|
cb(code, signal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function installJsController(cb) {
|
||||||
|
console.log('installJsController...');
|
||||||
|
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller') ||
|
||||||
|
!fs.existsSync(rootDir + 'tmp/' + appName + '-data')) {
|
||||||
|
// try to detect appName.js-controller in node_modules/appName.js-controller
|
||||||
|
// travis CI installs js-controller into node_modules
|
||||||
|
if (fs.existsSync(rootDir + 'node_modules/' + appName + '.js-controller')) {
|
||||||
|
console.log('installJsController: no js-controller => copy it from "' + rootDir + 'node_modules/' + appName + '.js-controller"');
|
||||||
|
// copy all
|
||||||
|
// stop controller
|
||||||
|
console.log('Stop controller if running...');
|
||||||
|
var _pid;
|
||||||
|
if (debug) {
|
||||||
|
// start controller
|
||||||
|
_pid = child_process.exec('node ' + appName + '.js stop', {
|
||||||
|
cwd: rootDir + 'node_modules/' + appName + '.js-controller',
|
||||||
|
stdio: [0, 1, 2]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
_pid = child_process.fork(appName + '.js', ['stop'], {
|
||||||
|
cwd: rootDir + 'node_modules/' + appName + '.js-controller',
|
||||||
|
stdio: [0, 1, 2, 'ipc']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForEnd(_pid, function () {
|
||||||
|
// copy all files into
|
||||||
|
if (!fs.existsSync(rootDir + 'tmp')) fs.mkdirSync(rootDir + 'tmp');
|
||||||
|
if (!fs.existsSync(rootDir + 'tmp/node_modules')) fs.mkdirSync(rootDir + 'tmp/node_modules');
|
||||||
|
|
||||||
|
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller')){
|
||||||
|
console.log('Copy js-controller...');
|
||||||
|
copyFolderRecursiveSync(rootDir + 'node_modules/' + appName + '.js-controller', rootDir + 'tmp/node_modules/');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Setup js-controller...');
|
||||||
|
var __pid;
|
||||||
|
if (debug) {
|
||||||
|
// start controller
|
||||||
|
_pid = child_process.exec('node ' + appName + '.js setup first --console', {
|
||||||
|
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
||||||
|
stdio: [0, 1, 2]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
__pid = child_process.fork(appName + '.js', ['setup', 'first', '--console'], {
|
||||||
|
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
||||||
|
stdio: [0, 1, 2, 'ipc']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
waitForEnd(__pid, function () {
|
||||||
|
checkIsControllerInstalled(function () {
|
||||||
|
// change ports for object and state DBs
|
||||||
|
var config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
||||||
|
config.objects.port = 19001;
|
||||||
|
config.states.port = 19000;
|
||||||
|
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
||||||
|
console.log('Setup finished.');
|
||||||
|
|
||||||
|
copyAdapterToController();
|
||||||
|
|
||||||
|
installAdapter(function () {
|
||||||
|
storeOriginalFiles();
|
||||||
|
if (cb) cb(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// check if port 9000 is free, else admin adapter will be added to running instance
|
||||||
|
var client = new require('net').Socket();
|
||||||
|
client.connect(9000, '127.0.0.1', function() {
|
||||||
|
console.error('Cannot initiate fisrt run of test, because one instance of application is running on this PC. Stop it and repeat.');
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
client.destroy();
|
||||||
|
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller')) {
|
||||||
|
console.log('installJsController: no js-controller => install from git');
|
||||||
|
|
||||||
|
child_process.execSync('npm install https://git.spacen.net/' + appName + '/' + appName + '.js-controller/tarball/master --prefix ./ --production', {
|
||||||
|
cwd: rootDir + 'tmp/',
|
||||||
|
stdio: [0, 1, 2]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('Setup js-controller...');
|
||||||
|
var __pid;
|
||||||
|
if (debug) {
|
||||||
|
// start controller
|
||||||
|
child_process.exec('node ' + appName + '.js setup first', {
|
||||||
|
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
||||||
|
stdio: [0, 1, 2]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
child_process.fork(appName + '.js', ['setup', 'first'], {
|
||||||
|
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
||||||
|
stdio: [0, 1, 2, 'ipc']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// let npm install admin and run setup
|
||||||
|
checkIsControllerInstalled(function () {
|
||||||
|
var _pid;
|
||||||
|
|
||||||
|
if (fs.existsSync(rootDir + 'node_modules/' + appName + '.js-controller/' + appName + '.js')) {
|
||||||
|
_pid = child_process.fork(appName + '.js', ['stop'], {
|
||||||
|
cwd: rootDir + 'node_modules/' + appName + '.js-controller',
|
||||||
|
stdio: [0, 1, 2, 'ipc']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForEnd(_pid, function () {
|
||||||
|
// change ports for object and state DBs
|
||||||
|
var config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
||||||
|
config.objects.port = 19001;
|
||||||
|
config.states.port = 19000;
|
||||||
|
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
||||||
|
|
||||||
|
copyAdapterToController();
|
||||||
|
|
||||||
|
installAdapter(function () {
|
||||||
|
storeOriginalFiles();
|
||||||
|
if (cb) cb(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTimeout(function () {
|
||||||
|
console.log('installJsController: js-controller installed');
|
||||||
|
if (cb) cb(false);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyAdapterToController() {
|
||||||
|
console.log('Copy adapter...');
|
||||||
|
// Copy adapter to tmp/node_modules/appName.adapter
|
||||||
|
copyFolderRecursiveSync(rootDir, rootDir + 'tmp/node_modules/', ['.idea', 'test', 'tmp', '.git', appName + '.js-controller']);
|
||||||
|
console.log('Adapter copied.');
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearControllerLog() {
|
||||||
|
var dirPath = rootDir + 'tmp/log';
|
||||||
|
var files;
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(dirPath)) {
|
||||||
|
console.log('Clear controller log...');
|
||||||
|
files = fs.readdirSync(dirPath);
|
||||||
|
} else {
|
||||||
|
console.log('Create controller log directory...');
|
||||||
|
files = [];
|
||||||
|
fs.mkdirSync(dirPath);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.error('Cannot read "' + dirPath + '"');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (files.length > 0) {
|
||||||
|
try {
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
var filePath = dirPath + '/' + files[i];
|
||||||
|
fs.unlinkSync(filePath);
|
||||||
|
}
|
||||||
|
console.log('Controller log cleared');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('cannot clear log: ' + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearDB() {
|
||||||
|
var dirPath = rootDir + 'tmp/yunkong2-data/sqlite';
|
||||||
|
var files;
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(dirPath)) {
|
||||||
|
console.log('Clear sqlite DB...');
|
||||||
|
files = fs.readdirSync(dirPath);
|
||||||
|
} else {
|
||||||
|
console.log('Create controller log directory...');
|
||||||
|
files = [];
|
||||||
|
fs.mkdirSync(dirPath);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.error('Cannot read "' + dirPath + '"');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (files.length > 0) {
|
||||||
|
try {
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
var filePath = dirPath + '/' + files[i];
|
||||||
|
fs.unlinkSync(filePath);
|
||||||
|
}
|
||||||
|
console.log('Clear sqlite DB');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('cannot clear DB: ' + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupController(cb) {
|
||||||
|
installJsController(function (isInited) {
|
||||||
|
clearControllerLog();
|
||||||
|
clearDB();
|
||||||
|
|
||||||
|
if (!isInited) {
|
||||||
|
restoreOriginalFiles();
|
||||||
|
copyAdapterToController();
|
||||||
|
}
|
||||||
|
// read system.config object
|
||||||
|
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
||||||
|
|
||||||
|
var objs;
|
||||||
|
try {
|
||||||
|
objs = fs.readFileSync(dataDir + 'objects.json');
|
||||||
|
objs = JSON.parse(objs);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log('ERROR reading/parsing system configuration. Ignore');
|
||||||
|
objs = {'system.config': {}};
|
||||||
|
}
|
||||||
|
if (!objs || !objs['system.config']) {
|
||||||
|
objs = {'system.config': {}};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cb) cb(objs['system.config']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function startAdapter(objects, states, callback) {
|
||||||
|
if (adapterStarted) {
|
||||||
|
console.log('Adapter already started ...');
|
||||||
|
if (callback) callback(objects, states);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
adapterStarted = true;
|
||||||
|
console.log('startAdapter...');
|
||||||
|
if (fs.existsSync(rootDir + 'tmp/node_modules/' + pkg.name + '/' + pkg.main)) {
|
||||||
|
try {
|
||||||
|
if (debug) {
|
||||||
|
// start controller
|
||||||
|
pid = child_process.exec('node node_modules/' + pkg.name + '/' + pkg.main + ' --console silly', {
|
||||||
|
cwd: rootDir + 'tmp',
|
||||||
|
stdio: [0, 1, 2]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// start controller
|
||||||
|
pid = child_process.fork('node_modules/' + pkg.name + '/' + pkg.main, ['--console', 'silly'], {
|
||||||
|
cwd: rootDir + 'tmp',
|
||||||
|
stdio: [0, 1, 2, 'ipc']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(JSON.stringify(error));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('Cannot find: ' + rootDir + 'tmp/node_modules/' + pkg.name + '/' + pkg.main);
|
||||||
|
}
|
||||||
|
if (callback) callback(objects, states);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startController(isStartAdapter, onObjectChange, onStateChange, callback) {
|
||||||
|
if (typeof isStartAdapter === 'function') {
|
||||||
|
callback = onStateChange;
|
||||||
|
onStateChange = onObjectChange;
|
||||||
|
onObjectChange = isStartAdapter;
|
||||||
|
isStartAdapter = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onStateChange === undefined) {
|
||||||
|
callback = onObjectChange;
|
||||||
|
onObjectChange = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid) {
|
||||||
|
console.error('Controller is already started!');
|
||||||
|
} else {
|
||||||
|
console.log('startController...');
|
||||||
|
adapterStarted = false;
|
||||||
|
var isObjectConnected;
|
||||||
|
var isStatesConnected;
|
||||||
|
|
||||||
|
var Objects = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/objects/objectsInMemServer');
|
||||||
|
objects = new Objects({
|
||||||
|
connection: {
|
||||||
|
"type" : "file",
|
||||||
|
"host" : "127.0.0.1",
|
||||||
|
"port" : 19001,
|
||||||
|
"user" : "",
|
||||||
|
"pass" : "",
|
||||||
|
"noFileCache": false,
|
||||||
|
"connectTimeout": 2000
|
||||||
|
},
|
||||||
|
logger: {
|
||||||
|
silly: function (msg) {
|
||||||
|
console.log(msg);
|
||||||
|
},
|
||||||
|
debug: function (msg) {
|
||||||
|
console.log(msg);
|
||||||
|
},
|
||||||
|
info: function (msg) {
|
||||||
|
console.log(msg);
|
||||||
|
},
|
||||||
|
warn: function (msg) {
|
||||||
|
console.warn(msg);
|
||||||
|
},
|
||||||
|
error: function (msg) {
|
||||||
|
console.error(msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
connected: function () {
|
||||||
|
isObjectConnected = true;
|
||||||
|
if (isStatesConnected) {
|
||||||
|
console.log('startController: started!');
|
||||||
|
if (isStartAdapter) {
|
||||||
|
startAdapter(objects, states, callback);
|
||||||
|
} else {
|
||||||
|
if (callback) {
|
||||||
|
callback(objects, states);
|
||||||
|
callback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
change: onObjectChange
|
||||||
|
});
|
||||||
|
|
||||||
|
// Just open in memory DB itself
|
||||||
|
var States = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/states/statesInMemServer');
|
||||||
|
states = new States({
|
||||||
|
connection: {
|
||||||
|
type: 'file',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 19000,
|
||||||
|
options: {
|
||||||
|
auth_pass: null,
|
||||||
|
retry_max_delay: 15000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
logger: {
|
||||||
|
silly: function (msg) {
|
||||||
|
console.log(msg);
|
||||||
|
},
|
||||||
|
debug: function (msg) {
|
||||||
|
console.log(msg);
|
||||||
|
},
|
||||||
|
info: function (msg) {
|
||||||
|
console.log(msg);
|
||||||
|
},
|
||||||
|
warn: function (msg) {
|
||||||
|
console.log(msg);
|
||||||
|
},
|
||||||
|
error: function (msg) {
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
connected: function () {
|
||||||
|
isStatesConnected = true;
|
||||||
|
if (isObjectConnected) {
|
||||||
|
console.log('startController: started!!');
|
||||||
|
if (isStartAdapter) {
|
||||||
|
startAdapter(objects, states, callback);
|
||||||
|
} else {
|
||||||
|
if (callback) {
|
||||||
|
callback(objects, states);
|
||||||
|
callback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
change: onStateChange
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopAdapter(cb) {
|
||||||
|
if (!pid) {
|
||||||
|
console.error('Controller is not running!');
|
||||||
|
if (cb) {
|
||||||
|
setTimeout(function () {
|
||||||
|
cb(false);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
adapterStarted = false;
|
||||||
|
pid.on('exit', function (code, signal) {
|
||||||
|
if (pid) {
|
||||||
|
console.log('child process terminated due to receipt of signal ' + signal);
|
||||||
|
if (cb) cb();
|
||||||
|
pid = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pid.on('close', function (code, signal) {
|
||||||
|
if (pid) {
|
||||||
|
if (cb) cb();
|
||||||
|
pid = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pid.kill('SIGTERM');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _stopController() {
|
||||||
|
if (objects) {
|
||||||
|
objects.destroy();
|
||||||
|
objects = null;
|
||||||
|
}
|
||||||
|
if (states) {
|
||||||
|
states.destroy();
|
||||||
|
states = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopController(cb) {
|
||||||
|
var timeout;
|
||||||
|
if (objects) {
|
||||||
|
console.log('Set system.adapter.' + pkg.name + '.0');
|
||||||
|
objects.setObject('system.adapter.' + pkg.name + '.0', {
|
||||||
|
common:{
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stopAdapter(function () {
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_stopController();
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
cb(true);
|
||||||
|
cb = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
timeout = setTimeout(function () {
|
||||||
|
timeout = null;
|
||||||
|
console.log('child process NOT terminated');
|
||||||
|
|
||||||
|
_stopController();
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
cb(false);
|
||||||
|
cb = null;
|
||||||
|
}
|
||||||
|
pid = null;
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the adapter
|
||||||
|
function setAdapterConfig(common, native, instance) {
|
||||||
|
var objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
||||||
|
var id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
||||||
|
if (common) objects[id].common = common;
|
||||||
|
if (native) objects[id].native = native;
|
||||||
|
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/objects.json', JSON.stringify(objects));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read config of the adapter
|
||||||
|
function getAdapterConfig(instance) {
|
||||||
|
var objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
||||||
|
var id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
||||||
|
return objects[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof module !== undefined && module.parent) {
|
||||||
|
module.exports.getAdapterConfig = getAdapterConfig;
|
||||||
|
module.exports.setAdapterConfig = setAdapterConfig;
|
||||||
|
module.exports.startController = startController;
|
||||||
|
module.exports.stopController = stopController;
|
||||||
|
module.exports.setupController = setupController;
|
||||||
|
module.exports.stopAdapter = stopAdapter;
|
||||||
|
module.exports.startAdapter = startAdapter;
|
||||||
|
module.exports.installAdapter = installAdapter;
|
||||||
|
module.exports.appName = appName;
|
||||||
|
module.exports.adapterName = adapterName;
|
||||||
|
module.exports.adapterStarted = adapterStarted;
|
||||||
|
}
|
460
test/testApi.js
Normal file
460
test/testApi.js
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
/* jshint -W097 */// jshint strict:false
|
||||||
|
/*jslint node: true */
|
||||||
|
/*jshint expr: true*/
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var setup = require(__dirname + '/lib/setup');
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
|
var objects = null;
|
||||||
|
var states = null;
|
||||||
|
|
||||||
|
process.env.NO_PROXY = '127.0.0.1';
|
||||||
|
|
||||||
|
function checkConnectionOfAdapter(cb, counter) {
|
||||||
|
counter = counter || 0;
|
||||||
|
console.log('Try check #' + counter);
|
||||||
|
if (counter > 30) {
|
||||||
|
if (cb) cb('Cannot check connection');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
states.getState('system.adapter.simple-api.0.alive', function (err, state) {
|
||||||
|
if (err) console.error(err);
|
||||||
|
if (state && state.val) {
|
||||||
|
if (cb) cb();
|
||||||
|
} else {
|
||||||
|
setTimeout(function () {
|
||||||
|
checkConnectionOfAdapter(cb, counter + 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Test RESTful API', function() {
|
||||||
|
before('Test RESTful API: Start js-controller', function (_done) {
|
||||||
|
this.timeout(600000); // because of first install from npm
|
||||||
|
var brokerStarted = false;
|
||||||
|
setup.adapterStarted = false;
|
||||||
|
|
||||||
|
setup.setupController(function () {
|
||||||
|
var config = setup.getAdapterConfig();
|
||||||
|
// enable adapter
|
||||||
|
config.common.enabled = true;
|
||||||
|
config.common.loglevel = 'debug';
|
||||||
|
config.native.port = 18183;
|
||||||
|
setup.setAdapterConfig(config.common, config.native);
|
||||||
|
|
||||||
|
setup.startController(function (_objects, _states) {
|
||||||
|
objects = _objects;
|
||||||
|
states = _states;
|
||||||
|
// give some time to start server
|
||||||
|
setTimeout(function () {
|
||||||
|
_done();
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test adapter: Check if adapter started and create upload datapoint', function (done) {
|
||||||
|
this.timeout(60000);
|
||||||
|
checkConnectionOfAdapter(function (res) {
|
||||||
|
if (res) console.log(res);
|
||||||
|
expect(res).not.to.be.equal('Cannot check connection');
|
||||||
|
objects.setObject('javascript.0.test-string', {
|
||||||
|
common: {
|
||||||
|
name: 'test',
|
||||||
|
type: 'string',
|
||||||
|
role: 'value',
|
||||||
|
def: ''
|
||||||
|
},
|
||||||
|
native: {
|
||||||
|
},
|
||||||
|
type: 'state'
|
||||||
|
}, function (err) {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
states.setState('javascript.0.test-string','', function(err) {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: get - must return value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/get/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('get/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
//{
|
||||||
|
// "val" : true,
|
||||||
|
// "ack" : true,
|
||||||
|
// "ts" : 1455009717,
|
||||||
|
// "q" : 0,
|
||||||
|
// "from" : "system.adapter.simple-api.0",
|
||||||
|
// "lc" : 1455009717,
|
||||||
|
// "expire" : 30000,
|
||||||
|
// "_id" : "system.adapter.simple-api.0.alive",
|
||||||
|
// "type" : "state",
|
||||||
|
// "common" : {
|
||||||
|
// "name" : "simple-api.0.alive",
|
||||||
|
// "type" : "boolean",
|
||||||
|
// "role" : "indicator.state"
|
||||||
|
// },
|
||||||
|
// "native" : {}
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.true;
|
||||||
|
expect(obj.ack).to.be.true;
|
||||||
|
expect(obj.ts).to.be.ok;
|
||||||
|
//expect(obj.from).to.equal("system.adapter.simple-api.0");
|
||||||
|
expect(obj.type).to.equal("state");
|
||||||
|
expect(obj._id).to.equal("system.adapter.simple-api.0.alive");
|
||||||
|
expect(obj.common).to.be.ok;
|
||||||
|
expect(obj.native).to.be.ok;
|
||||||
|
expect(obj.common.name).to.equal("simple-api.0.alive");
|
||||||
|
expect(obj.common.role).to.equal("indicator.state");
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: getPlainValue - must return plain value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('true');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: set - must set value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/system.adapter.simple-api.0.alive?val=false', function (error, response, body) {
|
||||||
|
console.log('set/system.adapter.simple-api.0.alive?val=false => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.false;
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('false');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/get/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('get/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(JSON.parse(body).val).equal(false);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: set - must set easy string value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/javascript.0.test-string?val=bla', function (error, response, body) {
|
||||||
|
console.log('set/javascript.0.test-string?val=bla => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).equal('bla');
|
||||||
|
expect(obj.id).to.equal('javascript.0.test-string');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/javascript.0.test-string', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/javascript.0.test-string => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('"bla"');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/get/javascript.0.test-string', function (error, response, body) {
|
||||||
|
console.log('get/javascript.0.test-string => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(JSON.parse(body).val).equal('bla');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: set - must set encoded string value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/javascript.0.test-string?val=bla%26fasel%2efoo%3Dhummer+hey', function (error, response, body) {
|
||||||
|
console.log('set/javascript.0.test-string?val=bla%20fasel%2efoo => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).equal('bla&fasel.foo=hummer hey');
|
||||||
|
expect(obj.id).to.equal('javascript.0.test-string');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/javascript.0.test-string', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/javascript.0.test-string => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('"bla&fasel.foo=hummer hey"');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/get/javascript.0.test-string', function (error, response, body) {
|
||||||
|
console.log('get/javascript.0.test-string => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(JSON.parse(body).val).equal('bla&fasel.foo=hummer hey');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: set - must set val', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/system.adapter.simple-api.0.alive?val=true', function (error, response, body) {
|
||||||
|
console.log('set/system.adapter.simple-api.0.alive?val=true => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.true;
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('true');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: toggle - must toggle boolean value to false', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/toggle/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('toggle/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.false;
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('false');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: toggle - must toggle boolean value to true', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/toggle/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('toggle/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.true;
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('true');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: toggle - must toggle number value to 100', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/toggle/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('toggle/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.equal(100);
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('100');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/set/system.adapter.simple-api.upload?val=49', function (error, response, body) {
|
||||||
|
console.log('set/system.adapter.simple-api.upload?val=49 => ' + body);
|
||||||
|
request('http://127.0.0.1:18183/toggle/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('toggle/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.equal(51);
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('51');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: setBulk - must set values', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/setBulk?system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false', function (error, response, body) {
|
||||||
|
console.log('setBulk/?system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(50);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(obj[1].val).to.be.equal(false);
|
||||||
|
expect(obj[1].id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(50);
|
||||||
|
expect(obj[1].val).equal(false);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: objects - must return objects', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/objects?pattern=system.adapter.*', function (error, response, body) {
|
||||||
|
console.log('objects?pattern=system.adapter.* => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj['system.adapter.simple-api.0.alive']._id).to.be.ok;
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: objects - must return objects', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/objects?pattern=system.adapter.*&type=instance', function (error, response, body) {
|
||||||
|
console.log('objects?pattern=system.adapter.* => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj['system.adapter.simple-api.0']._id).to.be.ok;
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: states - must return states', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/states?pattern=system.adapter.*', function (error, response, body) {
|
||||||
|
console.log('states?pattern=system.adapter.* => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var states = JSON.parse(body);
|
||||||
|
expect(states['system.adapter.simple-api.0.uptime'].val).to.be.least(0);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: setBulk(POST) - must set values', function (done) {
|
||||||
|
|
||||||
|
request({
|
||||||
|
uri: 'http://127.0.0.1:18183/setBulk',
|
||||||
|
method: 'POST',
|
||||||
|
body: 'system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false&javascript.0.test-string=bla%26fasel%2efoo%3Dhummer+hey'
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log('setBulk/?system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false&javascript.0.test-string=bla%26fasel%2efoo%3Dhummer+hey => ' + JSON.stringify(body));
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(50);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(obj[1].val).to.be.equal(false);
|
||||||
|
expect(obj[1].id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(obj[2].val).to.be.equal('bla&fasel.foo=hummer hey');
|
||||||
|
expect(obj[2].id).to.equal('javascript.0.test-string');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive,javascript.0.test-string', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive,javascript.0.test-string => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(50);
|
||||||
|
expect(obj[1].val).equal(false);
|
||||||
|
expect(obj[2].val).equal('bla&fasel.foo=hummer hey');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: setBulk(POST-GET-Mix) - must set values', function (done) {
|
||||||
|
|
||||||
|
request({
|
||||||
|
uri: 'http://127.0.0.1:18183/setBulk?system.adapter.simple-api.upload=51&system.adapter.simple-api.0.alive=false',
|
||||||
|
method: 'POST',
|
||||||
|
body: ''
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log('setBulk/?system.adapter.simple-api.upload=51&system.adapter.simple-api.0.alive=false => ' + JSON.stringify(body));
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(51);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(obj[1].val).to.be.equal(false);
|
||||||
|
expect(obj[1].id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(51);
|
||||||
|
expect(obj[1].val).equal(false);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API: setValueFromBody(POST) - must set one value', function (done) {
|
||||||
|
request({
|
||||||
|
uri: 'http://127.0.0.1:18183/setValueFromBody/system.adapter.simple-api.upload',
|
||||||
|
method: 'POST',
|
||||||
|
body: '55'
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log('setValueFromBody/?system.adapter.simple-api.upload => ' + JSON.stringify(body));
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(55);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(55);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after('Test RESTful API: Stop js-controller', function (done) {
|
||||||
|
this.timeout(6000);
|
||||||
|
setup.stopController(function (normalTerminated) {
|
||||||
|
console.log('Adapter normal terminated: ' + normalTerminated);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
277
test/testApiAsLimitedUser.js
Normal file
277
test/testApiAsLimitedUser.js
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
/* jshint -W097 */// jshint strict:false
|
||||||
|
/*jslint node: true */
|
||||||
|
/*jshint expr: true*/
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var setup = require(__dirname + '/lib/setup');
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
|
var objects = null;
|
||||||
|
var states = null;
|
||||||
|
|
||||||
|
process.env.NO_PROXY = '127.0.0.1';
|
||||||
|
|
||||||
|
function checkConnectionOfAdapter(cb, counter) {
|
||||||
|
counter = counter || 0;
|
||||||
|
console.log('Try check #' + counter);
|
||||||
|
if (counter > 30) {
|
||||||
|
if (cb) cb('Cannot check connection');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
states.getState('system.adapter.simple-api.0.alive', function (err, state) {
|
||||||
|
if (err) console.error(err);
|
||||||
|
if (state && state.val) {
|
||||||
|
if (cb) cb();
|
||||||
|
} else {
|
||||||
|
setTimeout(function () {
|
||||||
|
checkConnectionOfAdapter(cb, counter + 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Test RESTful API as Owner-User', function() {
|
||||||
|
before('Test RESTful API as Owner-User: Start js-controller', function (_done) {
|
||||||
|
this.timeout(600000); // because of first install from npm
|
||||||
|
setup.adapterStarted = false;
|
||||||
|
|
||||||
|
var brokerStarted = false;
|
||||||
|
setup.setupController(function () {
|
||||||
|
var config = setup.getAdapterConfig();
|
||||||
|
// enable adapter
|
||||||
|
config.common.enabled = true;
|
||||||
|
config.common.loglevel = 'debug';
|
||||||
|
config.native.port = 18183;
|
||||||
|
config.native.defaultUser = 'myuser';
|
||||||
|
config.native.onlyAllowWhenUserIsOwner = true;
|
||||||
|
setup.setAdapterConfig(config.common, config.native);
|
||||||
|
|
||||||
|
setup.startController(function (_objects, _states) {
|
||||||
|
objects = _objects;
|
||||||
|
states = _states;
|
||||||
|
// give some time to start server
|
||||||
|
setTimeout(function () {
|
||||||
|
_done();
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test adapter: Check if adapter started and create upload datapoint', function (done) {
|
||||||
|
this.timeout(60000);
|
||||||
|
checkConnectionOfAdapter(function (res) {
|
||||||
|
if (res) console.log(res);
|
||||||
|
expect(res).not.to.be.equal('Cannot check connection');
|
||||||
|
objects.setObject('system.group.writer', {
|
||||||
|
"common": {
|
||||||
|
"name": "Writer",
|
||||||
|
"desc": "",
|
||||||
|
"members": [
|
||||||
|
"system.user.myuser"
|
||||||
|
],
|
||||||
|
"acl": {
|
||||||
|
"object": {
|
||||||
|
"list": false,
|
||||||
|
"read": false,
|
||||||
|
"write": false,
|
||||||
|
"delete": false
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"list": false,
|
||||||
|
"read": true,
|
||||||
|
"write": true,
|
||||||
|
"create": false,
|
||||||
|
"delete": false
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"write": false,
|
||||||
|
"create": false,
|
||||||
|
"delete": false
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
"execute": false,
|
||||||
|
"http": false,
|
||||||
|
"sendto": false
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"list": false,
|
||||||
|
"read": false,
|
||||||
|
"write": false,
|
||||||
|
"create": false,
|
||||||
|
"delete": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"native": {},
|
||||||
|
"acl": {
|
||||||
|
"object": 1638,
|
||||||
|
"owner": "system.user.admin",
|
||||||
|
"ownerGroup": "system.group.administrator"
|
||||||
|
},
|
||||||
|
"_id": "system.group.writer",
|
||||||
|
"type": "group"
|
||||||
|
}, function (err) {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
|
||||||
|
objects.setObject('system.user.myuser', {
|
||||||
|
"type": "user",
|
||||||
|
"common": {
|
||||||
|
"name": "myuser",
|
||||||
|
"enabled": true,
|
||||||
|
"groups": [],
|
||||||
|
"password": "pbkdf2$10000$ab4104d8bb68390ee7e6c9397588e768de6c025f0c732c18806f3d1270c83f83fa86a7bf62583770e5f8d0b405fbb3ad32214ef3584f5f9332478f2506414443a910bf15863b36ebfcaa7cbb19253ae32cd3ca390dab87b29cd31e11be7fa4ea3a01dad625d9de44e412680e1a694227698788d71f1e089e5831dc1bbacfa794b45e1c995214bf71ee4160d98b4305fa4c3e36ee5f8da19b3708f68e7d2e8197375c0f763d90e31143eb04760cc2148c8f54937b9385c95db1742595634ed004fa567655dfe1d9b9fa698074a9fb70c05a252b2d9cf7ca1c9b009f2cd70d6972ccf0ee281d777d66a0346c6c6525436dd7fe3578b28dca2c7adbfde0ecd45148$31c3248ba4dc9600a024b4e0e7c3e585"
|
||||||
|
},
|
||||||
|
"_id": "system.user.myuser",
|
||||||
|
"native": {},
|
||||||
|
"acl": {
|
||||||
|
"object": 1638
|
||||||
|
}
|
||||||
|
}, function (err) {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
objects.setObject('javascript.0.test', {
|
||||||
|
common: {
|
||||||
|
name: 'test',
|
||||||
|
type: 'number',
|
||||||
|
role: 'level',
|
||||||
|
min: -100,
|
||||||
|
max: 100,
|
||||||
|
def: 1
|
||||||
|
},
|
||||||
|
native: {
|
||||||
|
},
|
||||||
|
type: 'state',
|
||||||
|
acl: {
|
||||||
|
object: 1638,
|
||||||
|
owner: "system.user.myuser",
|
||||||
|
ownerGroup:"system.group.administrator",
|
||||||
|
state: 1638
|
||||||
|
}
|
||||||
|
}, function (err) {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
states.setState('javascript.0.test',1, function(err) {
|
||||||
|
console.log('END javascript.0.test ' + err);
|
||||||
|
expect(err).to.be.null;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: get - must return value', function (done) {
|
||||||
|
console.log('START get/system.adapter.simple-api.0.alive');
|
||||||
|
request('http://127.0.0.1:18183/get/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('get/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: getPlainValue - must return plain value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: getPlainValue 4 Test-Endpoint - must return plain value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/javascript.0.test', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/javascript.0.test => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('1');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: set 4 Test-Endpoint - must set value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/javascript.0.test?val=2', function (error, response, body) {
|
||||||
|
console.log('set/javascript.0.test?val=false => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.equal(2);
|
||||||
|
expect(obj.id).to.equal('javascript.0.test');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/javascript.0.test', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/javascript.0.test => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('2');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: set - must set value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/system.adapter.simple-api.0.alive?val=false', function (error, response, body) {
|
||||||
|
console.log('set/system.adapter.simple-api.0.alive?val=false => ' + body);
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: set - must set val', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/system.adapter.simple-api.0.alive?val=true', function (error, response, body) {
|
||||||
|
console.log('set/system.adapter.simple-api.0.alive?val=true => ' + body);
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: objects - must return objects', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/objects?pattern=system.adapter.*', function (error, response, body) {
|
||||||
|
console.log('objects?pattern=system.adapter.* => ' + body);
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: objects - must return objects', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/objects?pattern=system.adapter.*&type=instance', function (error, response, body) {
|
||||||
|
console.log('objects?pattern=system.adapter.* => ' + body);
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: states - must return states', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/states?pattern=system.adapter.*', function (error, response, body) {
|
||||||
|
console.log('states?pattern=system.adapter.* => ' + body);
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as Owner-User: setValueFromBody(POST) - must set one value', function (done) {
|
||||||
|
request({
|
||||||
|
uri: 'http://127.0.0.1:18183/setValueFromBody/system.adapter.simple-api.upload',
|
||||||
|
method: 'POST',
|
||||||
|
body: '55'
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log('setValueFromBody/?system.adapter.simple-api.upload => ' + JSON.stringify(body));
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after('Test RESTful API as Owner-User: Stop js-controller', function (done) {
|
||||||
|
this.timeout(6000);
|
||||||
|
setup.stopController(function (normalTerminated) {
|
||||||
|
console.log('Adapter normal terminated: ' + normalTerminated);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
508
test/testApiAsUser.js
Normal file
508
test/testApiAsUser.js
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
/* jshint -W097 */// jshint strict:false
|
||||||
|
/*jslint node: true */
|
||||||
|
/*jshint expr: true*/
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var setup = require(__dirname + '/lib/setup');
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
|
var objects = null;
|
||||||
|
var states = null;
|
||||||
|
|
||||||
|
process.env.NO_PROXY = '127.0.0.1';
|
||||||
|
|
||||||
|
function checkConnectionOfAdapter(cb, counter) {
|
||||||
|
counter = counter || 0;
|
||||||
|
console.log('Try check #' + counter);
|
||||||
|
if (counter > 30) {
|
||||||
|
if (cb) cb('Cannot check connection');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
states.getState('system.adapter.simple-api.0.alive', function (err, state) {
|
||||||
|
if (err) console.error(err);
|
||||||
|
if (state && state.val) {
|
||||||
|
if (cb) cb();
|
||||||
|
} else {
|
||||||
|
setTimeout(function () {
|
||||||
|
checkConnectionOfAdapter(cb, counter + 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Test RESTful API as User', function() {
|
||||||
|
before('Test RESTful API as User: Start js-controller', function (_done) {
|
||||||
|
this.timeout(600000); // because of first install from npm
|
||||||
|
setup.adapterStarted = false;
|
||||||
|
|
||||||
|
var brokerStarted = false;
|
||||||
|
setup.setupController(function () {
|
||||||
|
var config = setup.getAdapterConfig();
|
||||||
|
// enable adapter
|
||||||
|
config.common.enabled = true;
|
||||||
|
config.common.loglevel = 'debug';
|
||||||
|
config.native.port = 18183;
|
||||||
|
config.native.defaultUser = 'myuser';
|
||||||
|
setup.setAdapterConfig(config.common, config.native);
|
||||||
|
|
||||||
|
setup.startController(function (_objects, _states) {
|
||||||
|
objects = _objects;
|
||||||
|
states = _states;
|
||||||
|
// give some time to start server
|
||||||
|
setTimeout(function () {
|
||||||
|
_done();
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test adapter: Check if adapter started and create upload datapoint', function (done) {
|
||||||
|
this.timeout(60000);
|
||||||
|
checkConnectionOfAdapter(function (res) {
|
||||||
|
if (res) console.log(res);
|
||||||
|
expect(res).not.to.be.equal('Cannot check connection');
|
||||||
|
objects.setObject('system.group.writer', {
|
||||||
|
"common": {
|
||||||
|
"name": "Writer",
|
||||||
|
"desc": "",
|
||||||
|
"members": [
|
||||||
|
"system.user.myuser"
|
||||||
|
],
|
||||||
|
"acl": {
|
||||||
|
"object": {
|
||||||
|
"list": false,
|
||||||
|
"read": false,
|
||||||
|
"write": false,
|
||||||
|
"delete": false
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"list": false,
|
||||||
|
"read": true,
|
||||||
|
"write": true,
|
||||||
|
"create": false,
|
||||||
|
"delete": false
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"write": false,
|
||||||
|
"create": false,
|
||||||
|
"delete": false
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
"execute": false,
|
||||||
|
"http": false,
|
||||||
|
"sendto": false
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"list": false,
|
||||||
|
"read": false,
|
||||||
|
"write": false,
|
||||||
|
"create": false,
|
||||||
|
"delete": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"native": {},
|
||||||
|
"acl": {
|
||||||
|
"object": 1638,
|
||||||
|
"owner": "system.user.admin",
|
||||||
|
"ownerGroup": "system.group.administrator"
|
||||||
|
},
|
||||||
|
"_id": "system.group.writer",
|
||||||
|
"type": "group"
|
||||||
|
}, function (err) {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
|
||||||
|
objects.setObject('system.user.myuser', {
|
||||||
|
"type": "user",
|
||||||
|
"common": {
|
||||||
|
"name": "myuser",
|
||||||
|
"enabled": true,
|
||||||
|
"groups": [],
|
||||||
|
"password": "pbkdf2$10000$ab4104d8bb68390ee7e6c9397588e768de6c025f0c732c18806f3d1270c83f83fa86a7bf62583770e5f8d0b405fbb3ad32214ef3584f5f9332478f2506414443a910bf15863b36ebfcaa7cbb19253ae32cd3ca390dab87b29cd31e11be7fa4ea3a01dad625d9de44e412680e1a694227698788d71f1e089e5831dc1bbacfa794b45e1c995214bf71ee4160d98b4305fa4c3e36ee5f8da19b3708f68e7d2e8197375c0f763d90e31143eb04760cc2148c8f54937b9385c95db1742595634ed004fa567655dfe1d9b9fa698074a9fb70c05a252b2d9cf7ca1c9b009f2cd70d6972ccf0ee281d777d66a0346c6c6525436dd7fe3578b28dca2c7adbfde0ecd45148$31c3248ba4dc9600a024b4e0e7c3e585"
|
||||||
|
},
|
||||||
|
"_id": "system.user.myuser",
|
||||||
|
"native": {},
|
||||||
|
"acl": {
|
||||||
|
"object": 1638
|
||||||
|
}
|
||||||
|
}, function (err) {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
objects.setObject('javascript.0.test', {
|
||||||
|
common: {
|
||||||
|
name: 'test',
|
||||||
|
type: 'number',
|
||||||
|
role: 'level',
|
||||||
|
min: -100,
|
||||||
|
max: 100,
|
||||||
|
def: 1
|
||||||
|
},
|
||||||
|
native: {
|
||||||
|
},
|
||||||
|
type: 'state',
|
||||||
|
acl: {
|
||||||
|
object: 1638,
|
||||||
|
owner: "system.user.myuser",
|
||||||
|
ownerGroup:"system.group.administrator",
|
||||||
|
state: 1638
|
||||||
|
}
|
||||||
|
}, function (err) {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
states.setState('javascript.0.test',1, function(err) {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: get - must return value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/get/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('get/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
//{
|
||||||
|
// "val" : true,
|
||||||
|
// "ack" : true,
|
||||||
|
// "ts" : 1455009717,
|
||||||
|
// "q" : 0,
|
||||||
|
// "from" : "system.adapter.simple-api.0",
|
||||||
|
// "lc" : 1455009717,
|
||||||
|
// "expire" : 30000,
|
||||||
|
// "_id" : "system.adapter.simple-api.0.alive",
|
||||||
|
// "type" : "state",
|
||||||
|
// "common" : {
|
||||||
|
// "name" : "simple-api.0.alive",
|
||||||
|
// "type" : "boolean",
|
||||||
|
// "role" : "indicator.state"
|
||||||
|
// },
|
||||||
|
// "native" : {}
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.true;
|
||||||
|
expect(obj.ack).to.be.true;
|
||||||
|
expect(obj.ts).to.be.ok;
|
||||||
|
//expect(obj.from).to.equal("system.adapter.simple-api.0");
|
||||||
|
expect(obj.type).to.equal("state");
|
||||||
|
expect(obj._id).to.equal("system.adapter.simple-api.0.alive");
|
||||||
|
expect(obj.common).to.be.ok;
|
||||||
|
expect(obj.native).to.be.ok;
|
||||||
|
expect(obj.common.name).to.equal("simple-api.0.alive");
|
||||||
|
expect(obj.common.role).to.equal("indicator.state");
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: getPlainValue - must return plain value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('true');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: getPlainValue 4 Test-Endpoint - must return plain value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/javascript.0.test', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/javascript.0.test => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('1');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: set 4 Test-Endpoint - must set value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/javascript.0.test?val=2', function (error, response, body) {
|
||||||
|
console.log('set/javascript.0.test?val=false => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.equal(2);
|
||||||
|
expect(obj.id).to.equal('javascript.0.test');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/javascript.0.test', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/javascript.0.test => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('2');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: set - must set value', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/system.adapter.simple-api.0.alive?val=false', function (error, response, body) {
|
||||||
|
console.log('set/system.adapter.simple-api.0.alive?val=false => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.false;
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('false');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: set - must set val', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/set/system.adapter.simple-api.0.alive?val=true', function (error, response, body) {
|
||||||
|
console.log('set/system.adapter.simple-api.0.alive?val=true => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.true;
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('true');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: toggle - must toggle boolean value to false', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/toggle/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('toggle/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.false;
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('false');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: toggle - must toggle boolean value to true', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/toggle/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('toggle/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.true;
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('true');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: toggle - must toggle number value to 100', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/toggle/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('toggle/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.equal(100);
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('100');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
request('http://127.0.0.1:18183/set/system.adapter.simple-api.upload?val=49', function (error, response, body) {
|
||||||
|
console.log('set/system.adapter.simple-api.upload?val=49 => ' + body);
|
||||||
|
request('http://127.0.0.1:18183/toggle/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('toggle/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.equal(51);
|
||||||
|
expect(obj.id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getPlainValue/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('getPlainValue/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(body).equal('51');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: setBulk - must set values', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/setBulk/?system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false&javascript.0.test=3', function (error, response, body) {
|
||||||
|
console.log('setBulk/?system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false&javascript.0.test=3 => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(50);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(obj[1].val).to.be.equal(false);
|
||||||
|
expect(obj[1].id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(obj[2].val).to.be.equal(3);
|
||||||
|
expect(obj[2].id).to.equal('javascript.0.test');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive,javascript.0.test', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive&javascript.0.test => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(50);
|
||||||
|
expect(obj[1].val).equal(false);
|
||||||
|
expect(obj[2].val).equal(3);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: objects - must return objects', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/objects?pattern=system.adapter.*', function (error, response, body) {
|
||||||
|
console.log('objects?pattern=system.adapter.* => ' + body);
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: objects - must return objects', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/objects?pattern=system.adapter.*&type=instance', function (error, response, body) {
|
||||||
|
console.log('objects?pattern=system.adapter.* => ' + body);
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: states - must return states', function (done) {
|
||||||
|
request('http://127.0.0.1:18183/states?pattern=system.adapter.*', function (error, response, body) {
|
||||||
|
console.log('states?pattern=system.adapter.* => ' + body);
|
||||||
|
expect(body).to.be.equal('error: permissionError');
|
||||||
|
expect(response.statusCode).to.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: setBulk(POST) - must set values', function (done) {
|
||||||
|
|
||||||
|
request({
|
||||||
|
uri: 'http://127.0.0.1:18183/setBulk',
|
||||||
|
method: 'POST',
|
||||||
|
body: 'system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false&javascript.0.test=4'
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log('setBulk/?system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false&javascript.0.test=4 => ' + JSON.stringify(body));
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(50);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(obj[1].val).to.be.equal(false);
|
||||||
|
expect(obj[1].id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(obj[2].val).to.be.equal(4);
|
||||||
|
expect(obj[2].id).to.equal('javascript.0.test');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive,javascript.0.test', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive,javascript.0.test => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(50);
|
||||||
|
expect(obj[1].val).equal(false);
|
||||||
|
expect(obj[2].val).equal(4);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: setBulk(POST-GET-Mix) - must set values', function (done) {
|
||||||
|
|
||||||
|
request({
|
||||||
|
uri: 'http://127.0.0.1:18183/setBulk?system.adapter.simple-api.upload=51&system.adapter.simple-api.0.alive=false',
|
||||||
|
method: 'POST',
|
||||||
|
body: ''
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log('setBulk/?system.adapter.simple-api.upload=51&system.adapter.simple-api.0.alive=false => ' + JSON.stringify(body));
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(51);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(obj[1].val).to.be.equal(false);
|
||||||
|
expect(obj[1].id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(51);
|
||||||
|
expect(obj[1].val).equal(false);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API as User: setValueFromBody(POST) - must set one value', function (done) {
|
||||||
|
request({
|
||||||
|
uri: 'http://127.0.0.1:18183/setValueFromBody/system.adapter.simple-api.upload',
|
||||||
|
method: 'POST',
|
||||||
|
body: '55'
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log('setValueFromBody/?system.adapter.simple-api.upload => ' + JSON.stringify(body));
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(55);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('http://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(55);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after('Test RESTful API as User: Stop js-controller', function (done) {
|
||||||
|
this.timeout(6000);
|
||||||
|
setup.stopController(function (normalTerminated) {
|
||||||
|
console.log('Adapter normal terminated: ' + normalTerminated);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
91
test/testPackageFiles.js
Normal file
91
test/testPackageFiles.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/* jshint -W097 */
|
||||||
|
/* jshint strict:false */
|
||||||
|
/* jslint node: true */
|
||||||
|
/* jshint expr: true */
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
describe('Test package.json and io-package.json', function() {
|
||||||
|
it('Test package files', function (done) {
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
|
||||||
|
var ioPackage = JSON.parse(fileContentIOPackage);
|
||||||
|
|
||||||
|
var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
|
||||||
|
var npmPackage = JSON.parse(fileContentNPMPackage);
|
||||||
|
|
||||||
|
expect(ioPackage).to.be.an('object');
|
||||||
|
expect(npmPackage).to.be.an('object');
|
||||||
|
|
||||||
|
expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
|
||||||
|
expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;
|
||||||
|
|
||||||
|
expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);
|
||||||
|
|
||||||
|
if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
|
||||||
|
console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
|
||||||
|
expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;
|
||||||
|
|
||||||
|
if (ioPackage.common.name.indexOf('template') !== 0) {
|
||||||
|
if (Array.isArray(ioPackage.common.authors)) {
|
||||||
|
expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
|
||||||
|
if (ioPackage.common.authors.length === 1) {
|
||||||
|
expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
|
||||||
|
if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
|
||||||
|
console.log('WARNING: titleLang is not existing in io-package.json. Please add');
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
ioPackage.common.title.indexOf('yunkong2') !== -1 ||
|
||||||
|
ioPackage.common.title.indexOf('yunkong2') !== -1 ||
|
||||||
|
ioPackage.common.title.indexOf('adapter') !== -1 ||
|
||||||
|
ioPackage.common.title.indexOf('Adapter') !== -1
|
||||||
|
) {
|
||||||
|
console.log('WARNING: title contains Adapter or yunkong2. It is clear anyway, that it is adapter for yunkong2.');
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioPackage.common.name.indexOf('vis-') !== 0) {
|
||||||
|
if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
|
||||||
|
console.log('WARNING: Admin3 support is missing! Please add it');
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
if (ioPackage.common.materialize) {
|
||||||
|
expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var licenseFileExists = fs.existsSync(__dirname + '/../LICENSE');
|
||||||
|
var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
|
||||||
|
if (fileContentReadme.indexOf('## Changelog') === -1) {
|
||||||
|
console.log('Warning: The README.md should have a section ## Changelog');
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
expect((licenseFileExists || fileContentReadme.indexOf('## License') !== -1), 'A LICENSE must exist as LICENSE file or as part of the README.md').to.be.true;
|
||||||
|
if (!licenseFileExists) {
|
||||||
|
console.log('Warning: The License should also exist as LICENSE file');
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
if (fileContentReadme.indexOf('## License') === -1) {
|
||||||
|
console.log('Warning: The README.md should also have a section ## License to be shown in Admin3');
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
194
test/testSsl.js
Normal file
194
test/testSsl.js
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/* jshint -W097 */// jshint strict:false
|
||||||
|
/*jslint node: true */
|
||||||
|
/*jshint expr: true*/
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var setup = require(__dirname + '/lib/setup');
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
|
var objects = null;
|
||||||
|
var states = null;
|
||||||
|
|
||||||
|
process.env.NO_PROXY = '127.0.0.1';
|
||||||
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||||
|
|
||||||
|
function checkConnectionOfAdapter(cb, counter) {
|
||||||
|
counter = counter || 0;
|
||||||
|
console.log('Try check #' + counter);
|
||||||
|
if (counter > 30) {
|
||||||
|
if (cb) cb('Cannot check connection');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
states.getState('system.adapter.simple-api.0.alive', function (err, state) {
|
||||||
|
if (err) console.error(err);
|
||||||
|
if (state && state.val) {
|
||||||
|
if (cb) cb();
|
||||||
|
} else {
|
||||||
|
setTimeout(function () {
|
||||||
|
checkConnectionOfAdapter(cb, counter + 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Test RESTful API SSL', function() {
|
||||||
|
before('Test RESTful API SSL: Start js-controller', function (_done) {
|
||||||
|
this.timeout(600000); // because of first install from npm
|
||||||
|
setup.adapterStarted = false;
|
||||||
|
|
||||||
|
var brokerStarted = false;
|
||||||
|
setup.setupController(function () {
|
||||||
|
var config = setup.getAdapterConfig();
|
||||||
|
// enable adapter
|
||||||
|
config.common.enabled = true;
|
||||||
|
config.common.loglevel = 'debug';
|
||||||
|
config.native.port = 18183;
|
||||||
|
config.native.auth = true;
|
||||||
|
config.native.secure = true;
|
||||||
|
config.native.certPublic = 'defaultPublic';
|
||||||
|
config.native.certPrivate = 'defaultPrivate';
|
||||||
|
|
||||||
|
setup.setAdapterConfig(config.common, config.native);
|
||||||
|
|
||||||
|
setup.startController(function (_objects, _states) {
|
||||||
|
objects = _objects;
|
||||||
|
states = _states;
|
||||||
|
// give some time to start server
|
||||||
|
setTimeout(function () {
|
||||||
|
_done();
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test adapter: Check if adapter started and create upload datapoint', function (done) {
|
||||||
|
this.timeout(60000);
|
||||||
|
checkConnectionOfAdapter(function (res) {
|
||||||
|
if (res) console.log(res);
|
||||||
|
expect(res).not.to.be.equal('Cannot check connection');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API SSL: get - must return value', function (done) {
|
||||||
|
request('https://127.0.0.1:18183/get/system.adapter.simple-api.0.alive?user=admin&pass=yunkong2', function (error, response, body) {
|
||||||
|
console.log('get/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
//{
|
||||||
|
// "val" : true,
|
||||||
|
// "ack" : true,
|
||||||
|
// "ts" : 1455009717,
|
||||||
|
// "q" : 0,
|
||||||
|
// "from" : "system.adapter.simple-api.0",
|
||||||
|
// "lc" : 1455009717,
|
||||||
|
// "expire" : 30000,
|
||||||
|
// "_id" : "system.adapter.simple-api.0.alive",
|
||||||
|
// "type" : "state",
|
||||||
|
// "common" : {
|
||||||
|
// "name" : "simple-api.0.alive",
|
||||||
|
// "type" : "boolean",
|
||||||
|
// "role" : "indicator.state"
|
||||||
|
// },
|
||||||
|
// "native" : {}
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj.val).to.be.true;
|
||||||
|
expect(obj.ack).to.be.true;
|
||||||
|
expect(obj.ts).to.be.ok;
|
||||||
|
//expect(obj.from).to.equal("system.adapter.simple-api.0");
|
||||||
|
expect(obj.type).to.equal("state");
|
||||||
|
expect(obj._id).to.equal("system.adapter.simple-api.0.alive");
|
||||||
|
expect(obj.common).to.be.ok;
|
||||||
|
expect(obj.native).to.be.ok;
|
||||||
|
expect(obj.common.name).to.equal("simple-api.0.alive");
|
||||||
|
expect(obj.common.role).to.equal("indicator.state");
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API SSL: get with no credentials', function (done) {
|
||||||
|
request('https://127.0.0.1:18183/get/system.adapter.simple-api.0.alive?user=admin&pass=io', function (error, response, body) {
|
||||||
|
console.log('get/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(response.statusCode).to.be.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API SSL: get with wrong credentials', function (done) {
|
||||||
|
request('https://127.0.0.1:18183/get/system.adapter.simple-api.0.alive', function (error, response, body) {
|
||||||
|
console.log('get/system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
expect(response.statusCode).to.be.equal(401);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API SSL: setBulk(POST) - must set values', function (done) {
|
||||||
|
|
||||||
|
request({
|
||||||
|
uri: 'https://127.0.0.1:18183/setBulk?user=admin&pass=yunkong2',
|
||||||
|
method: 'POST',
|
||||||
|
body: 'system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false'
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log('setBulk/?system.adapter.simple-api.upload=50&system.adapter.simple-api.0.alive=false => ' + JSON.stringify(body));
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(50);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(obj[1].val).to.be.equal(false);
|
||||||
|
expect(obj[1].id).to.equal('system.adapter.simple-api.0.alive');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
request('https://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive?user=admin&pass=yunkong2', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload,system.adapter.simple-api.0.alive => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(50);
|
||||||
|
expect(obj[1].val).equal(false);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Test RESTful API SSL: setValueFromBody(POST) - must set values', function (done) {
|
||||||
|
request({
|
||||||
|
uri: 'https://127.0.0.1:18183/setValueFromBody/system.adapter.simple-api.upload?user=admin&pass=yunkong2&',
|
||||||
|
method: 'POST',
|
||||||
|
body: '55'
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log('setValueFromBody/?system.adapter.simple-api.upload => ' + JSON.stringify(body));
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj).to.be.ok;
|
||||||
|
expect(obj[0].val).to.be.equal(55);
|
||||||
|
expect(obj[0].id).to.equal('system.adapter.simple-api.upload');
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
|
||||||
|
body = "";
|
||||||
|
request('https://127.0.0.1:18183/getBulk/system.adapter.simple-api.upload?user=admin&pass=yunkong2', function (error, response, body) {
|
||||||
|
console.log('getBulk/system.adapter.simple-api.upload => ' + body);
|
||||||
|
expect(error).to.be.not.ok;
|
||||||
|
var obj = JSON.parse(body);
|
||||||
|
expect(obj[0].val).equal(55);
|
||||||
|
expect(response.statusCode).to.equal(200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
after('Test RESTful API SSL: Stop js-controller', function (done) {
|
||||||
|
this.timeout(6000);
|
||||||
|
setup.stopController(function (normalTerminated) {
|
||||||
|
console.log('Adapter normal terminated: ' + normalTerminated);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user