@iobroker/socket-classes 1.6.2 → 2.0.2

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.
@@ -1,1886 +0,0 @@
1
- const utils = require('@iobroker/adapter-core'); // Get common adapter utils
2
- const pattern2RegEx = utils.commonTools.pattern2RegEx;
3
- let axios = null;
4
- let zipFiles = null;
5
-
6
- class SocketCommands {
7
- static ERROR_PERMISSION = 'permissionError';
8
- static COMMANDS_PERMISSIONS = {
9
- getObject: { type: 'object', operation: 'read' },
10
- getObjects: { type: 'object', operation: 'list' },
11
- getObjectView: { type: 'object', operation: 'list' },
12
- setObject: { type: 'object', operation: 'write' },
13
- requireLog: { type: 'object', operation: 'write' }, // just mapping to some command
14
- delObject: { type: 'object', operation: 'delete' },
15
- extendObject: { type: 'object', operation: 'write' },
16
- getHostByIp: { type: 'object', operation: 'list' },
17
- subscribeObjects: { type: 'object', operation: 'read' },
18
- unsubscribeObjects: { type: 'object', operation: 'read' },
19
-
20
- getStates: { type: 'state', operation: 'list' },
21
- getState: { type: 'state', operation: 'read' },
22
- setState: { type: 'state', operation: 'write' },
23
- delState: { type: 'state', operation: 'delete' },
24
- createState: { type: 'state', operation: 'create' },
25
- subscribe: { type: 'state', operation: 'read' },
26
- unsubscribe: { type: 'state', operation: 'read' },
27
- getStateHistory: { type: 'state', operation: 'read' },
28
- getVersion: { type: '', operation: '' },
29
- getAdapterName: { type: '', operation: '' },
30
-
31
- addUser: { type: 'users', operation: 'create' },
32
- delUser: { type: 'users', operation: 'delete' },
33
- addGroup: { type: 'users', operation: 'create' },
34
- delGroup: { type: 'users', operation: 'delete' },
35
- changePassword: { type: 'users', operation: 'write' },
36
-
37
- httpGet: { type: 'other', operation: 'http' },
38
- cmdExec: { type: 'other', operation: 'execute' },
39
- sendTo: { type: 'other', operation: 'sendto' },
40
- sendToHost: { type: 'other', operation: 'sendto' },
41
- readLogs: { type: 'other', operation: 'execute' },
42
-
43
- readDir: { type: 'file', operation: 'list' },
44
- createFile: { type: 'file', operation: 'create' },
45
- writeFile: { type: 'file', operation: 'write' },
46
- readFile: { type: 'file', operation: 'read' },
47
- fileExists: { type: 'file', operation: 'read' },
48
- deleteFile: { type: 'file', operation: 'delete' },
49
- readFile64: { type: 'file', operation: 'read' },
50
- writeFile64: { type: 'file', operation: 'write' },
51
- unlink: { type: 'file', operation: 'delete' },
52
- rename: { type: 'file', operation: 'write' },
53
- mkdir: { type: 'file', operation: 'write' },
54
- chmodFile: { type: 'file', operation: 'write' },
55
- chownFile: { type: 'file', operation: 'write' },
56
- subscribeFiles: { type: 'file', operation: 'read' },
57
- unsubscribeFiles: { type: 'file', operation: 'read' },
58
-
59
- authEnabled: { type: '', operation: '' },
60
- disconnect: { type: '', operation: '' },
61
- listPermissions: { type: '', operation: '' },
62
- getUserPermissions: { type: 'object', operation: 'read' }
63
- };
64
-
65
- constructor(adapter, updateSession) {
66
- this.adapter = adapter;
67
- this.commands = {};
68
- this.subscribes = {};
69
- this.logEnabled = false;
70
- this.clientSubscribes = {};
71
-
72
- this._updateSession = updateSession;
73
-
74
- if (!this._updateSession) {
75
- this._updateSession = () => true;
76
- }
77
-
78
- this._initCommands();
79
- }
80
-
81
- async _rename(_adapter, oldName, newName, options) {
82
- // read if it is a file or folder
83
- try {
84
- if (oldName.endsWith('/')) {
85
- oldName = oldName.substring(0, oldName.length - 1);
86
- }
87
-
88
- if (newName.endsWith('/')) {
89
- newName = newName.substring(0, newName.length - 1);
90
- }
91
-
92
- const files = await this.adapter.readDirAsync(_adapter, oldName, options);
93
- if (files && files.length) {
94
- for (let f = 0; f < files.length; f++) {
95
- await this._rename(_adapter, `${oldName}/${files[f].file}`, `${newName}/${files[f].file}`);
96
- }
97
- }
98
- } catch (error) {
99
- if (error.message !== 'Not exists') {
100
- throw error;
101
- }
102
- // else ignore, because it is a file and not a folder
103
- }
104
-
105
- try {
106
- await this.adapter.renameAsync(_adapter, oldName, newName, options);
107
- } catch (error) {
108
- if (error.message !== 'Not exists') {
109
- throw error;
110
- }
111
- // else ignore, because folder cannot be deleted
112
- }
113
- }
114
-
115
- async _unlink(_adapter, name, options) {
116
- // read if it is a file or folder
117
- try {
118
- // remove trailing '/'
119
- if (name.endsWith('/')) {
120
- name = name.substring(0, name.length - 1);
121
- }
122
- const files = await this.adapter.readDirAsync(_adapter, name, options);
123
- if (files && files.length) {
124
- for (let f = 0; f < files.length; f++) {
125
- await this._unlink(_adapter, `${name}/${files[f].file}`);
126
- }
127
- }
128
- } catch (error) {
129
- // ignore, because it is a file and not a folder
130
- if (error.message !== 'Not exists') {
131
- throw error;
132
- }
133
- }
134
-
135
- try {
136
- await this.adapter.unlinkAsync(_adapter, name, options);
137
- } catch (error) {
138
- if (error.message !== 'Not exists') {
139
- throw error;
140
- }
141
- // else ignore, because folder cannot be deleted
142
- }
143
- }
144
-
145
- /**
146
- * Convert errors into strings and then call cb
147
- * @param {function} cb - callback
148
- * @param {string|Error|null} error - error argument
149
- * @param {any[]} args - args passed to cb
150
- */
151
- static _fixCallback(cb, error, ...args) {
152
- if (typeof cb !== 'function') {
153
- return;
154
- }
155
-
156
- if (error instanceof Error) {
157
- error = error.message;
158
- }
159
-
160
- cb(error, ...args);
161
- }
162
-
163
- _checkPermissions(socket, command, callback, arg) {
164
- if (socket._acl.user !== 'system.user.admin') {
165
- // type: file, object, state, other
166
- // operation: create, read, write, list, delete, sendto, execute, sendToHost, readLogs
167
- if (SocketCommands.COMMANDS_PERMISSIONS[command]) {
168
- // If permission required
169
- if (SocketCommands.COMMANDS_PERMISSIONS[command].type) {
170
- if (
171
- socket._acl[SocketCommands.COMMANDS_PERMISSIONS[command].type] &&
172
- socket._acl[SocketCommands.COMMANDS_PERMISSIONS[command].type][
173
- SocketCommands.COMMANDS_PERMISSIONS[command].operation
174
- ]
175
- ) {
176
- return true;
177
- } else {
178
- this.adapter.log.warn(
179
- `No permission for "${socket._acl.user}" to call ${command}. Need "${SocketCommands.COMMANDS_PERMISSIONS[command].type}"."${SocketCommands.COMMANDS_PERMISSIONS[command].operation}"`
180
- );
181
- }
182
- } else {
183
- return true;
184
- }
185
- } else {
186
- this.adapter.log.warn(`No rule for command: ${command}`);
187
- }
188
-
189
- if (typeof callback === 'function') {
190
- callback(SocketCommands.ERROR_PERMISSION);
191
- } else {
192
- if (SocketCommands.COMMANDS_PERMISSIONS[command]) {
193
- socket.emit(SocketCommands.ERROR_PERMISSION, {
194
- command,
195
- type: SocketCommands.COMMANDS_PERMISSIONS[command].type,
196
- operation: SocketCommands.COMMANDS_PERMISSIONS[command].operation,
197
- arg
198
- });
199
- } else {
200
- socket.emit(SocketCommands.ERROR_PERMISSION, { command, arg });
201
- }
202
- }
203
- return false;
204
- }
205
-
206
- return true;
207
- }
208
-
209
- publish(socket, type, id, obj) {
210
- if (socket && socket.subscribe && socket.subscribe[type] && this._updateSession(socket)) {
211
- return !!socket.subscribe[type].find(sub => {
212
- if (sub.regex.test(id)) {
213
- // replace language
214
- if (this.adapter._language && id === 'system.config' && obj.common) {
215
- obj.common.language = this.adapter._language;
216
- }
217
- socket.emit(type, id, obj);
218
- return true;
219
- }
220
- });
221
- }
222
-
223
- return false;
224
- }
225
-
226
- publishFile(socket, id, fileName, size) {
227
- if (socket && socket.subscribe && socket.subscribe.fileChange && this._updateSession(socket)) {
228
- const key = `${id}####${fileName}`;
229
- return !!socket.subscribe.fileChange.find(sub => {
230
- if (sub.regex.test(key)) {
231
- socket.emit('fileChange', id, fileName, size);
232
- return true;
233
- }
234
- });
235
- }
236
-
237
- return false;
238
- }
239
-
240
- publishInstanceMessage(socket, sourceInstance, messageType, data) {
241
- if (
242
- this.clientSubscribes[socket.id] &&
243
- this.clientSubscribes[socket.id][sourceInstance] &&
244
- this.clientSubscribes[socket.id][sourceInstance].includes(messageType)
245
- ) {
246
- socket.emit('im', messageType, sourceInstance, data);
247
- return true;
248
- }
249
-
250
- // inform instance about missing subscription
251
- this.adapter.sendTo(sourceInstance, 'clientSubscribeError', {
252
- type: messageType,
253
- sid: socket.id,
254
- reason: 'no one subscribed'
255
- });
256
- return false;
257
- }
258
-
259
- _showSubscribes(socket, type) {
260
- if (socket && socket.subscribe) {
261
- const s = socket.subscribe[type] || [];
262
- const ids = [];
263
- for (let i = 0; i < s.length; i++) {
264
- ids.push(s[i].pattern);
265
- }
266
- this.adapter.log.debug(`Subscribes: ${ids.join(', ')}`);
267
- } else {
268
- this.adapter.log.debug('Subscribes: no subscribes');
269
- }
270
- }
271
-
272
- isLogEnabled() {
273
- return this.logEnabled;
274
- }
275
-
276
- subscribe(socket, type, pattern, patternFile) {
277
- if (!pattern) {
278
- return this.adapter.log.warn('Empty pattern on subscribe!');
279
- }
280
-
281
- this.subscribes[type] = this.subscribes[type] || {};
282
-
283
- let p;
284
- let key;
285
- pattern = pattern.toString();
286
- if (patternFile && type === 'fileChange') {
287
- patternFile = patternFile.toString();
288
- key = `${pattern}####${patternFile}`;
289
- } else {
290
- key = pattern;
291
- }
292
-
293
- try {
294
- p = pattern2RegEx(key);
295
- } catch (e) {
296
- this.adapter.log.error(`Invalid pattern on subscribe: ${e.message}`);
297
- return;
298
- }
299
-
300
- if (p === null) {
301
- return this.adapter.log.warn('Empty pattern on subscribe!');
302
- }
303
-
304
- let s;
305
- if (socket) {
306
- socket.subscribe = socket.subscribe || {};
307
- s = socket.subscribe[type] = socket.subscribe[type] || [];
308
-
309
- if (s.find(item => item.pattern === key)) {
310
- return;
311
- }
312
- s.push({ pattern: key, regex: new RegExp(p) });
313
- }
314
-
315
- const options = socket && socket._acl ? { user: socket._acl.user } : undefined;
316
-
317
- if (this.subscribes[type][key] === undefined) {
318
- this.subscribes[type][key] = 1;
319
- if (type === 'stateChange') {
320
- this.adapter
321
- .subscribeForeignStatesAsync(pattern, options)
322
- .catch(e => this.adapter.log.error(`Cannot subscribe "${pattern}": ${e.message}`));
323
- } else if (type === 'objectChange') {
324
- this.adapter
325
- .subscribeForeignObjectsAsync(pattern, options)
326
- .catch(e => this.adapter.log.error(`Cannot subscribe "${pattern}": ${e.message}`));
327
- } else if (type === 'log') {
328
- if (!this.logEnabled && this.adapter.requireLog) {
329
- this.logEnabled = true;
330
- this.adapter.requireLog(true, options);
331
- }
332
- } else if (type === 'fileChange' && this.adapter.subscribeForeignFiles) {
333
- this.adapter
334
- .subscribeForeignFiles(pattern, patternFile, options)
335
- .catch(e => this.adapter.log.error(`Cannot subscribe "${pattern}": ${e.message}`));
336
- }
337
- } else {
338
- this.subscribes[type][key]++;
339
- }
340
- }
341
-
342
- unsubscribe(socket, type, pattern, patternFile) {
343
- if (!pattern) {
344
- return this.adapter.log.warn('Empty pattern on subscribe!');
345
- }
346
- // console.log((socket._name || socket.id) + ' unsubscribe ' + pattern);
347
- if (!this.subscribes[type]) {
348
- return;
349
- }
350
-
351
- let key;
352
- pattern = pattern.toString();
353
- if (patternFile && type === 'fileChange') {
354
- patternFile = patternFile.toString();
355
- key = `${pattern}####${patternFile}`;
356
- } else {
357
- key = pattern;
358
- }
359
-
360
- const options = socket && socket._acl ? { user: socket._acl.user } : undefined;
361
-
362
- if (socket && typeof socket === 'object') {
363
- if (!socket.subscribe || !socket.subscribe[type]) {
364
- return;
365
- }
366
-
367
- for (let i = socket.subscribe[type].length - 1; i >= 0; i--) {
368
- if (socket.subscribe[type][i].pattern === key) {
369
- // Remove a pattern from a global list
370
- if (this.subscribes[type][key] !== undefined) {
371
- this.subscribes[type][key]--;
372
- if (this.subscribes[type][key] <= 0) {
373
- if (type === 'stateChange') {
374
- this.adapter
375
- .unsubscribeForeignStatesAsync(pattern, options)
376
- .catch(e =>
377
- this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`)
378
- );
379
- } else if (type === 'objectChange') {
380
- this.adapter
381
- .unsubscribeForeignObjectsAsync(pattern, options)
382
- .catch(e =>
383
- this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`)
384
- );
385
- } else if (type === 'log') {
386
- if (this.logEnabled && this.adapter.requireLog) {
387
- this.logEnabled = false;
388
- this.adapter.requireLog(false, options);
389
- }
390
- } else if (type === 'fileChange' && this.adapter.unsubscribeForeignFiles) {
391
- this.adapter
392
- .unsubscribeForeignFiles(pattern, patternFile, options)
393
- .catch(e =>
394
- this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`)
395
- );
396
- }
397
- delete this.subscribes[type][pattern];
398
- }
399
- }
400
-
401
- delete socket.subscribe[type][i];
402
- socket.subscribe[type].splice(i, 1);
403
- return;
404
- }
405
- }
406
- } else if (key) {
407
- // Remove a pattern from a global list
408
- if (this.subscribes[type][key] !== undefined) {
409
- this.subscribes[type][key]--;
410
- if (this.subscribes[type][key] <= 0) {
411
- if (type === 'stateChange') {
412
- this.adapter
413
- .unsubscribeForeignStatesAsync(pattern, options)
414
- .catch(e => this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`));
415
- } else if (type === 'objectChange') {
416
- this.adapter
417
- .unsubscribeForeignObjectsAsync(pattern, options)
418
- .catch(e => this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`));
419
- } else if (type === 'log') {
420
- if (this.adapter.requireLog && this.logEnabled) {
421
- this.logEnabled = false;
422
- this.adapter.requireLog(false, options);
423
- }
424
- } else if (type === 'fileChange' && this.adapter.unsubscribeForeignFiles) {
425
- this.adapter
426
- .unsubscribeForeignFiles(pattern, patternFile, options)
427
- .catch(e => this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`));
428
- }
429
- delete this.subscribes[type][key];
430
- }
431
- }
432
- } else {
433
- for (const pattern of Object.keys(this.subscribes[type])) {
434
- if (type === 'stateChange') {
435
- this.adapter
436
- .unsubscribeForeignStatesAsync(pattern, options)
437
- .catch(e => this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`));
438
- } else if (type === 'objectChange') {
439
- this.adapter
440
- .unsubscribeForeignObjectsAsync(pattern, options)
441
- .catch(e => this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`));
442
- } else if (type === 'log') {
443
- // console.log((socket._name || socket.id) + ' requireLog false');
444
- if (this.adapter.requireLog && this.logEnabled) {
445
- this.logEnabled = false;
446
- this.adapter.requireLog(false, options);
447
- }
448
- } else if (type === 'fileChange' && this.adapter.unsubscribeForeignFiles) {
449
- const [id, fileName] = pattern.split('####');
450
- this.adapter
451
- .unsubscribeForeignFiles(id, fileName, options)
452
- .catch(e => this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`));
453
- }
454
- }
455
-
456
- this.subscribes[type] = {};
457
- }
458
- }
459
-
460
- subscribeSocket(socket, type) {
461
- if (!socket || !socket.subscribe) {
462
- return;
463
- }
464
-
465
- if (!type) {
466
- // all
467
- return Object.keys(socket.subscribe).forEach(type => this.subscribeSocket(socket, type));
468
- }
469
-
470
- if (!socket.subscribe[type]) {
471
- return;
472
- }
473
-
474
- const options = socket && socket._acl ? { user: socket._acl.user } : undefined;
475
-
476
- for (let i = 0; i < socket.subscribe[type].length; i++) {
477
- const pattern = socket.subscribe[type][i].pattern;
478
- if (this.subscribes[type][pattern] === undefined) {
479
- this.subscribes[type][pattern] = 1;
480
- if (type === 'stateChange') {
481
- this.adapter
482
- .subscribeForeignStatesAsync(pattern, options)
483
- .catch(e => this.adapter.log.error(`Cannot subscribe "${pattern}": ${e.message}`));
484
- } else if (type === 'objectChange') {
485
- this.adapter
486
- .subscribeForeignObjectsAsync(pattern, options)
487
- .catch(e => this.adapter.log.error(`Cannot subscribe "${pattern}": ${e.message}`));
488
- } else if (type === 'log') {
489
- if (this.adapter.requireLog && !this.logEnabled) {
490
- this.logEnabled = true;
491
- this.adapter.requireLog(true, options);
492
- }
493
- } else if (type === 'fileChange' && this.adapter.subscribeForeignFiles) {
494
- const [id, fileName] = pattern.split('####');
495
- this.adapter
496
- .subscribeForeignFiles(id, fileName, options)
497
- .catch(e => this.adapter.log.error(`Cannot subscribe "${pattern}": ${e.message}`));
498
- }
499
- } else {
500
- this.subscribes[type][pattern]++;
501
- }
502
- }
503
- }
504
-
505
- unsubscribeSocket(socket, type) {
506
- if (!socket || !socket.subscribe) {
507
- return;
508
- }
509
- // inform all instances about disconnected socket
510
- this._informAboutDisconnect(socket.id);
511
-
512
- if (!type) {
513
- // all
514
- return Object.keys(socket.subscribe).forEach(type => this.unsubscribeSocket(socket, type));
515
- }
516
-
517
- if (!socket.subscribe[type]) {
518
- return;
519
- }
520
-
521
- const options = socket && socket._acl ? { user: socket._acl.user } : undefined;
522
-
523
- for (let i = 0; i < socket.subscribe[type].length; i++) {
524
- const pattern = socket.subscribe[type][i].pattern;
525
- if (this.subscribes[type][pattern] !== undefined) {
526
- this.subscribes[type][pattern]--;
527
- if (this.subscribes[type][pattern] <= 0) {
528
- if (type === 'stateChange') {
529
- this.adapter
530
- .unsubscribeForeignStatesAsync(pattern, options)
531
- .catch(e => this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`));
532
- } else if (type === 'objectChange') {
533
- this.adapter
534
- .unsubscribeForeignObjectsAsync(pattern, options)
535
- .catch(e => this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`));
536
- } else if (type === 'log') {
537
- if (this.adapter.requireLog && !this.logEnabled) {
538
- this.logEnabled = true;
539
- this.adapter.requireLog(true, options);
540
- }
541
- } else if (type === 'fileChange' && this.adapter.unsubscribeForeignFiles) {
542
- const [id, fileName] = pattern.split('####');
543
- this.adapter
544
- .unsubscribeForeignFiles(id, fileName, options)
545
- .catch(e => this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`));
546
- }
547
- delete this.subscribes[type][pattern];
548
- }
549
- }
550
- }
551
- }
552
-
553
- _subscribeStates(socket, pattern, callback) {
554
- if (this._checkPermissions(socket, 'subscribe', callback, pattern)) {
555
- if (Array.isArray(pattern)) {
556
- for (let p = 0; p < pattern.length; p++) {
557
- this.subscribe(socket, 'stateChange', pattern[p]);
558
- }
559
- } else {
560
- this.subscribe(socket, 'stateChange', pattern);
561
- }
562
-
563
- this.adapter.log.level === 'debug' && this._showSubscribes(socket, 'stateChange');
564
-
565
- typeof callback === 'function' && setImmediate(callback, null);
566
- }
567
- }
568
-
569
- _unsubscribeStates(socket, pattern, callback) {
570
- if (this._checkPermissions(socket, 'unsubscribe', callback, pattern)) {
571
- if (Array.isArray(pattern)) {
572
- for (let p = 0; p < pattern.length; p++) {
573
- this.unsubscribe(socket, 'stateChange', pattern[p]);
574
- }
575
- } else {
576
- this.unsubscribe(socket, 'stateChange', pattern);
577
- }
578
-
579
- this.adapter.log.level === 'debug' && this._showSubscribes(socket, 'stateChange');
580
-
581
- typeof callback === 'function' && setImmediate(callback, null);
582
- }
583
- }
584
-
585
- _subscribeFiles(socket, id, pattern, callback) {
586
- if (this._checkPermissions(socket, 'subscribeFiles', callback, pattern)) {
587
- if (Array.isArray(pattern)) {
588
- for (let p = 0; p < pattern.length; p++) {
589
- this.subscribe(socket, 'fileChange', id, pattern[p]);
590
- }
591
- } else {
592
- this.subscribe(socket, 'fileChange', id, pattern);
593
- }
594
-
595
- this.adapter.log.level === 'debug' && this._showSubscribes(socket, 'fileChange');
596
-
597
- typeof callback === 'function' && setImmediate(callback, null);
598
- }
599
- }
600
-
601
- _unsubscribeFiles(socket, id, pattern, callback) {
602
- if (this._checkPermissions(socket, 'unsubscribeFiles', callback, pattern)) {
603
- if (Array.isArray(pattern)) {
604
- for (let p = 0; p < pattern.length; p++) {
605
- this.unsubscribe(socket, 'fileChange', id, pattern[p]);
606
- }
607
- } else {
608
- this.unsubscribe(socket, 'fileChange', id, pattern);
609
- }
610
-
611
- this.adapter.log.level === 'debug' && this._showSubscribes(socket, 'fileChange');
612
-
613
- typeof callback === 'function' && setImmediate(callback, null);
614
- }
615
- }
616
-
617
- addCommandHandler(command, handler) {
618
- if (handler) {
619
- this.commands[command] = handler;
620
- } else if (command in this.commands) {
621
- delete this.commands[command];
622
- }
623
- }
624
-
625
- getCommandHandler(command) {
626
- return this.commands[command];
627
- }
628
-
629
- _fixAdminUI(obj) {
630
- if (obj && obj.common && !obj.common.adminUI) {
631
- if (obj.common.noConfig) {
632
- obj.common.adminUI = obj.common.adminUI || {};
633
- obj.common.adminUI.config = 'none';
634
- } else if (obj.common.jsonConfig) {
635
- obj.common.adminUI = obj.common.adminUI || {};
636
- obj.common.adminUI.config = 'json';
637
- } else if (obj.common.materialize) {
638
- obj.common.adminUI = obj.common.adminUI || {};
639
- obj.common.adminUI.config = 'materialize';
640
- } else {
641
- obj.common.adminUI = obj.common.adminUI || {};
642
- obj.common.adminUI.config = 'html';
643
- }
644
-
645
- if (obj.common.jsonCustom) {
646
- obj.common.adminUI = obj.common.adminUI || {};
647
- obj.common.adminUI.custom = 'json';
648
- } else if (obj.common.supportCustoms) {
649
- obj.common.adminUI = obj.common.adminUI || {};
650
- obj.common.adminUI.custom = 'json';
651
- }
652
-
653
- if (obj.common.materializeTab && obj.common.adminTab) {
654
- obj.common.adminUI = obj.common.adminUI || {};
655
- obj.common.adminUI.tab = 'materialize';
656
- } else if (obj.common.adminTab) {
657
- obj.common.adminUI = obj.common.adminUI || {};
658
- obj.common.adminUI.tab = 'html';
659
- }
660
-
661
- obj.common.adminUI &&
662
- this.adapter.log.debug(
663
- `Please add to "${obj._id.replace(/\.\d+$/, '')}" common.adminUI=${JSON.stringify(
664
- obj.common.adminUI
665
- )}`
666
- );
667
- }
668
- }
669
-
670
- __initCommandsCommon() {
671
- this.commands['authenticate'] = (socket, user, pass, callback) => {
672
- // Authenticate user by login and password
673
- // @param {string} user - user name
674
- // @param {string} pass - password
675
- // @param {function} callback - `function (isUserAuthenticated, isAuthenticationUsed)`
676
- if (socket && socket.___socket) {
677
- socket = socket.___socket;
678
- }
679
-
680
- this.adapter.log.debug(`${new Date().toISOString()} Request authenticate [${socket._acl.user}]`);
681
- if (typeof user === 'function') {
682
- callback = user;
683
- // user = undefined;
684
- }
685
- if (socket._acl.user !== null) {
686
- if (typeof callback === 'function') {
687
- callback(true, socket._secure);
688
- }
689
- } else {
690
- this.adapter.log.debug(`${new Date().toISOString()} Request authenticate [${socket._acl.user}]`);
691
- socket._authPending = callback;
692
- }
693
- };
694
-
695
- this.commands['error'] = (socket, error) => {
696
- // Write error into ioBroker log
697
- // @param {string} error - error text
698
- this.adapter.log.error(`Socket error: ${error}`);
699
- };
700
-
701
- this.commands['log'] = (socket, text, level) => {
702
- // Write log entry into ioBroker log
703
- // @param {string} text - log text
704
- // @param {string} level - one of `['silly', 'debug', 'info', 'warn', 'error']`. Default is 'debug'.
705
- if (level === 'error') {
706
- this.adapter.log.error(text);
707
- } else if (level === 'warn') {
708
- this.adapter.log.warn(text);
709
- } else if (level === 'info') {
710
- this.adapter.log.info(text);
711
- } else {
712
- this.adapter.log.debug(text);
713
- }
714
- };
715
-
716
- this.commands['checkFeatureSupported'] = (socket, feature, callback) => {
717
- // Checks, if the same feature is supported by the current js-controller
718
- // @param {string} feature - feature name like `CONTROLLER_LICENSE_MANAGER`
719
- // @param {function} callback - `function (error, isSupported)`
720
- if (feature === 'INSTANCE_MESSAGES') {
721
- SocketCommands._fixCallback(callback, null, true);
722
- } else if (feature === 'PARTIAL_OBJECT_TREE') {
723
- SocketCommands._fixCallback(callback, null, true);
724
- } else {
725
- SocketCommands._fixCallback(
726
- callback,
727
- null,
728
- this.adapter.supportsFeature && this.adapter.supportsFeature(feature)
729
- );
730
- }
731
- };
732
-
733
- // new History
734
- this.commands['getHistory'] = (socket, id, options, callback) => {
735
- // Get history data from specific instance
736
- // @param {string} id - object ID
737
- // @param {object} options - See object description here: https://github.com/ioBroker/ioBroker.history/blob/master/docs/en/README.md#access-values-from-javascript-adapter
738
- // @param {function} callback - `function (error, result)`
739
- if (this._checkPermissions(socket, 'getStateHistory', callback, id)) {
740
- if (typeof options === 'string') {
741
- options = {
742
- instance: options
743
- };
744
- }
745
- options = options || {};
746
- options.user = socket._acl.user;
747
- options.aggregate = options.aggregate || 'none';
748
- try {
749
- this.adapter.getHistory(id, options, (error, ...args) =>
750
- SocketCommands._fixCallback(callback, error, ...args)
751
- );
752
- } catch (error) {
753
- this.adapter.log.error(`[getHistory] ERROR: ${error.toString()}`);
754
- SocketCommands._fixCallback(callback, error);
755
- }
756
- }
757
- };
758
-
759
- // HTTP
760
- this.commands['httpGet'] = (socket, url, callback) => {
761
- // Read content of HTTP(S) page server-side (without CORS and stuff)
762
- // @param {string} url - Page URL
763
- // @param {function} callback - `function (error, {status, statusText}, body)`
764
- if (this._checkPermissions(socket, 'httpGet', callback, url)) {
765
- axios = axios || require('axios');
766
- this.adapter.log.debug(`httpGet: ${url}`);
767
- try {
768
- axios(url, {
769
- responseType: 'arraybuffer',
770
- timeout: 15000,
771
- validateStatus: status => status < 400
772
- })
773
- .then(result =>
774
- callback(null, { status: result.status, statusText: result.statusText }, result.data)
775
- )
776
- .catch(error => callback(error));
777
- } catch (error) {
778
- callback(error);
779
- }
780
- }
781
- };
782
-
783
- // commands
784
- this.commands['sendTo'] = (socket, adapterInstance, command, message, callback) => {
785
- // Send the message to specific instance
786
- // @param {string} adapterInstance - instance name, e.g. `history.0`
787
- // @param {string} command - command name
788
- // @param {object} message - the message is instance dependent
789
- // @param {function} callback - `function (result)`
790
- if (this._checkPermissions(socket, 'sendTo', callback, command)) {
791
- try {
792
- this.adapter.sendTo(
793
- adapterInstance,
794
- command,
795
- message,
796
- res => typeof callback === 'function' && setImmediate(() => callback(res))
797
- );
798
- } catch (error) {
799
- typeof callback === 'function' && setImmediate(() => callback({ error }));
800
- }
801
- }
802
- };
803
-
804
- // following commands are protected and require the extra permissions
805
- const protectedCommands = [
806
- 'cmdExec',
807
- 'getLocationOnDisk',
808
- 'getDiagData',
809
- 'getDevList',
810
- 'delLogs',
811
- 'writeDirAsZip',
812
- 'writeObjectsAsZip',
813
- 'readObjectsAsZip',
814
- 'checkLogging',
815
- 'updateMultihost',
816
- 'rebuildAdapter'
817
- ];
818
-
819
- this.commands['sendToHost'] = (socket, host, command, message, callback) => {
820
- // Send a message to the specific host.
821
- // Host can answer to the following commands: `cmdExec, getRepository, getInstalled, getInstalledAdapter, getVersion, getDiagData, getLocationOnDisk, getDevList, getLogs, getHostInfo, delLogs, readDirAsZip, writeDirAsZip, readObjectsAsZip, writeObjectsAsZip, checkLogging, updateMultihost`.
822
- // @param {string} host - instance name, e.g. `history.0`
823
- // @param {string} command - command name
824
- // @param {object} message - the message is command-specific
825
- // @param {function} callback - `function (result)`
826
- if (
827
- this._checkPermissions(
828
- socket,
829
- protectedCommands.includes(command) ? 'cmdExec' : 'sendToHost',
830
- callback,
831
- command
832
- )
833
- ) {
834
- // Try to decode this file locally as redis has a limitation for files bigger than 20MB
835
- if (command === 'writeDirAsZip' && message && message.data.length > 1024 * 1024) {
836
- let buffer;
837
- try {
838
- buffer = Buffer.from(message.data, 'base64');
839
- } catch (error) {
840
- this.adapter.log.error(`Cannot convert data: ${error.toString()}`);
841
- return callback && callback({ error: `Cannot convert data: ${error.toString()}` });
842
- }
843
-
844
- zipFiles = zipFiles || utils.commonTools.zipFiles;
845
-
846
- zipFiles
847
- .writeDirAsZip(
848
- this.adapter, // normally we have to pass here the internal "objects" object, but as
849
- // only writeFile is used, and it has the same name, we can pass here the
850
- // adapter, which has the function with the same name and arguments
851
- message.id,
852
- message.name,
853
- buffer,
854
- message.options,
855
- error => callback({ error }) // this is for back compatibility with js-controller@4.0 or older
856
- )
857
- .then(() => callback({}))
858
- .catch(error => {
859
- this.adapter.log.error(`Cannot write zip file as folder: ${error.toString()}`);
860
- callback && callback({ error });
861
- });
862
- } else if (this._sendToHost) {
863
- this._sendToHost(host, command, message, callback);
864
- } else {
865
- try {
866
- this.adapter.sendToHost(host, command, message, callback);
867
- } catch (error) {
868
- return callback && callback({ error });
869
- }
870
- }
871
- }
872
- };
873
-
874
- this.commands['authEnabled'] = (socket, callback) => {
875
- // Ask server is authentication enabled, and if the user authenticated
876
- // @param {function} callback - `function (isAuthenticationUsed, userName)`
877
- if (this._checkPermissions(socket, 'authEnabled', callback)) {
878
- if (typeof callback === 'function') {
879
- callback(this.adapter.config.auth, (socket._acl.user || '').replace(/^system\.user\./, ''));
880
- } else {
881
- this.adapter.log.warn('[authEnabled] Invalid callback');
882
- }
883
- }
884
- };
885
-
886
- this.commands['logout'] = (socket, callback) => {
887
- // Logout user
888
- // @param {function} callback - function (error)
889
- if (socket.id) {
890
- this.adapter.destroySession(socket.id, callback);
891
- }
892
- };
893
-
894
- this.commands['listPermissions'] = (socket, callback) => {
895
- // List commands and permissions
896
- // @param {function} callback - `function (permissions)`
897
- if (typeof callback === 'function') {
898
- callback(SocketCommands.COMMANDS_PERMISSIONS);
899
- } else {
900
- this.adapter.log.warn('[listPermissions] Invalid callback');
901
- }
902
- };
903
-
904
- this.commands['getUserPermissions'] = (socket, callback) => {
905
- // Get user permissions
906
- // @param {function} callback - `function (error, permissions)`
907
- if (this._checkPermissions(socket, 'getUserPermissions', callback)) {
908
- if (typeof callback === 'function') {
909
- callback(null, socket._acl);
910
- } else {
911
- this.adapter.log.warn('[getUserPermissions] Invalid callback');
912
- }
913
- }
914
- };
915
-
916
- this.commands['getVersion'] = (socket, callback) => {
917
- // Get the adapter version. Not the socket-classes version!
918
- // @param {function} callback - `function (error, adapterVersion, adapterName)`
919
- if (this._checkPermissions(socket, 'getVersion', callback)) {
920
- if (typeof callback === 'function') {
921
- callback(null, this.adapter.version, this.adapter.name);
922
- } else {
923
- this.adapter.log.warn('[getVersion] Invalid callback');
924
- }
925
- }
926
- };
927
-
928
- this.commands['getAdapterName'] = (socket, callback) => {
929
- // Get adapter name. Not the socket-classes version!
930
- // @param {function} callback - `function (error, adapterVersion)`
931
- if (this._checkPermissions(socket, 'getAdapterName', callback)) {
932
- if (typeof callback === 'function') {
933
- callback(null, this.adapter.name || 'unknown');
934
- } else {
935
- this.adapter.log.warn('[getAdapterName] Invalid callback');
936
- }
937
- }
938
- };
939
- }
940
-
941
- __initCommandsFiles() {
942
- // file operations
943
- this.commands['readFile'] = (socket, _adapter, fileName, callback) => {
944
- // Read file from ioBroker DB
945
- // @param {string} _adapter - instance name, e.g. `vis.0`
946
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
947
- // @param {function} callback - `function (error, data, mimeType)`
948
- if (this._checkPermissions(socket, 'readFile', callback, fileName)) {
949
- try {
950
- this.adapter.readFile(_adapter, fileName, { user: socket._acl.user }, (error, ...args) =>
951
- SocketCommands._fixCallback(callback, error, ...args)
952
- );
953
- } catch (error) {
954
- this.adapter.log.error(`[readFile] ERROR: ${error.toString()}`);
955
- SocketCommands._fixCallback(callback, error);
956
- }
957
- }
958
- };
959
-
960
- this.commands['readFile64'] = (socket, _adapter, fileName, callback) => {
961
- // Read file from ioBroker DB as base64 string
962
- // @param {string} _adapter - instance name, e.g. `vis.0`
963
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
964
- // @param {function} callback - `function (error, base64, mimeType)`
965
- if (this._checkPermissions(socket, 'readFile64', callback, fileName)) {
966
- try {
967
- this.adapter.readFile(_adapter, fileName, { user: socket._acl.user }, (error, buffer, type) => {
968
- let data64;
969
- if (buffer) {
970
- try {
971
- if (
972
- type === 'application/json' ||
973
- type === 'application/json5' ||
974
- fileName.toLowerCase().endsWith('.json5')
975
- ) {
976
- data64 = Buffer.from(encodeURIComponent(buffer)).toString('base64');
977
- } else {
978
- if (typeof buffer === 'string') {
979
- data64 = Buffer.from(buffer).toString('base64');
980
- } else {
981
- data64 = buffer.toString('base64');
982
- }
983
- }
984
- } catch (error) {
985
- this.adapter.log.error(`[readFile64] Cannot convert data: ${error.toString()}`);
986
- }
987
- }
988
-
989
- // Convert buffer to base 64
990
- if (typeof callback === 'function') {
991
- callback(error, data64 || '', type);
992
- } else {
993
- this.adapter.log.warn('[readFile64] Invalid callback');
994
- }
995
- });
996
- } catch (error) {
997
- this.adapter.log.error(`[readFile64] ERROR: ${error.toString()}`);
998
- SocketCommands._fixCallback(callback, error);
999
- }
1000
- }
1001
- };
1002
-
1003
- this.commands['writeFile64'] = (socket, _adapter, fileName, data64, options, callback) => {
1004
- // Write file into ioBroker DB as base64 string
1005
- // @param {string} _adapter - instance name, e.g. `vis.0`
1006
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1007
- // @param {string} data64 - file content as base64 string
1008
- // @param {object} options - optional `{mode: 0x0644}`
1009
- // @param {function} callback - `function (error)`
1010
- if (typeof options === 'function') {
1011
- callback = options;
1012
- options = { user: socket._acl.user };
1013
- }
1014
-
1015
- options = options || {};
1016
- options.user = socket._acl.user;
1017
-
1018
- if (this._checkPermissions(socket, 'writeFile64', callback, fileName)) {
1019
- if (!data64) {
1020
- return SocketCommands._fixCallback(callback, 'No data provided');
1021
- }
1022
- // Convert base 64 to buffer
1023
-
1024
- try {
1025
- const buffer = Buffer.from(data64, 'base64');
1026
- this.adapter.writeFile(_adapter, fileName, buffer, options, (error, ...args) =>
1027
- SocketCommands._fixCallback(callback, error, ...args)
1028
- );
1029
- } catch (error) {
1030
- this.adapter.log.error(`[writeFile64] Cannot convert data: ${error.toString()}`);
1031
- SocketCommands._fixCallback(callback, `Cannot convert data: ${error.toString()}`);
1032
- }
1033
- }
1034
- };
1035
-
1036
- // this function is overloaded in admin (because admin accepts only base64)
1037
- this.commands['writeFile'] = (socket, _adapter, fileName, data, options, callback) => {
1038
- // Write file into ioBroker DB as text **DEPRECATED**
1039
- // @param {string} _adapter - instance name, e.g. `vis.0`
1040
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1041
- // @param {string} data64 - file content as base64 string
1042
- // @param {object} options - optional `{mode: 0x644}`
1043
- // @param {function} callback - `function (error)`
1044
- if (this._checkPermissions(socket, 'writeFile', callback, fileName)) {
1045
- if (typeof options === 'function') {
1046
- callback = options;
1047
- options = { user: socket._acl.user };
1048
- }
1049
- options = options || {};
1050
- options.user = socket._acl.user;
1051
- this.adapter.log.debug('writeFile deprecated. Please use writeFile64');
1052
- // const buffer = Buffer.from(data64, 'base64');
1053
- try {
1054
- this.adapter.writeFile(_adapter, fileName, data, options, (error, ...args) =>
1055
- SocketCommands._fixCallback(callback, error, ...args)
1056
- );
1057
- } catch (error) {
1058
- this.adapter.log.error(`[writeFile] ERROR: ${error.toString()}`);
1059
- SocketCommands._fixCallback(callback, error);
1060
- }
1061
- }
1062
- };
1063
-
1064
- this.commands['unlink'] = (socket, _adapter, name, callback) => {
1065
- // Delete file in ioBroker DB
1066
- // @param {string} _adapter - instance name, e.g. `vis.0`
1067
- // @param {string} name - file name, e.g. `main/vis-views.json`
1068
- // @param {function} callback - `function (error)`
1069
- if (this._checkPermissions(socket, 'unlink', callback, name)) {
1070
- try {
1071
- this._unlink(_adapter, name, { user: socket._acl.user })
1072
- .then(() => SocketCommands._fixCallback(callback))
1073
- .catch(error => SocketCommands._fixCallback(callback, error));
1074
- } catch (error) {
1075
- this.adapter.log.error(`[unlink] ERROR: ${error.toString()}`);
1076
- SocketCommands._fixCallback(callback, error);
1077
- }
1078
- }
1079
- };
1080
-
1081
- this.commands['deleteFile'] = (socket, _adapter, name, callback) => {
1082
- // Delete file in ioBroker DB (same as unlink, but only for files)
1083
- // @param {string} _adapter - instance name, e.g. `vis.0`
1084
- // @param {string} name - file name, e.g. `main/vis-views.json`
1085
- // @param {function} callback - `function (error)`
1086
- if (this._checkPermissions(socket, 'unlink', callback, name)) {
1087
- try {
1088
- this.adapter.unlink(_adapter, name, { user: socket._acl.user }, (error, ...args) =>
1089
- SocketCommands._fixCallback(callback, error, ...args)
1090
- );
1091
- } catch (error) {
1092
- this.adapter.log.error(`[deleteFile] ERROR: ${error.toString()}`);
1093
- SocketCommands._fixCallback(callback, error);
1094
- }
1095
- }
1096
- };
1097
-
1098
- this.commands['deleteFolder'] = (socket, _adapter, name, callback) => {
1099
- // Delete file in ioBroker DB (same as unlink, but only for folders)
1100
- // @param {string} _adapter - instance name, e.g. `vis.0`
1101
- // @param {string} name - folder name, e.g. `main`
1102
- // @param {function} callback - `function (error)`
1103
- if (this._checkPermissions(socket, 'unlink', callback, name)) {
1104
- try {
1105
- this._unlink(_adapter, name, { user: socket._acl.user })
1106
- .then(() => SocketCommands._fixCallback(callback, null))
1107
- .catch(error => SocketCommands._fixCallback(callback, error));
1108
- } catch (error) {
1109
- this.adapter.log.error(`[deleteFolder] ERROR: ${error.toString()}`);
1110
- SocketCommands._fixCallback(callback, error);
1111
- }
1112
- }
1113
- };
1114
-
1115
- this.commands['renameFile'] = (socket, _adapter, oldName, newName, callback) => {
1116
- // Rename file in ioBroker DB
1117
- // @param {string} _adapter - instance name, e.g. `vis.0`
1118
- // @param {string} oldName - current file name, e.g. `main/vis-views.json`
1119
- // @param {string} newName - new file name, e.g. `main/vis-views-new.json`
1120
- // @param {function} callback - `function (error)`
1121
- if (this._checkPermissions(socket, 'rename', callback, oldName)) {
1122
- try {
1123
- this.adapter.rename(_adapter, oldName, newName, { user: socket._acl.user }, (error, ...args) =>
1124
- SocketCommands._fixCallback(callback, error, ...args)
1125
- );
1126
- } catch (error) {
1127
- this.adapter.log.error(`[renameFile] ERROR: ${error.toString()}`);
1128
- SocketCommands._fixCallback(callback, error);
1129
- }
1130
- }
1131
- };
1132
-
1133
- this.commands['rename'] = (socket, _adapter, oldName, newName, callback) => {
1134
- // Rename file or folder in ioBroker DB
1135
- // @param {string} _adapter - instance name, e.g. `vis.0`
1136
- // @param {string} oldName - current file name, e.g. `main/vis-views.json`
1137
- // @param {string} newName - new file name, e.g. `main/vis-views-new.json`
1138
- // @param {function} callback - `function (error)`
1139
- if (this._checkPermissions(socket, 'rename', callback, oldName)) {
1140
- try {
1141
- this._rename(_adapter, oldName, newName, { user: socket._acl.user })
1142
- .then(() => SocketCommands._fixCallback(callback))
1143
- .catch(error => SocketCommands._fixCallback(callback, error));
1144
- } catch (error) {
1145
- this.adapter.log.error(`[rename] ERROR: ${error.toString()}`);
1146
- SocketCommands._fixCallback(callback, error);
1147
- }
1148
- }
1149
- };
1150
-
1151
- this.commands['mkdir'] = (socket, _adapter, dirName, callback) => {
1152
- // Create folder in ioBroker DB
1153
- // @param {string} _adapter - instance name, e.g. `vis.0`
1154
- // @param {string} dirName - desired folder name, e.g. `main`
1155
- // @param {function} callback - `function (error)`
1156
- if (this._checkPermissions(socket, 'mkdir', callback, dirName)) {
1157
- try {
1158
- this.adapter.mkdir(_adapter, dirName, { user: socket._acl.user }, (error, ...args) =>
1159
- SocketCommands._fixCallback(callback, error, ...args)
1160
- );
1161
- } catch (error) {
1162
- this.adapter.log.error(`[mkdir] ERROR: ${error.toString()}`);
1163
- SocketCommands._fixCallback(callback, error);
1164
- }
1165
- }
1166
- };
1167
-
1168
- this.commands['readDir'] = (socket, _adapter, dirName, options, callback) => {
1169
- // Read content of folder in ioBroker DB
1170
- // @param {string} _adapter - instance name, e.g. `vis.0`
1171
- // @param {string} dirName - folder name, e.g. `main`
1172
- // @param {object} options - optional `{filter: '*'}` or `{filter: '*.json'}`
1173
- // @param {function} callback - `function (error, files)` where `files` is an array of objects, like `{file: 'vis-views.json', isDir: false, stats: {size: 123}, modifiedAt: 1661336290090, acl: {owner: 'system.user.admin', ownerGroup: 'system.group.administrator', permissions: 1632, read: true, write: true}`
1174
- if (typeof options === 'function') {
1175
- callback = options;
1176
- options = {};
1177
- }
1178
- options = options || {};
1179
- options.user = socket._acl.user;
1180
-
1181
- if (options.filter === undefined) {
1182
- options.filter = true;
1183
- }
1184
-
1185
- if (this._checkPermissions(socket, 'readDir', callback, dirName)) {
1186
- try {
1187
- this.adapter.readDir(_adapter, dirName, { user: socket._acl.user }, (error, ...args) =>
1188
- SocketCommands._fixCallback(callback, error, ...args)
1189
- );
1190
- } catch (error) {
1191
- this.adapter.log.error(`[readDir] ERROR: ${error.toString()}`);
1192
- SocketCommands._fixCallback(callback, error);
1193
- }
1194
- }
1195
- };
1196
-
1197
- this.commands['chmodFile'] = (socket, _adapter, fileName, options, callback) => {
1198
- // Change file mode in ioBroker DB
1199
- // @param {string} _adapter - instance name, e.g. `vis.0`
1200
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1201
- // @param {object} options - `{mode: 0x644}` or 0x644. The first digit is user, second group, third others. Bit 1 is `execute`, bit 2 is `write`, bit 3 is `read`
1202
- // @param {function} callback - `function (error)`
1203
- if (typeof options === 'function') {
1204
- callback = options;
1205
- options = {};
1206
- }
1207
- options = options || {};
1208
- options.user = socket._acl.user;
1209
-
1210
- if (options.filter === undefined) {
1211
- options.filter = true;
1212
- }
1213
-
1214
- if (this._checkPermissions(socket, 'chmodFile', callback, fileName)) {
1215
- try {
1216
- this.adapter.chmodFile(_adapter, fileName, options, (error, ...args) =>
1217
- SocketCommands._fixCallback(callback, error, ...args)
1218
- );
1219
- } catch (error) {
1220
- this.adapter.log.error(`[chmodFile] ERROR: ${error.toString()}`);
1221
- SocketCommands._fixCallback(callback, error);
1222
- }
1223
- }
1224
- };
1225
-
1226
- this.commands['chownFile'] = (socket, _adapter, fileName, options, callback) => {
1227
- // Change file owner in ioBroker DB
1228
- // @param {string} _adapter - instance name, e.g. `vis.0`
1229
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1230
- // @param {object} options - `{owner: 'system.user.user', ownerGroup: ''system.group.administrator'}` or 'system.user.user'. If ownerGroup is not defined, it will be taken from owner.
1231
- // @param {function} callback - `function (error)`
1232
- if (this._checkPermissions(socket, 'chownFile', callback, fileName)) {
1233
- options = options || {};
1234
- options.user = socket._acl.user;
1235
- try {
1236
- this.adapter.chownFile(_adapter, fileName, options, (error, ...args) =>
1237
- SocketCommands._fixCallback(callback, error, ...args)
1238
- );
1239
- } catch (error) {
1240
- this.adapter.log.error(`[chownFile] ERROR: ${error.toString()}`);
1241
- SocketCommands._fixCallback(callback, error);
1242
- }
1243
- }
1244
- };
1245
-
1246
- this.commands['fileExists'] = (socket, _adapter, fileName, callback) => {
1247
- // Check if the file or folder exists in ioBroker DB
1248
- // @param {string} _adapter - instance name, e.g. `vis.0`
1249
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1250
- // @param {function} callback - `function (error, isExist)`
1251
- if (this._checkPermissions(socket, 'fileExists', callback, fileName)) {
1252
- try {
1253
- this.adapter.fileExists(_adapter, fileName, { user: socket._acl.user }, (error, ...args) =>
1254
- SocketCommands._fixCallback(callback, error, ...args)
1255
- );
1256
- } catch (error) {
1257
- this.adapter.log.error(`[fileExists] ERROR: ${error.toString()}`);
1258
- SocketCommands._fixCallback(callback, error);
1259
- }
1260
- }
1261
- };
1262
-
1263
- this.commands['subscribeFiles'] = (socket, id, pattern, callback) => {
1264
- // Subscribe to file changes in ioBroker DB
1265
- // @param {string} id - instance name, e.g. `vis.0` or any object ID of type `meta`. `id` could have wildcards `*` too.
1266
- // @param {string} pattern - file name pattern, e.g. `main/*.json`
1267
- // @param {function} callback - `function (error)`
1268
- return this._subscribeFiles(socket, id, pattern, callback);
1269
- };
1270
-
1271
- this.commands['unsubscribeFiles'] = (socket, id, pattern, callback) => {
1272
- // Unsubscribe from file changes in ioBroker DB
1273
- // @param {string} id - instance name, e.g. `vis.0` or any object ID of type `meta`. `id` could have wildcards `*` too.
1274
- // @param {string} pattern - file name pattern, e.g. `main/*.json`
1275
- // @param {function} callback - `function (error)`
1276
-
1277
- return this._unsubscribeFiles(socket, id, pattern, callback);
1278
- };
1279
-
1280
- this.commands['getAdapterInstances'] = (socket, adapterName, callback) => {
1281
- // Read all instances of the given adapter, or all instances of all adapters if adapterName is not defined
1282
- // @param {string} adapterName - optional adapter name, e.g. `history`.
1283
- // @param {function} callback - `function (error, instanceList)`, where instanceList is an array of instance objects, e.g. `{_id: 'system.adapter.history.0', common: {name: 'history', ...}, native: {...}}`
1284
- if (typeof callback === 'function') {
1285
- if (this._checkPermissions(socket, 'getObject', callback)) {
1286
- let _adapterName =
1287
- adapterName !== undefined && adapterName !== null ? adapterName : this.adapterName || '';
1288
- if (_adapterName) {
1289
- _adapterName += '.';
1290
- }
1291
- try {
1292
- this.adapter.getObjectView(
1293
- 'system',
1294
- 'instance',
1295
- {
1296
- startkey: `system.adapter.${_adapterName}`,
1297
- endkey: `system.adapter.${_adapterName}\u9999`
1298
- },
1299
- { user: socket._acl.user },
1300
- (error, doc) => {
1301
- if (error) {
1302
- callback(error);
1303
- } else {
1304
- callback(
1305
- null,
1306
- doc.rows
1307
- .map(item => {
1308
- const obj = item.value;
1309
- if (obj.common) {
1310
- delete obj.common.news;
1311
- }
1312
- this._fixAdminUI(obj);
1313
- return obj;
1314
- })
1315
- .filter(
1316
- obj =>
1317
- obj &&
1318
- (!adapterName || (obj.common && obj.common.name === adapterName))
1319
- )
1320
- );
1321
- }
1322
- }
1323
- );
1324
- } catch (error) {
1325
- this.adapter.log.error(`[getAdapterInstances] ERROR: ${error.toString()}`);
1326
- SocketCommands._fixCallback(callback, error);
1327
- }
1328
- }
1329
- }
1330
- };
1331
- }
1332
-
1333
- __initCommandsStates() {
1334
- this.commands['getStates'] = (socket, pattern, callback) => {
1335
- // Read states by pattern
1336
- // @param {string} pattern - optional pattern, like `system.adapter.*` or array of state IDs
1337
- // @param {function} callback - `function (error, states)`, where `states` is an object like `{'system.adapter.history.0': {_id: 'system.adapter.history.0', common: {name: 'history', ...}, native: {...}, 'system.adapter.history.1': {...}}}`
1338
- if (this._checkPermissions(socket, 'getStates', callback, pattern)) {
1339
- if (typeof pattern === 'function') {
1340
- callback = pattern;
1341
- pattern = null;
1342
- }
1343
- if (typeof callback === 'function') {
1344
- try {
1345
- this.adapter.getForeignStates(pattern || '*', { user: socket._acl.user }, (error, ...args) =>
1346
- SocketCommands._fixCallback(callback, error, ...args)
1347
- );
1348
- } catch (error) {
1349
- this.adapter.log.error(`[getStates] ERROR: ${error.toString()}`);
1350
- SocketCommands._fixCallback(callback, error);
1351
- }
1352
- } else {
1353
- this.adapter.log.warn('[getStates] Invalid callback');
1354
- }
1355
- }
1356
- };
1357
-
1358
- this.commands['getForeignStates'] = (socket, pattern, callback) => {
1359
- // Read all states (which might not belong to this adapter) which match the given pattern
1360
- // @param {string} pattern - pattern like `system.adapter.*` or array of state IDs
1361
- // @param {function} callback - `function (error)`
1362
- if (this._checkPermissions(socket, 'getStates', callback)) {
1363
- if (typeof callback === 'function') {
1364
- try {
1365
- this.adapter.getForeignStates(pattern, { user: socket._acl.user }, (error, ...args) =>
1366
- SocketCommands._fixCallback(callback, error, ...args)
1367
- );
1368
- } catch (error) {
1369
- this.adapter.log.error(`[getForeignStates] ERROR: ${error}`);
1370
- SocketCommands._fixCallback(callback, error);
1371
- }
1372
- } else {
1373
- this.adapter.log.warn('[getForeignStates] Invalid callback');
1374
- }
1375
- }
1376
- };
1377
-
1378
- this.commands['getState'] = (socket, id, callback) => {
1379
- // Read one state.
1380
- // @param {string} id - State ID like, 'system.adapter.admin.0.memRss'
1381
- // @param {function} callback - `function (error, state)`, where `state` is an object like `{val: 123, ts: 1663915537418, ack: true, from: 'system.adapter.admin.0', q: 0, lc: 1663915537418, c: 'javascript.0'}`
1382
- if (this._checkPermissions(socket, 'getState', callback, id)) {
1383
- if (typeof callback === 'function') {
1384
- if (this.states && this.states[id]) {
1385
- callback(null, this.states[id]);
1386
- } else {
1387
- try {
1388
- this.adapter.getForeignState(id, { user: socket._acl.user }, (error, ...args) =>
1389
- SocketCommands._fixCallback(callback, error, ...args)
1390
- );
1391
- } catch (error) {
1392
- this.adapter.log.error(`[getState] ERROR: ${error.toString()}`);
1393
- SocketCommands._fixCallback(callback, error);
1394
- }
1395
- }
1396
- } else {
1397
- this.adapter.log.warn('[getState] Invalid callback');
1398
- }
1399
- }
1400
- };
1401
-
1402
- this.commands['setState'] = (socket, id, state, callback) => {
1403
- // Write one state.
1404
- // @param {string} id - State ID like, 'system.adapter.admin.0.memRss'
1405
- // @param {any} state - value or object like `{val: 123, ack: true}`
1406
- // @param {function} callback - `function (error, state)`, where `state` is an object like `{val: 123, ts: 1663915537418, ack: true, from: 'system.adapter.admin.0', q: 0, lc: 1663915537418, c: 'javascript.0'}`
1407
- if (this._checkPermissions(socket, 'setState', callback, id)) {
1408
- if (typeof state !== 'object') {
1409
- state = { val: state };
1410
- }
1411
-
1412
- // clear cache
1413
- if (this.states && this.states[id]) {
1414
- delete this.states[id];
1415
- }
1416
-
1417
- try {
1418
- this.adapter.setForeignState(id, state, { user: socket._acl.user }, (error, ...args) =>
1419
- SocketCommands._fixCallback(callback, error, ...args)
1420
- );
1421
- } catch (error) {
1422
- this.adapter.log.error(`[setState] ERROR: ${error.toString()}`);
1423
- SocketCommands._fixCallback(callback, error);
1424
- }
1425
- }
1426
- };
1427
-
1428
- this.commands['getBinaryState'] = (socket, id, callback) => {
1429
- // Read one binary state.
1430
- // @param {string} id - State ID like, 'javascript.0.binary'
1431
- // @param {function} callback - `function (error, base64)`
1432
- if (this._checkPermissions(socket, 'getState', callback, id)) {
1433
- if (typeof callback === 'function') {
1434
- try {
1435
- if (this.adapter.getForeignBinaryState) {
1436
- this.adapter.getForeignBinaryState(id, { user: socket._acl.user }, (error, data) => {
1437
- if (data) {
1438
- try {
1439
- data = Buffer.from(data).toString('base64');
1440
- } catch (error) {
1441
- this.adapter.log.error(
1442
- `[getBinaryState] Cannot convert data: ${error.toString()}`
1443
- );
1444
- }
1445
- }
1446
- SocketCommands._fixCallback(callback, error, data);
1447
- });
1448
- } else {
1449
- this.adapter.getBinaryState(id, { user: socket._acl.user }, (error, data) => {
1450
- if (data) {
1451
- try {
1452
- data = Buffer.from(data).toString('base64');
1453
- } catch (error) {
1454
- this.adapter.log.error(
1455
- `[getBinaryState] Cannot convert data: ${error.toString()}`
1456
- );
1457
- }
1458
- }
1459
- SocketCommands._fixCallback(callback, error, data);
1460
- });
1461
- }
1462
- } catch (error) {
1463
- this.adapter.log.error(`[getBinaryState] ERROR: ${error.toString()}`);
1464
- SocketCommands._fixCallback(callback, error);
1465
- }
1466
- } else {
1467
- this.adapter.log.warn('[getBinaryState] Invalid callback');
1468
- }
1469
- }
1470
- };
1471
-
1472
- this.commands['setBinaryState'] = (socket, id, base64, callback) => {
1473
- // Write one binary state.
1474
- // @param {string} id - State ID like, 'javascript.0.binary'
1475
- // @param {string} base64 - State value as base64 string. Binary states have no acknowledged flag.
1476
- // @param {function} callback - `function (error)`
1477
- if (this._checkPermissions(socket, 'setState', callback, id)) {
1478
- if (typeof callback === 'function') {
1479
- let data = null;
1480
- try {
1481
- data = Buffer.from(base64, 'base64');
1482
- } catch (error) {
1483
- this.adapter.log.warn(`[setBinaryState] Cannot convert base64 data: ${error.toString()}`);
1484
- }
1485
-
1486
- try {
1487
- if (this.adapter.setForeignBinaryState) {
1488
- this.adapter.setForeignBinaryState(id, data, { user: socket._acl.user }, (error, ...args) =>
1489
- SocketCommands._fixCallback(callback, error, ...args)
1490
- );
1491
- } else {
1492
- this.adapter.setBinaryState(id, data, { user: socket._acl.user }, (error, ...args) =>
1493
- SocketCommands._fixCallback(callback, error, ...args)
1494
- );
1495
- }
1496
- } catch (error) {
1497
- this.adapter.log.error(`[setBinaryState] ERROR: ${error.toString()}`);
1498
- SocketCommands._fixCallback(callback, error);
1499
- }
1500
- } else {
1501
- this.adapter.log.warn('[setBinaryState] Invalid callback');
1502
- }
1503
- }
1504
- };
1505
-
1506
- this.commands['subscribe'] = (socket, pattern, callback) => {
1507
- // Subscribe to state changes by pattern. The events will come as 'stateChange' events to the socket.
1508
- // @param {string} pattern - pattern like 'system.adapter.*' or array of states like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1509
- // @param {function} callback - `function (error)`
1510
- return this._subscribeStates(socket, pattern, callback);
1511
- };
1512
-
1513
- this.commands['subscribeStates'] = (socket, pattern, callback) => {
1514
- // Subscribe to state changes by pattern. Same as `subscribe`. The events will come as 'stateChange' events to the socket.
1515
- // @param {string} pattern - pattern like 'system.adapter.*' or array of states like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1516
- // @param {function} callback - `function (error)`
1517
- return this._subscribeStates(socket, pattern, callback);
1518
- };
1519
-
1520
- this.commands['unsubscribe'] = (socket, pattern, callback) => {
1521
- // Unsubscribe from state changes by pattern.
1522
- // @param {string} pattern - pattern like 'system.adapter.*' or array of states like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1523
- // @param {function} callback - `function (error)`
1524
- return this._unsubscribeStates(socket, pattern, callback);
1525
- };
1526
-
1527
- this.commands['unsubscribeStates'] = (socket, pattern, callback) => {
1528
- // Unsubscribe from state changes by pattern. Same as `unsubscribe`.
1529
- // @param {string} pattern - pattern like 'system.adapter.*' or array of states like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1530
- // @param {function} callback - `function (error)`
1531
- return this._unsubscribeStates(socket, pattern, callback);
1532
- };
1533
- }
1534
-
1535
- __initCommandsObjects() {
1536
- this.commands['getObject'] = (socket, id, callback) => {
1537
- // Get one object
1538
- // @param {string} id - object ID.
1539
- // @param {function} callback - `function (error, obj)`
1540
- if (this._checkPermissions(socket, 'getObject', callback, id)) {
1541
- try {
1542
- this.adapter.getForeignObject(id, { user: socket._acl.user }, (error, obj) => {
1543
- // overload language from current instance
1544
- if (this.adapter._language && id === 'system.config' && obj.common) {
1545
- obj.common.language = this.adapter._language;
1546
- }
1547
- SocketCommands._fixCallback(callback, error, obj);
1548
- });
1549
- } catch (error) {
1550
- this.adapter.log.error(`[getObject] ERROR: ${error.toString()}`);
1551
- SocketCommands._fixCallback(callback, error);
1552
- }
1553
- }
1554
- };
1555
-
1556
- // not admin version of "all objects"
1557
- // this function is overloaded in admin
1558
- this.commands['getObjects'] = (socket, list, callback) => {
1559
- // Get all objects that are relevant for web: all states and enums with rooms
1560
- // @param {string} id - object ID.
1561
- // @param {string[]} list - optional list of IDs.
1562
- // @param {function} callback - `function (error, obj)`
1563
- if (typeof list === 'function') {
1564
- callback = list;
1565
- list = null;
1566
- }
1567
- if (list && list.length) {
1568
- if (this._checkPermissions(socket, 'getObject', callback)) {
1569
- if (typeof callback === 'function') {
1570
- try {
1571
- this.adapter.getForeignObjects(list, { user: socket._acl.user }, (error, objs) =>
1572
- SocketCommands._fixCallback(callback, error, objs)
1573
- );
1574
- } catch (error) {
1575
- this.adapter.log.error(`[getObjects] ERROR: ${error.toString()}`);
1576
- SocketCommands._fixCallback(callback, error);
1577
- }
1578
- } else {
1579
- this.adapter.log.warn('[getObjects] Invalid callback');
1580
- }
1581
- }
1582
- } else if (this._checkPermissions(socket, 'getObjects', callback)) {
1583
- try {
1584
- if (typeof callback === 'function') {
1585
- this.adapter.getForeignObjects(
1586
- '*',
1587
- 'state',
1588
- 'rooms',
1589
- { user: socket._acl.user },
1590
- async (error, objs) => {
1591
- try {
1592
- const channels = await this.adapter.getForeignObjectsAsync('*', 'channel', null, {
1593
- user: socket._acl.user
1594
- });
1595
- const devices = await this.adapter.getForeignObjectsAsync('*', 'device', null, {
1596
- user: socket._acl.user
1597
- });
1598
- const enums = await this.adapter.getForeignObjectsAsync('*', 'enum', null, {
1599
- user: socket._acl.user
1600
- });
1601
- const config = await this.adapter.getForeignObjectAsync('system.config', {
1602
- user: socket._acl.user
1603
- });
1604
- Object.assign(objs, channels, devices, enums);
1605
- objs['system.config'] = config;
1606
- } catch (e) {
1607
- this.adapter.log.error(`[getObjects] ERROR: ${e.toString()}`);
1608
- }
1609
- // overload language
1610
- if (this.adapter._language && objs['system.config'] && objs['system.config'].common) {
1611
- objs['system.config'].common.language = this.adapter._language;
1612
- }
1613
-
1614
- SocketCommands._fixCallback(callback, error, objs);
1615
- }
1616
- );
1617
- } else {
1618
- this.adapter.log.warn('[getObjects] Invalid callback');
1619
- }
1620
- } catch (error) {
1621
- this.adapter.log.error(`[getObjects] ERROR: ${error.toString()}`);
1622
- SocketCommands._fixCallback(callback, error);
1623
- }
1624
- }
1625
- };
1626
-
1627
- this.commands['subscribeObjects'] = (socket, pattern, callback) => {
1628
- // Subscribe to object changes by pattern. The events will come as 'objectChange' events to the socket.
1629
- // @param {string} pattern - pattern like 'system.adapter.*' or array of IDs like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1630
- // @param {function} callback - `function (error)`
1631
- if (this._checkPermissions(socket, 'subscribeObjects', callback, pattern)) {
1632
- try {
1633
- if (Array.isArray(pattern)) {
1634
- for (let p = 0; p < pattern.length; p++) {
1635
- this.subscribe(socket, 'objectChange', pattern[p]);
1636
- }
1637
- } else {
1638
- this.subscribe(socket, 'objectChange', pattern);
1639
- }
1640
- if (typeof callback === 'function') {
1641
- setImmediate(callback, null);
1642
- }
1643
- } catch (error) {
1644
- if (typeof callback === 'function') {
1645
- setImmediate(callback, error);
1646
- }
1647
- }
1648
- }
1649
- };
1650
-
1651
- this.commands['unsubscribeObjects'] = (socket, pattern, callback) => {
1652
- // Unsubscribe from object changes by pattern.
1653
- // @param {string} pattern - pattern like 'system.adapter.*' or array of IDs like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1654
- // @param {function} callback - `function (error)`
1655
- if (this._checkPermissions(socket, 'unsubscribeObjects', callback, pattern)) {
1656
- try {
1657
- if (Array.isArray(pattern)) {
1658
- for (let p = 0; p < pattern.length; p++) {
1659
- this.unsubscribe(socket, 'objectChange', pattern[p]);
1660
- }
1661
- } else {
1662
- this.unsubscribe(socket, 'objectChange', pattern);
1663
- }
1664
- if (typeof callback === 'function') {
1665
- setImmediate(callback, null);
1666
- }
1667
- } catch (error) {
1668
- if (typeof callback === 'function') {
1669
- setImmediate(callback, error);
1670
- }
1671
- }
1672
- }
1673
- };
1674
-
1675
- this.commands['getObjectView'] = (socket, design, search, params, callback) => {
1676
- // Make a query to the object database.
1677
- // @param {string} design - 'system' or other designs like `custom`, but it must exist object `_design/custom`. Too 99,9% use `system`.
1678
- // @param {string} search - object type, like `state`, `instance`, `adapter`, `host`, ...
1679
- // @param {string} params - parameters for the query in form `{startkey: 'system.adapter.', endkey?: 'system.adapter.\u9999', depth?: number}`
1680
- // @param {function} callback - `function (error)`
1681
- if (typeof callback === 'function') {
1682
- if (this._checkPermissions(socket, 'getObjectView', callback, search)) {
1683
- try {
1684
- if (params && (params.root || params.depth)) {
1685
- // To save the bandwidth, the request can define root and depth. Default is depth 1.
1686
- this.adapter.getObjectView(
1687
- design,
1688
- search,
1689
- params,
1690
- { user: socket._acl.user },
1691
- (err, result) => {
1692
- if (result?.rows?.length && result.rows[0].value?._id) {
1693
- const rows = [];
1694
- // filter rows
1695
- const depth = params.depth || 1;
1696
- let root = params.startkey;
1697
- let rootWithoutDot;
1698
- if (!root.endsWith('.')) {
1699
- root += '.';
1700
- rootWithoutDot = root;
1701
- } else {
1702
- rootWithoutDot = root.substring(0, root.length - 1);
1703
- }
1704
-
1705
- const rootDepth = root.split('.').length;
1706
- const virtualObjects = {};
1707
- for (let r = 0; r < result.rows.length; r++) {
1708
- if (
1709
- result.rows[r].value._id.startsWith(root) ||
1710
- result.rows[r].value._id === rootWithoutDot
1711
- ) {
1712
- const parts = result.rows[r].id.split('.');
1713
- if (parts.length - rootDepth <= depth) {
1714
- rows.push(result.rows[r]);
1715
- } else {
1716
- // create virtual objects to show that there are more objects
1717
- for (let d = depth; d < parts.length - rootDepth; d++) {
1718
- const id = parts.slice(0, rootDepth + d).join('.');
1719
- if (!virtualObjects[id]) {
1720
- virtualObjects[id] = {
1721
- id,
1722
- value: {
1723
- _id: id,
1724
- common: {},
1725
- type: 'folder',
1726
- virtual: true,
1727
- hasChildren: 1
1728
- }
1729
- };
1730
- rows.push(virtualObjects[id]);
1731
- } else {
1732
- virtualObjects[id].value.hasChildren++;
1733
- }
1734
- }
1735
- }
1736
- }
1737
- }
1738
- result.rows = rows;
1739
- }
1740
- callback(err, result);
1741
- }
1742
- );
1743
- } else {
1744
- this.adapter.getObjectView(design, search, params, { user: socket._acl.user }, callback);
1745
- }
1746
- } catch (error) {
1747
- this.adapter.log.error(`[getObjectView] ERROR: ${error.toString()}`);
1748
- SocketCommands._fixCallback(callback, error);
1749
- }
1750
- }
1751
- } else {
1752
- this.adapter.log.error('Callback is not a function');
1753
- }
1754
- };
1755
-
1756
- this.commands['setObject'] = (socket, id, obj, callback) => {
1757
- // Set object.
1758
- // @param {string} id - object ID
1759
- // @param {object} obj - object itself
1760
- // @param {function} callback - `function (error)`
1761
- if (this._checkPermissions(socket, 'setObject', callback, id)) {
1762
- try {
1763
- this.adapter.setForeignObject(id, obj, { user: socket._acl.user }, (error, ...args) =>
1764
- SocketCommands._fixCallback(callback, error, ...args)
1765
- );
1766
- } catch (error) {
1767
- this.adapter.log.error(`[setObject] ERROR: ${error.toString()}`);
1768
- SocketCommands._fixCallback(callback, error);
1769
- }
1770
- }
1771
- };
1772
-
1773
- // this function is overloaded in admin
1774
- this.commands['delObject'] = (socket, id, options, callback) => {
1775
- // Delete object. Only deletion of flot objects is allowed
1776
- // @param {string} id - Object ID like, 'flot.0.myChart'
1777
- // @param {string} options - ignored
1778
- // @param {function} callback - `function (error)`
1779
- if (id.startsWith('flot.') || id.startsWith('fullcalendar.')) {
1780
- if (this._checkPermissions(socket, 'delObject', callback, id)) {
1781
- try {
1782
- this.adapter.delForeignObject(id, { user: socket._acl.user }, (error, ...args) =>
1783
- SocketCommands._fixCallback(callback, error, ...args)
1784
- );
1785
- } catch (error) {
1786
- this.adapter.log.error(`[delObject] ERROR: ${error.toString()}`);
1787
- SocketCommands._fixCallback(callback, error);
1788
- }
1789
- }
1790
- } else {
1791
- SocketCommands._fixCallback(callback, SocketCommands.ERROR_PERMISSION);
1792
- }
1793
- };
1794
-
1795
- this.commands['clientSubscribe'] = (socket, targetInstance, messageType, data, callback) => {
1796
- // Client informs specific instance about subscription on its messages. After subscription the socket will receive "im" messages from desired instance
1797
- // @param {string} targetInstance - instance name, e.g. "cameras.0"
1798
- // @param {string} messageType - message type, e.g. "startRecording/cam1"
1799
- // @param {object} data - optional data object, e.g. {width: 640, height: 480}
1800
- // @param {function} callback - `function (error, result)`, target instance MUST acknowledge the subscription and return some object as result
1801
- if (typeof data === 'function') {
1802
- callback = data;
1803
- data = null;
1804
- }
1805
- if (!targetInstance.startsWith('system.adapter.')) {
1806
- targetInstance = `system.adapter.${targetInstance}`;
1807
- }
1808
- const sid = socket.id;
1809
- // GUI subscribes for messages from targetInstance
1810
- this.clientSubscribes[sid] = this.clientSubscribes[sid] || {};
1811
- this.clientSubscribes[sid][targetInstance] = this.clientSubscribes[sid][targetInstance] || [];
1812
- if (!this.clientSubscribes[sid][targetInstance].includes(messageType)) {
1813
- this.clientSubscribes[sid][targetInstance].push(messageType);
1814
- }
1815
- // inform instance about new subscription
1816
- this.adapter.sendTo(targetInstance, 'clientSubscribe', { type: messageType, sid, data }, result =>
1817
- SocketCommands._fixCallback(callback, null, result)
1818
- );
1819
- };
1820
-
1821
- this.commands['clientUnsubscribe'] = (socket, targetInstance, messageType, callback) => {
1822
- // Client unsubscribes from specific instance's messages
1823
- // @param {string} targetInstance - instance name, e.g. "cameras.0"
1824
- // @param {string} messageType - message type, e.g. "startRecording/cam1"
1825
- // @param {function} callback - `function (error, wasSubscribed)`, target instance MUST NOT acknowledge the un-subscription
1826
- const sid = socket.id;
1827
- if (!targetInstance.startsWith('system.adapter.')) {
1828
- targetInstance = `system.adapter.${targetInstance}`;
1829
- }
1830
-
1831
- // GUI unsubscribes for messages from targetInstance
1832
- if (this.clientSubscribes[sid] && this.clientSubscribes[sid][targetInstance]) {
1833
- const pos = this.clientSubscribes[sid][targetInstance].indexOf(messageType);
1834
- if (pos !== -1) {
1835
- this.clientSubscribes[sid][targetInstance].splice(pos, 1);
1836
- // inform instance about unsubscription
1837
- this.adapter.sendTo(targetInstance, 'clientUnsubscribe', {
1838
- type: [messageType],
1839
- sid,
1840
- reason: 'client'
1841
- });
1842
- SocketCommands._fixCallback(callback, null, true);
1843
- return;
1844
- }
1845
- }
1846
- SocketCommands._fixCallback(callback, null, false);
1847
- };
1848
- }
1849
-
1850
- _initCommands() {
1851
- this.__initCommandsCommon();
1852
- this.__initCommandsObjects();
1853
- this.__initCommandsStates();
1854
- this.__initCommandsFiles();
1855
- }
1856
-
1857
- _informAboutDisconnect(socketId) {
1858
- // say to all instances, that this socket was disconnected
1859
- if (this.clientSubscribes[socketId]) {
1860
- Object.keys(this.clientSubscribes[socketId]).forEach(targetInstance => {
1861
- this.adapter.sendTo(targetInstance, 'clientUnsubscribe', {
1862
- type: this.clientSubscribes[socketId][targetInstance],
1863
- sid: socketId,
1864
- reason: 'disconnect'
1865
- });
1866
- });
1867
- delete this.clientSubscribes[socketId];
1868
- }
1869
- }
1870
-
1871
- applyCommands(socket) {
1872
- Object.keys(this.commands).forEach(command =>
1873
- socket.on(command, (...args) => {
1874
- if (this._updateSession(socket)) {
1875
- this.commands[command](socket, ...args);
1876
- }
1877
- })
1878
- );
1879
- }
1880
-
1881
- destroy() {
1882
- // could be overloaded
1883
- }
1884
- }
1885
-
1886
- module.exports = SocketCommands;