iobroker.rest-api 1.0.1 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,6 +73,7 @@ You cannot send POST request to commands via GUI.
73
73
  <!-- START -->
74
74
  ### States
75
75
  - `getStates(pattern)` - get the list of states for pattern (e.g. for system.adapter.admin.0.*). GUI can have problems by visualization of answer.
76
+ - `getForeignStates(pattern)` - same as getStates
76
77
  - `getState(id)` - get state value by ID
77
78
  - `setState(id, state)` - set state value with JSON object (e.g. `{"val": 1, "ack": true}`)
78
79
  - `getBinaryState(id)` - get binary state by ID
@@ -115,6 +116,7 @@ You cannot send POST request to commands via GUI.
115
116
  - `getCompactAdapters()` - read list of installed adapters with short information
116
117
  - `getCompactInstalled(host)` - read short information about installed adapters
117
118
  - `getCompactSystemConfig()` - read short system config
119
+ - `getCompactSystemRepositories()`
118
120
  - `getCompactRepository(host)` - read short repository
119
121
  - `getCompactHosts()` - get short information about hosts
120
122
  - `addUser(user, pass)` - add new user
@@ -125,7 +127,6 @@ You cannot send POST request to commands via GUI.
125
127
  - `getAllObjects()` - read all objects as list. GUI can have problems by visualization of answer.
126
128
  - `extendObject(id, obj)` - modify object by ID with JSON. (.e.g. `{"common":{"enabled": true}}`)
127
129
  - `getForeignObjects(pattern, type)` - same as getObjects
128
- - `getForeignStates(pattern)` - same as getStates
129
130
  - `delObjects(id, options)` - delete objects by pattern
130
131
 
131
132
  ### Others
@@ -140,12 +141,25 @@ You cannot send POST request to commands via GUI.
140
141
  - `getAdapterInstances(adapterName)` - get objects of type "instance". You can define optionally adapterName
141
142
 
142
143
  <!-- END -->
144
+
145
+ ## Todo
146
+ - [ ] Implement GET,PATCH,POST,DELETE file operations
147
+
143
148
  <!--
144
149
  Placeholder for the next version (at the beginning of the line):
145
150
  ### **WORK IN PROGRESS**
146
151
  -->
147
152
 
148
153
  ## Changelog
154
+ ### 1.0.5 (2023-03-27)
155
+ * (Apollon77) Prepare for future js-controller versions
156
+
157
+ ### 1.0.4 (2022-08-31)
158
+ * (bluefox) Check if the port is occupied only on defined interface
159
+
160
+ ### 1.0.2 (2022-07-27)
161
+ * (bluefox) Implemented binary read/write operations
162
+
149
163
  ### 1.0.1 (2022-07-27)
150
164
  * (bluefox) Increased the max size of body to 100Mb
151
165
 
@@ -179,4 +193,4 @@ You cannot send POST request to commands via GUI.
179
193
  ## License
180
194
  Apache 2.0
181
195
 
182
- Copyright (c) 2017-2022 bluefox <dogafox@gmail.com>
196
+ Copyright (c) 2017-2023 bluefox <dogafox@gmail.com>
package/io-package.json CHANGED
@@ -1,8 +1,45 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "rest-api",
4
- "version": "1.0.1",
4
+ "version": "1.0.5",
5
5
  "news": {
6
+ "1.0.5": {
7
+ "en": "Prepare for future js-controller versions",
8
+ "de": "Bereiten Sie sich auf zukünftige js-Controller-Versionen",
9
+ "ru": "Подготовьтесь к будущим версиям js-controller",
10
+ "pt": "Prepare-se para futuras versões js-controller",
11
+ "nl": "Bereid je voor op toekomstige Js-controller versie",
12
+ "fr": "Préparez-vous pour les versions futures de js-controller",
13
+ "it": "Prepararsi per le future versioni js-controller",
14
+ "es": "Prepararse para futuras versiones js-controller",
15
+ "pl": "Prepare for future js-controller version",
16
+ "uk": "Підготовка до майбутніх версій js-controller",
17
+ "zh-cn": "今后防污版本的编制"
18
+ },
19
+ "1.0.4": {
20
+ "en": "Check if the port is occupied only on defined interface",
21
+ "de": "Überprüfen Sie, ob der Port nur auf definierter Schnittstelle besetzt ist",
22
+ "ru": "Проверьте, занят ли порт только на определенном интерфейсе",
23
+ "pt": "Verifique se a porta está ocupada apenas na interface definida",
24
+ "nl": "Controleer of de haven alleen bezet is op definitieve interface",
25
+ "fr": "Vérifiez si le port n'est occupé que sur l'interface définie",
26
+ "it": "Controllare se la porta è occupata solo su interfaccia definita",
27
+ "es": "Compruebe si el puerto está ocupado sólo en la interfaz definida",
28
+ "pl": "Jeśli port jest zajęty tylko na określonym interfejsie",
29
+ "zh-cn": "如果港口只在界定的界线上被占有,则该港口将被扣押。"
30
+ },
31
+ "1.0.2": {
32
+ "en": "Implemented binary read/write operations",
33
+ "de": "Implementierung binärer Schreib-/Lesevorgänge",
34
+ "ru": "Внедренные бинарные чтения / записи операции",
35
+ "pt": "Operações de leitura/escrita binárias implementadas",
36
+ "nl": "Geïmplementeerde binaire las/schrijf operaties",
37
+ "fr": "Opérations de lecture/écriture binaires mises en œuvre",
38
+ "it": "Operazioni di lettura/scrittura binarie implementate",
39
+ "es": "Operaciones de lectura y escritura binarias aplicadas",
40
+ "pl": "Poprawianie binarnego odczytu/pisania operacji",
41
+ "zh-cn": "执行本文的文字/仪式作业"
42
+ },
6
43
  "1.0.1": {
7
44
  "en": "Increased the max size of body to 100Mb",
8
45
  "de": "Erhöht die maximale Körpergröße auf 100Mb",
@@ -50,42 +87,6 @@
50
87
  "es": "Se corrigieron algunos errores de acceso",
51
88
  "pl": "Poprawiono niektóre błędy dostępu",
52
89
  "zh-cn": "一些访问错误已得到纠正"
53
- },
54
- "0.4.0": {
55
- "en": "Added socket commands",
56
- "de": "Socket-Befehle hinzugefügt",
57
- "ru": "Добавлены команды сокета",
58
- "pt": "Comandos de soquete adicionados",
59
- "nl": "Socket-opdrachten toegevoegd",
60
- "fr": "Commandes de socket ajoutées",
61
- "it": "Aggiunti comandi socket",
62
- "es": "Comandos de socket agregados",
63
- "pl": "Dodano polecenia dotyczące gniazd",
64
- "zh-cn": "添加了套接字命令"
65
- },
66
- "0.3.6": {
67
- "en": "Added object creation and enumerations reading",
68
- "de": "Objekterstellung und Lesen von Aufzählungen hinzugefügt",
69
- "ru": "Добавлено создание объектов и чтение перечислений",
70
- "pt": "Adicionado criação de objetos e leitura de enumerações",
71
- "nl": "Toegevoegd objectcreatie en opsommingen lezen",
72
- "fr": "Ajout de la création d'objets et de la lecture des énumérations",
73
- "it": "Aggiunta creazione di oggetti e lettura di enumerazioni",
74
- "es": "Añadida creación de objetos y lectura de enumeraciones.",
75
- "pl": "Dodano tworzenie obiektów i odczytywanie wyliczeń",
76
- "zh-cn": "添加了对象创建和枚举读取"
77
- },
78
- "0.3.5": {
79
- "en": "Allowed the reading of current subscriptions",
80
- "de": "Erlaubt das Lesen aktueller Abonnements",
81
- "ru": "Разрешено чтение текущих подписок",
82
- "pt": "Permitiu a leitura de assinaturas atuais",
83
- "nl": "Lezen van huidige abonnementen toegestaan",
84
- "fr": "Autorisé la lecture des abonnements en cours",
85
- "it": "Consentita la lettura degli abbonamenti in corso",
86
- "es": "Permitida la lectura de suscripciones vigentes",
87
- "pl": "Umożliwił czytanie aktualnych subskrypcji",
88
- "zh-cn": "允许阅读当前订阅"
89
90
  }
90
91
  },
91
92
  "title": "REST API",
@@ -31,7 +31,7 @@ function findState(adapter, idOrName, user, type, callback) {
31
31
  callback = type;
32
32
  type = null;
33
33
  }
34
- adapter.findForeignObject(idOrName, type, {user: user, checked: true, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, callback);
34
+ adapter.findForeignObject(idOrName, type, {user, checked: true, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, callback);
35
35
  }
36
36
 
37
37
  function getState(adapter, idOrName, user, type, callback) {
@@ -48,7 +48,7 @@ function getState(adapter, idOrName, user, type, callback) {
48
48
  id = idOrName;
49
49
  }
50
50
  if (id) {
51
- adapter.getForeignState(id, {user: user, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, (err, state) => {
51
+ adapter.getForeignState(id, {user, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, (err, state) => {
52
52
  if (err || !state) {
53
53
  state = undefined;
54
54
  }
@@ -61,6 +61,42 @@ function getState(adapter, idOrName, user, type, callback) {
61
61
  });
62
62
  }
63
63
 
64
+ function getBinaryState(adapter, idOrName, user, type, callback) {
65
+ if (typeof type === 'function') {
66
+ callback = type;
67
+ type = null;
68
+ }
69
+ findState(adapter, idOrName, user, type, (err, id, originId) => {
70
+ if (err && (!err.message || !err.message.includes('permissionError'))) {
71
+ callback && callback(err, undefined, null, originId);
72
+ } else {
73
+ if (err && err.message.includes('permissionError')) {
74
+ // assume it is ID
75
+ id = idOrName;
76
+ }
77
+ if (id) {
78
+ if (adapter.getForeignBinaryState) {
79
+ adapter.getForeignBinaryState(id, {user, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, (err, binary) => {
80
+ if (err) {
81
+ binary = undefined;
82
+ }
83
+ callback && callback (err, binary, id, originId);
84
+ });
85
+ } else {
86
+ adapter.getBinaryState(id, {user, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, (err, binary) => {
87
+ if (err) {
88
+ binary = undefined;
89
+ }
90
+ callback && callback (err, binary, id, originId);
91
+ });
92
+ }
93
+ } else {
94
+ callback && callback(null, undefined, null, originId);
95
+ }
96
+ }
97
+ });
98
+ }
99
+
64
100
  function parseUrl(url, swagger, webExtensionPrefix) {
65
101
  // "/v1/object/adapter.system.admin.0.alive"
66
102
  const parts = url.split('?')[0].split('/');
@@ -108,6 +144,7 @@ module.exports = {
108
144
  checkPermissions,
109
145
  findState,
110
146
  getState,
147
+ getBinaryState,
111
148
  parseUrl,
112
149
  errorResponse,
113
150
  };
@@ -1,120 +1,123 @@
1
1
  'use strict';
2
2
  const commonLib = require('./common.js');
3
3
 
4
- module.exports = {
5
- sendTo: function (req, res) {
6
- commonLib.checkPermissions(req._adapter, req._user, [{type: 'other', operation: 'sendto'}], async error => {
7
- if (error) {
8
- commonLib.errorResponse(req, res, error);
9
- } else {
10
- const params = commonLib.parseUrl(req.url, req.swagger, req._adapter.WEB_EXTENSION_PREFIX);
11
- let message = req.query.message;
12
- let noResponse = req.query.noResponse;
13
- let timeout = req.query.timeout;
14
- let data = req.query.data;
15
- if (req.body && req.body.message) {
16
- message = req.query.message;
17
- }
18
- if (req.body && req.body.timeout) {
19
- timeout = req.query.timeout;
20
- }
21
- timeout = parseInt(timeout, 10) || 10000;
22
- if (req.body && req.body.noResponse !== undefined) {
23
- noResponse = req.query.noResponse;
24
- }
25
- noResponse = noResponse === 'true';
4
+ function sendTo(req, res) {
5
+ commonLib.checkPermissions(req._adapter, req._user, [{type: 'other', operation: 'sendto'}], async error => {
6
+ if (error) {
7
+ commonLib.errorResponse(req, res, error);
8
+ } else {
9
+ const params = commonLib.parseUrl(req.url, req.swagger, req._adapter.WEB_EXTENSION_PREFIX);
10
+ let message = req.query.message;
11
+ let noResponse = req.query.noResponse;
12
+ let timeout = req.query.timeout;
13
+ let data = req.query.data;
14
+ if (req.body && req.body.message) {
15
+ message = req.query.message;
16
+ }
17
+ if (req.body && req.body.timeout) {
18
+ timeout = req.query.timeout;
19
+ }
20
+ timeout = parseInt(timeout, 10) || 10000;
21
+ if (req.body && req.body.noResponse !== undefined) {
22
+ noResponse = req.query.noResponse;
23
+ }
24
+ noResponse = noResponse === 'true';
26
25
 
27
- if (req.body && req.body.data !== undefined) {
28
- data = req.query.data;
29
- } else {
30
- if (data !== undefined && data !== null) {
31
- if (data === 'null') {
32
- data = null;
33
- } else if (data === 'undefined') {
34
- data = undefined;
35
- } else if (data === 'true') {
36
- data = true;
37
- } else if (data === 'false') {
38
- data = false;
39
- } else if (isFinite(data)) {
40
- data = parseFloat(data);
41
- } else if (data.startsWith('{') && data.endsWith('}')) {
42
- try {
43
- data = JSON.parse(data);
44
- } catch (error) {
45
- // ignore
46
- }
47
- } else if (data.startsWith('[') && data.endsWith(']')) {
48
- try {
49
- data = JSON.parse(data);
50
- } catch (error) {
51
- // ignore
52
- }
26
+ if (req.body && req.body.data !== undefined) {
27
+ data = req.query.data;
28
+ } else {
29
+ if (data !== undefined && data !== null) {
30
+ if (data === 'null') {
31
+ data = null;
32
+ } else if (data === 'undefined') {
33
+ data = undefined;
34
+ } else if (data === 'true') {
35
+ data = true;
36
+ } else if (data === 'false') {
37
+ data = false;
38
+ } else if (isFinite(data)) {
39
+ data = parseFloat(data);
40
+ } else if (data.startsWith('{') && data.endsWith('}')) {
41
+ try {
42
+ data = JSON.parse(data);
43
+ } catch (error) {
44
+ // ignore
45
+ }
46
+ } else if (data.startsWith('[') && data.endsWith(']')) {
47
+ try {
48
+ data = JSON.parse(data);
49
+ } catch (error) {
50
+ // ignore
53
51
  }
54
52
  }
55
53
  }
56
- const instance = params.instance;
54
+ }
55
+ const instance = params.instance;
57
56
 
58
- if (!instance) {
59
- res
60
- .status(422)
61
- .json({error: 'No instance provided'});
62
- return;
63
- }
64
- if (!message) {
65
- res
66
- .status(422)
67
- .json({error: 'No message provided'});
68
- return;
69
- }
57
+ if (!instance) {
58
+ res
59
+ .status(422)
60
+ .json({error: 'No instance provided'});
61
+ return;
62
+ }
63
+ if (!message) {
64
+ res
65
+ .status(422)
66
+ .json({error: 'No message provided'});
67
+ return;
68
+ }
70
69
 
71
- // check if instance is alive
72
- let state;
73
- try {
74
- state = await req._adapter.getForeignStateAsync(`system.adapter.${instance}.alive`);
75
- if (!state || !state.val) {
76
- res
77
- .status(500)
78
- .json({error: 'instance is not online', instance});
79
- return;
80
- }
81
- } catch (error) {
70
+ // check if instance is alive
71
+ let state;
72
+ try {
73
+ state = await req._adapter.getForeignStateAsync(`system.adapter.${instance}.alive`);
74
+ if (!state || !state.val) {
82
75
  res
83
76
  .status(500)
84
- .json({error: 'invalid instance', instance});
77
+ .json({error: 'instance is not online', instance});
85
78
  return;
86
79
  }
87
- if (noResponse) {
88
- req._adapter.sendTo(instance, message, data);
89
- res.json({result: 'sent'});
90
- } else {
91
- let timer;
92
- let answerDone = false;
93
- if (timeout) {
94
- timer = setTimeout(() => {
95
- timer = null;
96
- if (!answerDone) {
97
- answerDone = true;
98
- res.status(408).json({error: 'timeout'});
99
- }
100
- }, timeout);
101
- }
102
-
103
- req._adapter.sendTo(instance, message, data, (result, result1) => {
104
- timer && clearTimeout(timer);
80
+ } catch (error) {
81
+ res
82
+ .status(500)
83
+ .json({error: 'invalid instance', instance});
84
+ return;
85
+ }
86
+ if (noResponse) {
87
+ req._adapter.sendTo(instance, message, data);
88
+ res.json({result: 'sent'});
89
+ } else {
90
+ let timer;
91
+ let answerDone = false;
92
+ if (timeout) {
93
+ timer = setTimeout(() => {
94
+ timer = null;
105
95
  if (!answerDone) {
106
96
  answerDone = true;
107
- if (!result && result1) {
108
- res.json(result1);
109
- } else if (result && !result1) {
110
- res.json(result);
111
- } else {
112
- res.json({error: result, result: result1});
113
- }
97
+ res.status(408).json({error: 'timeout'});
114
98
  }
115
- });
99
+ }, timeout);
116
100
  }
101
+
102
+ req._adapter.sendTo(instance, message, data, (result, result1) => {
103
+ timer && clearTimeout(timer);
104
+ if (!answerDone) {
105
+ answerDone = true;
106
+ if (!result && result1) {
107
+ res.json(result1);
108
+ } else if (result && !result1) {
109
+ res.json(result);
110
+ } else {
111
+ res.json({error: result, result: result1});
112
+ }
113
+ }
114
+ });
117
115
  }
118
- });
119
- },
116
+ }
117
+ });
118
+ }
119
+
120
+ module.exports = {
121
+ sendToPost: sendTo,
122
+ sendTo: sendTo,
120
123
  };
@@ -295,6 +295,101 @@ module.exports = {
295
295
  });
296
296
  },
297
297
 
298
+ readBinaryState: function (req, res) {
299
+ commonLib.checkPermissions(req._adapter, req._user, [{type: 'state', operation: 'read'}], async error => {
300
+ if (error) {
301
+ commonLib.errorResponse(req, res, error);
302
+ } else {
303
+ const params = commonLib.parseUrl(req.url, req.swagger, req._adapter.WEB_EXTENSION_PREFIX);
304
+ const oId = getIDs(params.stateId)[0];
305
+
306
+ let result;
307
+ let foundID;
308
+ try {
309
+ const {binary, id, originId} = await new Promise((resolve, reject) => commonLib.getBinaryState(req._adapter, oId, req._user, (error, binary, id) =>
310
+ error ? reject(error) : resolve({binary, id})));
311
+
312
+ if (!id) {
313
+ res.status(404).json({error: 'ID not found', id: originId});
314
+ return;
315
+ }
316
+ result = binary;
317
+ foundID = id;
318
+ } catch (error) {
319
+ req._adapter.log.warn(`Cannot read ${oId}: ${error}`);
320
+ commonLib.errorResponse(req, res, error, {id: oId});
321
+ return;
322
+ }
323
+
324
+ // try to detect popular content types
325
+ foundID = foundID.toLowerCase()
326
+ if (foundID.endsWith('.png')) {
327
+ res.setHeader('Content-Type', 'image/png');
328
+ } else if (foundID.endsWith('.jpg')) {
329
+ res.setHeader('Content-Type', 'image/jpeg');
330
+ } else if (foundID.endsWith('.svg')) {
331
+ res.setHeader('Content-Type', 'image/svg+xml');
332
+ } else if (foundID.endsWith('.txt')) {
333
+ res.setHeader('Content-Type', 'text/plain');
334
+ } else if (foundID.endsWith('.json')) {
335
+ res.setHeader('Content-Type', 'application/json');
336
+ } else if (foundID.endsWith('.mp3')) {
337
+ res.setHeader('Content-Type', 'audio/mpeg');
338
+ } else if (foundID.endsWith('.wav')) {
339
+ res.setHeader('Content-Type', 'audio/wav');
340
+ } else if (foundID.endsWith('.ogg')) {
341
+ res.setHeader('Content-Type', 'audio/ogg');
342
+ } else {
343
+ res.setHeader('Content-Type', 'application/octet-stream');
344
+ }
345
+
346
+ res.send(result);
347
+ }
348
+ });
349
+ },
350
+
351
+ writeBinaryState: function (req, res) {
352
+ commonLib.checkPermissions(req._adapter, req._user, [{type: 'state', operation: 'write'}], error => {
353
+ if (error) {
354
+ commonLib.errorResponse(req, res, error);
355
+ } else {
356
+ const params = commonLib.parseUrl(req.url, req.swagger, req._adapter.WEB_EXTENSION_PREFIX);
357
+ const oId = getIDs(params.stateId)[0];
358
+
359
+ commonLib.findState(req._adapter, oId, req._user, async (error, id, originId) => {
360
+ if (error && error.message && error.message.includes('permissionError')) {
361
+ // assume it is ID
362
+ id = oId;
363
+ error = null;
364
+ }
365
+
366
+ if (error) {
367
+ commonLib.errorResponse(req, res, error, {id: oId});
368
+ } else if (!id) {
369
+ res.status(404).json({error: 'ID not found', id: oId});
370
+ } else {
371
+ try {
372
+ const obj = await req._adapter.getForeignObjectAsync(id, {user: req._user, limitToOwnerRights: req._adapter.config.onlyAllowWhenUserIsOwner});
373
+ if (obj && obj.common && obj.common.type === 'file') {
374
+ if (req._adapter.setForeignBinaryStateAsync) {
375
+ await req._adapter.setForeignBinaryStateAsync(id, req.body, {user: req._user, limitToOwnerRights: req._adapter.config.onlyAllowWhenUserIsOwner});
376
+ } else {
377
+ await req._adapter.setBinaryStateAsync(id, req.body, {user: req._user, limitToOwnerRights: req._adapter.config.onlyAllowWhenUserIsOwner});
378
+ }
379
+ res.status(200).json({result: 'ok', id});
380
+ } else {
381
+ res.status(422).json({error: 'State is not binary', id});
382
+ }
383
+ } catch (error) {
384
+ req._adapter.log.warn(`Cannot read object ${id}: ${error.toString()}`);
385
+ res.status(401).json({error: `Cannot read object ${id}: ${error.toString()}`, id});
386
+ }
387
+ }
388
+ });
389
+ }
390
+ });
391
+ },
392
+
298
393
  plainState: function (req, res) {
299
394
  commonLib.checkPermissions(req._adapter, req._user, [{type: 'state', operation: 'read'}], async error => {
300
395
  if (error) {
@@ -2,7 +2,7 @@
2
2
  swagger: "2.0"
3
3
  info:
4
4
  description: "This is a REST server for ioBroker."
5
- version: "1.0.1"
5
+ version: "1.0.5"
6
6
  title: "ioBroker Swagger UI"
7
7
  contact:
8
8
  email: "admin@iobroker.net"
@@ -16,6 +16,8 @@ basePath: "/v1"
16
16
  tags:
17
17
  - name: "state"
18
18
  description: "Read, write the states"
19
+ - name: "binary"
20
+ description: "Read, write the binary states"
19
21
  - name: "object"
20
22
  description: "Read the objects"
21
23
  - name: "history"
@@ -94,6 +96,12 @@ paths:
94
96
  required: false
95
97
  type: "integer"
96
98
  format: "int64"
99
+ - in: "body"
100
+ required: true
101
+ name: "data"
102
+ description: "State object to write"
103
+ schema:
104
+ $ref: "#/definitions/WriteState"
97
105
  responses:
98
106
  200:
99
107
  description: "successful operation"
@@ -105,6 +113,7 @@ paths:
105
113
  description: "State not found"
106
114
  405:
107
115
  description: "Invalid value"
116
+
108
117
  /state/{stateId}/toggle:
109
118
  x-swagger-router-controller: state
110
119
  get:
@@ -262,6 +271,63 @@ paths:
262
271
  description: "State not found"
263
272
  400:
264
273
  description: "Invalid state ID supplied"
274
+ /binary/{stateId}:
275
+ x-swagger-router-controller: state
276
+ get:
277
+ tags:
278
+ - "binary"
279
+ summary: "Read value of the binary state as stream"
280
+ operationId: "readBinaryState"
281
+ produces:
282
+ - "application/octet-stream"
283
+ parameters:
284
+ - name: "stateId"
285
+ in: "path"
286
+ description: "ID of the state to return"
287
+ required: true
288
+ type: "string"
289
+
290
+ responses:
291
+ 200:
292
+ description: "successful operation"
293
+ 404:
294
+ description: "State not found"
295
+ 400:
296
+ description: "Invalid state ID supplied"
297
+ patch:
298
+ tags:
299
+ - "binary"
300
+ summary: "Update the value of the state"
301
+ description: ""
302
+ operationId: "writeBinaryState"
303
+ consumes:
304
+ - "application/octet-stream"
305
+ produces:
306
+ - "application/json"
307
+ parameters:
308
+ - in: "path"
309
+ name: "stateId"
310
+ description: "ID of the state to write"
311
+ required: true
312
+ type: "string"
313
+ - in: "body"
314
+ required: true
315
+ name: "data"
316
+ description: "Binary data to write"
317
+ schema:
318
+ type: string
319
+ format: binary
320
+ responses:
321
+ 200:
322
+ description: "successful operation"
323
+ schema:
324
+ $ref: "#/definitions/State"
325
+ 400:
326
+ description: "Invalid state ID supplied"
327
+ 404:
328
+ description: "State not found"
329
+ 405:
330
+ description: "Invalid value"
265
331
  /states:
266
332
  x-swagger-router-controller: state
267
333
  get:
@@ -456,7 +522,7 @@ paths:
456
522
  - "object"
457
523
  summary: "Delete object"
458
524
  description: ""
459
- operationId: "deletedObject"
525
+ operationId: "deleteObject"
460
526
  produces:
461
527
  - "application/json"
462
528
  parameters:
@@ -559,9 +625,7 @@ paths:
559
625
  200:
560
626
  description: "successful operation"
561
627
  schema:
562
- type: array
563
- items:
564
- $ref: "#/definitions/Object"
628
+ $ref: "#/definitions/ObjectArray"
565
629
  404:
566
630
  description: "URL or session not found"
567
631
  422:
@@ -905,7 +969,7 @@ paths:
905
969
  - "sendTo"
906
970
  summary: "Send message to instance as POST"
907
971
  description: "You can send message to instance that supports it"
908
- operationId: "sendTo"
972
+ operationId: "sendToPost"
909
973
  consumes:
910
974
  - "application/json"
911
975
  produces:
@@ -950,6 +1014,23 @@ paths:
950
1014
  responses:
951
1015
  200:
952
1016
  description: "successful operation"
1017
+ /command/getForeignStates:
1018
+ get:
1019
+ tags:
1020
+ - "commands"
1021
+ summary: "same as getStates"
1022
+ produces:
1023
+ - "application/json"
1024
+ parameters:
1025
+
1026
+ - name: "pattern"
1027
+ in: "query"
1028
+ description: ""
1029
+ type: "string"
1030
+ required: true
1031
+ responses:
1032
+ 200:
1033
+ description: "successful operation"
953
1034
  /command/getState:
954
1035
  get:
955
1036
  tags:
@@ -1691,6 +1772,16 @@ paths:
1691
1772
  responses:
1692
1773
  200:
1693
1774
  description: "successful operation"
1775
+ /command/getCompactSystemRepositories:
1776
+ get:
1777
+ tags:
1778
+ - "commands"
1779
+ summary: ""
1780
+ produces:
1781
+ - "application/json"
1782
+ responses:
1783
+ 200:
1784
+ description: "successful operation"
1694
1785
  /command/getCompactRepository:
1695
1786
  get:
1696
1787
  tags:
@@ -1883,23 +1974,6 @@ paths:
1883
1974
  responses:
1884
1975
  200:
1885
1976
  description: "successful operation"
1886
- /command/getForeignStates:
1887
- get:
1888
- tags:
1889
- - "commands"
1890
- summary: "same as getStates"
1891
- produces:
1892
- - "application/json"
1893
- parameters:
1894
-
1895
- - name: "pattern"
1896
- in: "query"
1897
- description: ""
1898
- type: "string"
1899
- required: true
1900
- responses:
1901
- 200:
1902
- description: "successful operation"
1903
1977
  /command/delObjects:
1904
1978
  get:
1905
1979
  tags:
@@ -2082,7 +2156,6 @@ definitions:
2082
2156
  type: "string"
2083
2157
  description: "ID of the state"
2084
2158
  val:
2085
- type: "string"
2086
2159
  description: "Actual value"
2087
2160
  q:
2088
2161
  type: "integer"
@@ -2114,6 +2187,29 @@ definitions:
2114
2187
  native:
2115
2188
  type: "object"
2116
2189
  description: "Native state description"
2190
+ WriteState:
2191
+ type: "object"
2192
+ properties:
2193
+ val:
2194
+ description: "Actual value"
2195
+ q:
2196
+ type: "integer"
2197
+ format: "int32"
2198
+ description: "Quality"
2199
+ ts:
2200
+ type: "integer"
2201
+ format: "int64"
2202
+ description: "Timestamp in ms from epoch of last update"
2203
+ lc:
2204
+ type: "integer"
2205
+ format: "int64"
2206
+ description: "Timestamp in ms from epoch of last value change"
2207
+ ack:
2208
+ type: "boolean"
2209
+ description: "Is acknowledged. true = update, false = command"
2210
+ expire:
2211
+ type: "integer"
2212
+ description: "Expire in seconds"
2117
2213
  #Type:
2118
2214
  # type: "string"
2119
2215
  # enum: [state, channel, device, enum, instance, adapter, host, chart, script, folder]
@@ -2133,6 +2229,10 @@ definitions:
2133
2229
  native:
2134
2230
  type: "object"
2135
2231
  description: "Native state description"
2232
+ ObjectArray:
2233
+ type: "object"
2234
+ additionalProperties:
2235
+ $ref: "#/definitions/Object"
2136
2236
  UrlHook:
2137
2237
  type: "object"
2138
2238
  properties:
@@ -2227,7 +2327,6 @@ definitions:
2227
2327
  type: "object"
2228
2328
  properties:
2229
2329
  val:
2230
- type: "number"
2231
2330
  description: "Value"
2232
2331
  ts:
2233
2332
  type: "number"
@@ -2252,7 +2351,6 @@ definitions:
2252
2351
  type: "object"
2253
2352
  properties:
2254
2353
  val:
2255
- type: "number"
2256
2354
  description: "Value"
2257
2355
  ts:
2258
2356
  type: "number"
package/lib/rest-api.js CHANGED
@@ -14,7 +14,7 @@ const cors = require('cors');
14
14
  const fs = require('fs');
15
15
  const path = require('path');
16
16
  const utils = require('@iobroker/adapter-core'); // Get common adapter utils
17
- const tools = require(utils.controllerDir + '/lib/tools');
17
+ const pattern2RegEx = utils.commonTools.pattern2RegEx;
18
18
  const CommandsAdmin = require('@iobroker/socket-classes').SocketCommandsAdmin;
19
19
  const CommandsCommon = require('@iobroker/socket-classes').SocketCommands;
20
20
  const common = require('./common');
@@ -258,9 +258,28 @@ function SwaggerUI(_ignore, webSettings, adapter, instanceSettings, app, callbac
258
258
 
259
259
  // enable cors only if standalone
260
260
  !instanceSettings && this.app.use(cors());
261
- this.app.use(bodyParser.json({
261
+ const jsonParser = bodyParser.json({
262
+ limit: '100mb',
263
+ });
264
+ const rawParser = bodyParser.raw({
265
+ limit: '100mb',
266
+ });
267
+
268
+ this.app.use((req, res, next) => {
269
+ if (req.method !== 'GET' && req.url.startsWith('/v1/binary/')) {
270
+ rawParser(req, res, next);
271
+ } else {
272
+ jsonParser(req, res, next);
273
+ }
274
+ });
275
+ /*this.app.use(bodyParser.json({
262
276
  limit: '100mb',
263
277
  }));
278
+ this.app.use(bodyParser.urlencoded({
279
+ extended: true,
280
+ parameterLimit: 100000,
281
+ limit: '100mb',
282
+ }));*/
264
283
 
265
284
  const _options = {
266
285
  appRoot: __dirname,
@@ -514,7 +533,7 @@ function SwaggerUI(_ignore, webSettings, adapter, instanceSettings, app, callbac
514
533
  const item = {id, delta: options.delta, onchange: options.onchange};
515
534
  this.subscribes[urlHash][type].push(item);
516
535
  if (item.id.includes('*')) {
517
- item.regEx = new RegExp(tools.pattern2RegEx(item.id));
536
+ item.regEx = new RegExp(pattern2RegEx(item.id));
518
537
  }
519
538
 
520
539
  if (type === 'state') {
package/main.js CHANGED
@@ -4,7 +4,7 @@
4
4
  'use strict';
5
5
 
6
6
  const utils = require('@iobroker/adapter-core'); // Get common adapter utils
7
- const LE = require(utils.controllerDir + '/lib/letsencrypt.js');
7
+ const LE = utils.commonTools.letsEncrypt;
8
8
  const RestAPI = require('./lib/rest-api.js');
9
9
  const adapterName = require('./package.json').name.split('.').pop();
10
10
 
@@ -137,14 +137,14 @@ function initWebServer(settings, callback) {
137
137
  }
138
138
  });
139
139
 
140
- adapter.getPort(settings.port, port => {
140
+ adapter.getPort(settings.port, (!settings.bind || settings.bind === '0.0.0.0') ? undefined : settings.bind || undefined, port => {
141
141
  if (port !== settings.port && !adapter.config.findNextPort) {
142
142
  adapter.log.error(`port ${settings.port} already in use`);
143
143
  process.exit(1);
144
144
  }
145
145
  serverPort = port;
146
146
 
147
- server.server.listen(port, async () => {
147
+ server.server.listen(port, (!settings.bind || settings.bind === '0.0.0.0') ? undefined : settings.bind || undefined, async () => {
148
148
  await adapter.setStateAsync('info.connection', true, true);
149
149
  adapter.log.info(`http${settings.secure ? 's' : ''} server listening on port ${port}`);
150
150
  serverListening = true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.rest-api",
3
- "version": "1.0.1",
3
+ "version": "1.0.5",
4
4
  "description": "RESTful interface for ioBroker with GUI.",
5
5
  "author": {
6
6
  "name": "bluefox",
@@ -19,27 +19,28 @@
19
19
  "url": "https://github.com/ioBroker/ioBroker.rest-api"
20
20
  },
21
21
  "dependencies": {
22
- "@iobroker/adapter-core": "^2.6.0",
23
- "@iobroker/socket-classes": "^0.5.0",
24
- "axios": "^0.27.2",
25
- "body-parser": "^1.20.0",
22
+ "@iobroker/adapter-core": "^2.6.7",
23
+ "@iobroker/socket-classes": "^1.1.5",
24
+ "axios": "^1.3.4",
25
+ "body-parser": "^1.20.2",
26
26
  "cors": "^2.8.5",
27
- "express": "^4.18.1",
27
+ "express": "^4.18.2",
28
28
  "swagger-node-runner-fork": "^0.8.0",
29
- "swagger-ui-express": "^4.5.0",
29
+ "swagger-ui-express": "^4.6.2",
30
30
  "yamljs": "^0.3.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@alcalzone/release-script": "^3.5.9",
34
34
  "@alcalzone/release-script-plugin-iobroker": "^3.5.9",
35
35
  "@alcalzone/release-script-plugin-license": "^3.5.9",
36
- "@iobroker/testing": "^3.0.2",
37
- "chai": "^4.3.6",
36
+ "@iobroker/adapter-dev": "^1.2.0",
37
+ "@iobroker/testing": "^4.1.0",
38
+ "chai": "^4.3.7",
38
39
  "eslint-plugin-eqeqeq-fix": "^1.0.3",
39
- "eslint-plugin-only-warn": "^1.0.3",
40
- "eslint-plugin-react": "^7.30.1",
40
+ "eslint-plugin-only-warn": "^1.1.0",
41
+ "eslint-plugin-react": "^7.32.2",
41
42
  "gulp": "^4.0.2",
42
- "mocha": "^9.2.2"
43
+ "mocha": "^10.2.0"
43
44
  },
44
45
  "bugs": {
45
46
  "url": "https://github.com/ioBroker/ioBroker.rest-api/issues"
@@ -60,7 +61,8 @@
60
61
  "release": "release-script",
61
62
  "release-patch": "release-script patch --yes --no-update-lockfile",
62
63
  "release-minor": "release-script minor --yes --no-update-lockfile",
63
- "release-major": "release-script major --yes --no-update-lockfile"
64
+ "release-major": "release-script major --yes --no-update-lockfile",
65
+ "translate": "translate-adapter"
64
66
  },
65
67
  "license": "Apache-2.0"
66
68
  }