iobroker.rest-api 0.3.2 → 0.3.3
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 +1 -1
- package/io-package.json +13 -1
- package/lib/api/controllers/state.js +11 -3
- package/lib/api/swagger/swagger.yaml +16 -5
- package/lib/rest-api.js +60 -12
- package/package.json +1 -1
package/README.md
CHANGED
package/io-package.json
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "rest-api",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.3",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.3.3": {
|
|
7
|
+
"en": "Corrected subscription",
|
|
8
|
+
"de": "Abonnement korrigiert",
|
|
9
|
+
"ru": "Исправлена подписка",
|
|
10
|
+
"pt": "Assinatura corrigida",
|
|
11
|
+
"nl": "Gecorrigeerd abonnement",
|
|
12
|
+
"fr": "Abonnement corrigé",
|
|
13
|
+
"it": "Abbonamento corretto",
|
|
14
|
+
"es": "Suscripción corregida",
|
|
15
|
+
"pl": "Poprawiona subskrypcja",
|
|
16
|
+
"zh-cn": "更正订阅"
|
|
17
|
+
},
|
|
6
18
|
"0.3.2": {
|
|
7
19
|
"en": "Corrected subscription",
|
|
8
20
|
"de": "Abonnement korrigiert",
|
|
@@ -69,7 +69,11 @@ function subscribeState(req, res) {
|
|
|
69
69
|
} else if (obj.type !== 'state') {
|
|
70
70
|
res.status(500).json({error: 'Cannot subscribe on non-state', stateId: params.stateId, type: obj.type, url: req.body.url});
|
|
71
71
|
} else {
|
|
72
|
-
const error = await req._swaggerObject.registerSubscribe(url, params.stateId, 'state', req._user,
|
|
72
|
+
const error = await req._swaggerObject.registerSubscribe(url, params.stateId, 'state', req._user, {
|
|
73
|
+
method: (req.query && req.query.method) || (req.body && req.body.method),
|
|
74
|
+
delta: (req.query && req.query.delta) || (req.body && req.body.delta),
|
|
75
|
+
onchange: (req.query && req.query.onchange) || (req.body && req.body.onchange),
|
|
76
|
+
});
|
|
73
77
|
if (error) {
|
|
74
78
|
res.status(500).json({error, stateId: params.stateId, url: req.body.url});
|
|
75
79
|
return;
|
|
@@ -376,7 +380,11 @@ module.exports = {
|
|
|
376
380
|
return;
|
|
377
381
|
}
|
|
378
382
|
try {
|
|
379
|
-
await req._swaggerObject.registerSubscribe(url, req.body.pattern, 'state', req._user,
|
|
383
|
+
await req._swaggerObject.registerSubscribe(url, req.body.pattern, 'state', req._user, {
|
|
384
|
+
method: req.body.method,
|
|
385
|
+
onchange: req.body.onchange === 'true',
|
|
386
|
+
delta: req.body.delta !== undefined ? parseFloat(req.body.delta) : undefined,
|
|
387
|
+
});
|
|
380
388
|
} catch (error) {
|
|
381
389
|
res.status(500).json({error, pattern: req.body.pattern, url: req.body.url});
|
|
382
390
|
}
|
|
@@ -410,4 +418,4 @@ module.exports = {
|
|
|
410
418
|
}
|
|
411
419
|
});
|
|
412
420
|
},
|
|
413
|
-
};
|
|
421
|
+
};
|
|
@@ -168,6 +168,14 @@ paths:
|
|
|
168
168
|
description: "method=polling forces subscribe via long polling"
|
|
169
169
|
enum: [polling]
|
|
170
170
|
type: "string"
|
|
171
|
+
- name: "onchange"
|
|
172
|
+
type: "boolean"
|
|
173
|
+
description: "If the updates must be delivered if the value changed"
|
|
174
|
+
in: "query"
|
|
175
|
+
- name: "delta"
|
|
176
|
+
type: "number"
|
|
177
|
+
description: "Minimal delta to trigger the event"
|
|
178
|
+
in: "query"
|
|
171
179
|
responses:
|
|
172
180
|
200:
|
|
173
181
|
description: "successful operation"
|
|
@@ -304,7 +312,7 @@ paths:
|
|
|
304
312
|
description: "URL of web hook and the unsubscribe pattern"
|
|
305
313
|
required: true
|
|
306
314
|
schema:
|
|
307
|
-
$ref: "#/definitions/
|
|
315
|
+
$ref: "#/definitions/UrlHook"
|
|
308
316
|
responses:
|
|
309
317
|
200:
|
|
310
318
|
description: "successful operation"
|
|
@@ -520,7 +528,7 @@ paths:
|
|
|
520
528
|
description: "URL of web hook and the unsubscribe pattern"
|
|
521
529
|
required: true
|
|
522
530
|
schema:
|
|
523
|
-
$ref: "#/definitions/
|
|
531
|
+
$ref: "#/definitions/UrlHook"
|
|
524
532
|
responses:
|
|
525
533
|
200:
|
|
526
534
|
description: "successful operation"
|
|
@@ -775,7 +783,7 @@ definitions:
|
|
|
775
783
|
method:
|
|
776
784
|
type: "string"
|
|
777
785
|
description: "HTTP Method"
|
|
778
|
-
enum: [ POST, GET, PUT, PATCH ]
|
|
786
|
+
enum: [ POST, GET, PUT, PATCH, polling ]
|
|
779
787
|
UrlHookWithPattern:
|
|
780
788
|
type: "object"
|
|
781
789
|
required: [pattern]
|
|
@@ -783,13 +791,16 @@ definitions:
|
|
|
783
791
|
url:
|
|
784
792
|
type: "string"
|
|
785
793
|
description: "URL"
|
|
794
|
+
onchange:
|
|
795
|
+
type: "boolean"
|
|
796
|
+
description: "If the updates must be delivered if the value changed"
|
|
786
797
|
pattern:
|
|
787
798
|
type: "string"
|
|
788
799
|
description: "Subscribe pattern like: \"system.adapter.admin.0.*\""
|
|
789
800
|
method:
|
|
790
801
|
type: "string"
|
|
791
802
|
description: "HTTP Method"
|
|
792
|
-
enum: [ POST, GET, PUT, PATCH,
|
|
803
|
+
enum: [ POST, GET, PUT, PATCH, polling ]
|
|
793
804
|
HistoryOptions:
|
|
794
805
|
type: "object"
|
|
795
806
|
#required: [pattern]
|
|
@@ -913,4 +924,4 @@ definitions:
|
|
|
913
924
|
description: "Error description"
|
|
914
925
|
externalDocs:
|
|
915
926
|
description: "Find out more about ioBroker"
|
|
916
|
-
url: "https://www.iobroker.net"
|
|
927
|
+
url: "https://www.iobroker.net"
|
package/lib/rest-api.js
CHANGED
|
@@ -277,27 +277,57 @@ function SwaggerUI(_ignore, webSettings, adapter, instanceSettings, app, callbac
|
|
|
277
277
|
this.gcInterval = this.gcInterval || setInterval(() => this._executeGC(), 30000);
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
this.registerSubscribe = async (urlHook, id, type, user,
|
|
280
|
+
this.registerSubscribe = async (urlHook, id, type, user, options) => {
|
|
281
|
+
if (typeof options === 'string') {
|
|
282
|
+
options = {method: options};
|
|
283
|
+
}
|
|
284
|
+
if (options.delta) {
|
|
285
|
+
options.delta = parseFloat(options.delta);
|
|
286
|
+
} else {
|
|
287
|
+
delete options.delta;
|
|
288
|
+
}
|
|
289
|
+
if (options.onchange) {
|
|
290
|
+
options.onchange = options.onchange === true || options.onchange === 'true';
|
|
291
|
+
} else {
|
|
292
|
+
delete options.onchange;
|
|
293
|
+
}
|
|
294
|
+
|
|
281
295
|
const urlHash = crypto.createHash('md5').update(urlHook).digest('hex');
|
|
282
296
|
if (!this.subscribes[urlHash]) {
|
|
283
|
-
if (method !== 'polling') {
|
|
297
|
+
if (options.method !== 'polling') {
|
|
284
298
|
const error = await _validateUrlHook({urlHook});
|
|
285
299
|
if (error) {
|
|
286
300
|
return `No valid answer from URL hook: ${error}`;
|
|
287
301
|
}
|
|
288
302
|
}
|
|
289
|
-
if (method === 'polling') {
|
|
303
|
+
if (options.method === 'polling') {
|
|
290
304
|
this.adapter.log.debug(`[${urlHook}] Subscribe on connection`);
|
|
291
305
|
this.startGC();
|
|
292
306
|
}
|
|
293
307
|
|
|
294
|
-
this.subscribes[urlHash] = {
|
|
308
|
+
this.subscribes[urlHash] = {
|
|
309
|
+
state: [],
|
|
310
|
+
object: [],
|
|
311
|
+
urlHook,
|
|
312
|
+
polling: options.method === 'polling',
|
|
313
|
+
ts: Date.now()
|
|
314
|
+
};
|
|
295
315
|
}
|
|
296
|
-
|
|
297
|
-
|
|
316
|
+
|
|
317
|
+
if (!this.subscribes[urlHash][type].find(item => item.id === id && (!item.method || item.method === options.method))) {
|
|
318
|
+
const item = {id, delta: options.delta, onchange: options.onchange};
|
|
319
|
+
this.subscribes[urlHash][type].push(item);
|
|
298
320
|
if (type === 'state') {
|
|
299
321
|
this.adapter.log.debug(`[${urlHook}] Subscribe on state "${id}"`);
|
|
300
322
|
await this.adapter.subscribeForeignStatesAsync(id, {user});
|
|
323
|
+
if (options.onchange || options.delta) {
|
|
324
|
+
item.val = await this.adapter.getForeignStateAsync(id);
|
|
325
|
+
if (item.val) {
|
|
326
|
+
item.val = item.val.val;
|
|
327
|
+
} else {
|
|
328
|
+
item.val = null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
301
331
|
} else {
|
|
302
332
|
this.adapter.log.debug(`[${urlHook}] Subscribe on object "${id}"`);
|
|
303
333
|
await this.adapter.subscribeForeignObjectsAsync(id, {user});
|
|
@@ -385,6 +415,21 @@ function SwaggerUI(_ignore, webSettings, adapter, instanceSettings, app, callbac
|
|
|
385
415
|
this.subscribes[urlHash].state.forEach(async item => {
|
|
386
416
|
// check if id
|
|
387
417
|
if (typeof item.id === 'string' && item.id === id) {
|
|
418
|
+
if (state && item.delta && item.val !== null && Math.abs(item.val - state.val) < item.delta) {
|
|
419
|
+
// ignore
|
|
420
|
+
this.adapter.log.debug(`State change for "${id}" ignored as delta (${item.val} - ${state.val}) is less than ${item.delta}`);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
if (state && item.onchange && !item.delta && item.val === state.val) {
|
|
424
|
+
// ignore
|
|
425
|
+
this.adapter.log.debug(`State change for "${id}" ignored as does not changed (${state.val})`);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (state && (item.delta || item.onchange)) {
|
|
429
|
+
// remember last value
|
|
430
|
+
item.val = state.val;
|
|
431
|
+
}
|
|
432
|
+
|
|
388
433
|
await reportChange(this.subscribes[urlHash], {id, state});
|
|
389
434
|
} else {
|
|
390
435
|
// todo
|
|
@@ -495,15 +540,18 @@ function SwaggerUI(_ignore, webSettings, adapter, instanceSettings, app, callbac
|
|
|
495
540
|
new Promise(resolve => {
|
|
496
541
|
item.promise = {
|
|
497
542
|
resolve,
|
|
498
|
-
|
|
499
|
-
item.promise
|
|
543
|
+
timer: setTimeout(() => {
|
|
544
|
+
if (item.promise) {
|
|
545
|
+
// could never happen
|
|
546
|
+
item.promise.timer = null;
|
|
547
|
+
}
|
|
500
548
|
resolve();
|
|
501
549
|
}, item ? item.timeout : 30000)};
|
|
502
550
|
})
|
|
503
551
|
.then(data => {
|
|
504
552
|
if (item.promise) {
|
|
505
|
-
item.promise.
|
|
506
|
-
item.promise.
|
|
553
|
+
item.promise.timer && clearTimeout(item.promise.timer);
|
|
554
|
+
item.promise.timer = null;
|
|
507
555
|
item.promise.resolve = null;
|
|
508
556
|
item.promise = null;
|
|
509
557
|
} else {
|
|
@@ -517,8 +565,8 @@ function SwaggerUI(_ignore, webSettings, adapter, instanceSettings, app, callbac
|
|
|
517
565
|
this.adapter.log.warn(`[${item && item.urlHook}]Error in polling connection: ${error}`);
|
|
518
566
|
}
|
|
519
567
|
if (item.promise) {
|
|
520
|
-
item.promise.
|
|
521
|
-
item.promise.
|
|
568
|
+
item.promise.timer && clearTimeout(item.promise.timer);
|
|
569
|
+
item.promise.timer = null;
|
|
522
570
|
item.promise.resolve = null;
|
|
523
571
|
item.promise = null;
|
|
524
572
|
}
|