@iobroker/socket-classes 1.6.1 → 2.0.0

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,1884 +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
- this.adapter.destroySession(socket._sessionID, callback);
890
- };
891
-
892
- this.commands['listPermissions'] = (socket, callback) => {
893
- // List commands and permissions
894
- // @param {function} callback - `function (permissions)`
895
- if (typeof callback === 'function') {
896
- callback(SocketCommands.COMMANDS_PERMISSIONS);
897
- } else {
898
- this.adapter.log.warn('[listPermissions] Invalid callback');
899
- }
900
- };
901
-
902
- this.commands['getUserPermissions'] = (socket, callback) => {
903
- // Get user permissions
904
- // @param {function} callback - `function (error, permissions)`
905
- if (this._checkPermissions(socket, 'getUserPermissions', callback)) {
906
- if (typeof callback === 'function') {
907
- callback(null, socket._acl);
908
- } else {
909
- this.adapter.log.warn('[getUserPermissions] Invalid callback');
910
- }
911
- }
912
- };
913
-
914
- this.commands['getVersion'] = (socket, callback) => {
915
- // Get the adapter version. Not the socket-classes version!
916
- // @param {function} callback - `function (error, adapterVersion, adapterName)`
917
- if (this._checkPermissions(socket, 'getVersion', callback)) {
918
- if (typeof callback === 'function') {
919
- callback(null, this.adapter.version, this.adapter.name);
920
- } else {
921
- this.adapter.log.warn('[getVersion] Invalid callback');
922
- }
923
- }
924
- };
925
-
926
- this.commands['getAdapterName'] = (socket, callback) => {
927
- // Get adapter name. Not the socket-classes version!
928
- // @param {function} callback - `function (error, adapterVersion)`
929
- if (this._checkPermissions(socket, 'getAdapterName', callback)) {
930
- if (typeof callback === 'function') {
931
- callback(null, this.adapter.name || 'unknown');
932
- } else {
933
- this.adapter.log.warn('[getAdapterName] Invalid callback');
934
- }
935
- }
936
- };
937
- }
938
-
939
- __initCommandsFiles() {
940
- // file operations
941
- this.commands['readFile'] = (socket, _adapter, fileName, callback) => {
942
- // Read file from ioBroker DB
943
- // @param {string} _adapter - instance name, e.g. `vis.0`
944
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
945
- // @param {function} callback - `function (error, data, mimeType)`
946
- if (this._checkPermissions(socket, 'readFile', callback, fileName)) {
947
- try {
948
- this.adapter.readFile(_adapter, fileName, { user: socket._acl.user }, (error, ...args) =>
949
- SocketCommands._fixCallback(callback, error, ...args)
950
- );
951
- } catch (error) {
952
- this.adapter.log.error(`[readFile] ERROR: ${error.toString()}`);
953
- SocketCommands._fixCallback(callback, error);
954
- }
955
- }
956
- };
957
-
958
- this.commands['readFile64'] = (socket, _adapter, fileName, callback) => {
959
- // Read file from ioBroker DB as base64 string
960
- // @param {string} _adapter - instance name, e.g. `vis.0`
961
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
962
- // @param {function} callback - `function (error, base64, mimeType)`
963
- if (this._checkPermissions(socket, 'readFile64', callback, fileName)) {
964
- try {
965
- this.adapter.readFile(_adapter, fileName, { user: socket._acl.user }, (error, buffer, type) => {
966
- let data64;
967
- if (buffer) {
968
- try {
969
- if (
970
- type === 'application/json' ||
971
- type === 'application/json5' ||
972
- fileName.toLowerCase().endsWith('.json5')
973
- ) {
974
- data64 = Buffer.from(encodeURIComponent(buffer)).toString('base64');
975
- } else {
976
- if (typeof buffer === 'string') {
977
- data64 = Buffer.from(buffer).toString('base64');
978
- } else {
979
- data64 = buffer.toString('base64');
980
- }
981
- }
982
- } catch (error) {
983
- this.adapter.log.error(`[readFile64] Cannot convert data: ${error.toString()}`);
984
- }
985
- }
986
-
987
- // Convert buffer to base 64
988
- if (typeof callback === 'function') {
989
- callback(error, data64 || '', type);
990
- } else {
991
- this.adapter.log.warn('[readFile64] Invalid callback');
992
- }
993
- });
994
- } catch (error) {
995
- this.adapter.log.error(`[readFile64] ERROR: ${error.toString()}`);
996
- SocketCommands._fixCallback(callback, error);
997
- }
998
- }
999
- };
1000
-
1001
- this.commands['writeFile64'] = (socket, _adapter, fileName, data64, options, callback) => {
1002
- // Write file into ioBroker DB as base64 string
1003
- // @param {string} _adapter - instance name, e.g. `vis.0`
1004
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1005
- // @param {string} data64 - file content as base64 string
1006
- // @param {object} options - optional `{mode: 0x0644}`
1007
- // @param {function} callback - `function (error)`
1008
- if (typeof options === 'function') {
1009
- callback = options;
1010
- options = { user: socket._acl.user };
1011
- }
1012
-
1013
- options = options || {};
1014
- options.user = socket._acl.user;
1015
-
1016
- if (this._checkPermissions(socket, 'writeFile64', callback, fileName)) {
1017
- if (!data64) {
1018
- return SocketCommands._fixCallback(callback, 'No data provided');
1019
- }
1020
- // Convert base 64 to buffer
1021
-
1022
- try {
1023
- const buffer = Buffer.from(data64, 'base64');
1024
- this.adapter.writeFile(_adapter, fileName, buffer, options, (error, ...args) =>
1025
- SocketCommands._fixCallback(callback, error, ...args)
1026
- );
1027
- } catch (error) {
1028
- this.adapter.log.error(`[writeFile64] Cannot convert data: ${error.toString()}`);
1029
- SocketCommands._fixCallback(callback, `Cannot convert data: ${error.toString()}`);
1030
- }
1031
- }
1032
- };
1033
-
1034
- // this function is overloaded in admin (because admin accepts only base64)
1035
- this.commands['writeFile'] = (socket, _adapter, fileName, data, options, callback) => {
1036
- // Write file into ioBroker DB as text **DEPRECATED**
1037
- // @param {string} _adapter - instance name, e.g. `vis.0`
1038
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1039
- // @param {string} data64 - file content as base64 string
1040
- // @param {object} options - optional `{mode: 0x644}`
1041
- // @param {function} callback - `function (error)`
1042
- if (this._checkPermissions(socket, 'writeFile', callback, fileName)) {
1043
- if (typeof options === 'function') {
1044
- callback = options;
1045
- options = { user: socket._acl.user };
1046
- }
1047
- options = options || {};
1048
- options.user = socket._acl.user;
1049
- this.adapter.log.debug('writeFile deprecated. Please use writeFile64');
1050
- // const buffer = Buffer.from(data64, 'base64');
1051
- try {
1052
- this.adapter.writeFile(_adapter, fileName, data, options, (error, ...args) =>
1053
- SocketCommands._fixCallback(callback, error, ...args)
1054
- );
1055
- } catch (error) {
1056
- this.adapter.log.error(`[writeFile] ERROR: ${error.toString()}`);
1057
- SocketCommands._fixCallback(callback, error);
1058
- }
1059
- }
1060
- };
1061
-
1062
- this.commands['unlink'] = (socket, _adapter, name, callback) => {
1063
- // Delete file in ioBroker DB
1064
- // @param {string} _adapter - instance name, e.g. `vis.0`
1065
- // @param {string} name - file name, e.g. `main/vis-views.json`
1066
- // @param {function} callback - `function (error)`
1067
- if (this._checkPermissions(socket, 'unlink', callback, name)) {
1068
- try {
1069
- this._unlink(_adapter, name, { user: socket._acl.user })
1070
- .then(() => SocketCommands._fixCallback(callback))
1071
- .catch(error => SocketCommands._fixCallback(callback, error));
1072
- } catch (error) {
1073
- this.adapter.log.error(`[unlink] ERROR: ${error.toString()}`);
1074
- SocketCommands._fixCallback(callback, error);
1075
- }
1076
- }
1077
- };
1078
-
1079
- this.commands['deleteFile'] = (socket, _adapter, name, callback) => {
1080
- // Delete file in ioBroker DB (same as unlink, but only for files)
1081
- // @param {string} _adapter - instance name, e.g. `vis.0`
1082
- // @param {string} name - file name, e.g. `main/vis-views.json`
1083
- // @param {function} callback - `function (error)`
1084
- if (this._checkPermissions(socket, 'unlink', callback, name)) {
1085
- try {
1086
- this.adapter.unlink(_adapter, name, { user: socket._acl.user }, (error, ...args) =>
1087
- SocketCommands._fixCallback(callback, error, ...args)
1088
- );
1089
- } catch (error) {
1090
- this.adapter.log.error(`[deleteFile] ERROR: ${error.toString()}`);
1091
- SocketCommands._fixCallback(callback, error);
1092
- }
1093
- }
1094
- };
1095
-
1096
- this.commands['deleteFolder'] = (socket, _adapter, name, callback) => {
1097
- // Delete file in ioBroker DB (same as unlink, but only for folders)
1098
- // @param {string} _adapter - instance name, e.g. `vis.0`
1099
- // @param {string} name - folder name, e.g. `main`
1100
- // @param {function} callback - `function (error)`
1101
- if (this._checkPermissions(socket, 'unlink', callback, name)) {
1102
- try {
1103
- this._unlink(_adapter, name, { user: socket._acl.user })
1104
- .then(() => SocketCommands._fixCallback(callback, null))
1105
- .catch(error => SocketCommands._fixCallback(callback, error));
1106
- } catch (error) {
1107
- this.adapter.log.error(`[deleteFolder] ERROR: ${error.toString()}`);
1108
- SocketCommands._fixCallback(callback, error);
1109
- }
1110
- }
1111
- };
1112
-
1113
- this.commands['renameFile'] = (socket, _adapter, oldName, newName, callback) => {
1114
- // Rename file in ioBroker DB
1115
- // @param {string} _adapter - instance name, e.g. `vis.0`
1116
- // @param {string} oldName - current file name, e.g. `main/vis-views.json`
1117
- // @param {string} newName - new file name, e.g. `main/vis-views-new.json`
1118
- // @param {function} callback - `function (error)`
1119
- if (this._checkPermissions(socket, 'rename', callback, oldName)) {
1120
- try {
1121
- this.adapter.rename(_adapter, oldName, newName, { user: socket._acl.user }, (error, ...args) =>
1122
- SocketCommands._fixCallback(callback, error, ...args)
1123
- );
1124
- } catch (error) {
1125
- this.adapter.log.error(`[renameFile] ERROR: ${error.toString()}`);
1126
- SocketCommands._fixCallback(callback, error);
1127
- }
1128
- }
1129
- };
1130
-
1131
- this.commands['rename'] = (socket, _adapter, oldName, newName, callback) => {
1132
- // Rename file or folder in ioBroker DB
1133
- // @param {string} _adapter - instance name, e.g. `vis.0`
1134
- // @param {string} oldName - current file name, e.g. `main/vis-views.json`
1135
- // @param {string} newName - new file name, e.g. `main/vis-views-new.json`
1136
- // @param {function} callback - `function (error)`
1137
- if (this._checkPermissions(socket, 'rename', callback, oldName)) {
1138
- try {
1139
- this._rename(_adapter, oldName, newName, { user: socket._acl.user })
1140
- .then(() => SocketCommands._fixCallback(callback))
1141
- .catch(error => SocketCommands._fixCallback(callback, error));
1142
- } catch (error) {
1143
- this.adapter.log.error(`[rename] ERROR: ${error.toString()}`);
1144
- SocketCommands._fixCallback(callback, error);
1145
- }
1146
- }
1147
- };
1148
-
1149
- this.commands['mkdir'] = (socket, _adapter, dirName, callback) => {
1150
- // Create folder in ioBroker DB
1151
- // @param {string} _adapter - instance name, e.g. `vis.0`
1152
- // @param {string} dirName - desired folder name, e.g. `main`
1153
- // @param {function} callback - `function (error)`
1154
- if (this._checkPermissions(socket, 'mkdir', callback, dirName)) {
1155
- try {
1156
- this.adapter.mkdir(_adapter, dirName, { user: socket._acl.user }, (error, ...args) =>
1157
- SocketCommands._fixCallback(callback, error, ...args)
1158
- );
1159
- } catch (error) {
1160
- this.adapter.log.error(`[mkdir] ERROR: ${error.toString()}`);
1161
- SocketCommands._fixCallback(callback, error);
1162
- }
1163
- }
1164
- };
1165
-
1166
- this.commands['readDir'] = (socket, _adapter, dirName, options, callback) => {
1167
- // Read content of folder in ioBroker DB
1168
- // @param {string} _adapter - instance name, e.g. `vis.0`
1169
- // @param {string} dirName - folder name, e.g. `main`
1170
- // @param {object} options - optional `{filter: '*'}` or `{filter: '*.json'}`
1171
- // @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}`
1172
- if (typeof options === 'function') {
1173
- callback = options;
1174
- options = {};
1175
- }
1176
- options = options || {};
1177
- options.user = socket._acl.user;
1178
-
1179
- if (options.filter === undefined) {
1180
- options.filter = true;
1181
- }
1182
-
1183
- if (this._checkPermissions(socket, 'readDir', callback, dirName)) {
1184
- try {
1185
- this.adapter.readDir(_adapter, dirName, { user: socket._acl.user }, (error, ...args) =>
1186
- SocketCommands._fixCallback(callback, error, ...args)
1187
- );
1188
- } catch (error) {
1189
- this.adapter.log.error(`[readDir] ERROR: ${error.toString()}`);
1190
- SocketCommands._fixCallback(callback, error);
1191
- }
1192
- }
1193
- };
1194
-
1195
- this.commands['chmodFile'] = (socket, _adapter, fileName, options, callback) => {
1196
- // Change file mode in ioBroker DB
1197
- // @param {string} _adapter - instance name, e.g. `vis.0`
1198
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1199
- // @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`
1200
- // @param {function} callback - `function (error)`
1201
- if (typeof options === 'function') {
1202
- callback = options;
1203
- options = {};
1204
- }
1205
- options = options || {};
1206
- options.user = socket._acl.user;
1207
-
1208
- if (options.filter === undefined) {
1209
- options.filter = true;
1210
- }
1211
-
1212
- if (this._checkPermissions(socket, 'chmodFile', callback, fileName)) {
1213
- try {
1214
- this.adapter.chmodFile(_adapter, fileName, options, (error, ...args) =>
1215
- SocketCommands._fixCallback(callback, error, ...args)
1216
- );
1217
- } catch (error) {
1218
- this.adapter.log.error(`[chmodFile] ERROR: ${error.toString()}`);
1219
- SocketCommands._fixCallback(callback, error);
1220
- }
1221
- }
1222
- };
1223
-
1224
- this.commands['chownFile'] = (socket, _adapter, fileName, options, callback) => {
1225
- // Change file owner in ioBroker DB
1226
- // @param {string} _adapter - instance name, e.g. `vis.0`
1227
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1228
- // @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.
1229
- // @param {function} callback - `function (error)`
1230
- if (this._checkPermissions(socket, 'chownFile', callback, fileName)) {
1231
- options = options || {};
1232
- options.user = socket._acl.user;
1233
- try {
1234
- this.adapter.chownFile(_adapter, fileName, options, (error, ...args) =>
1235
- SocketCommands._fixCallback(callback, error, ...args)
1236
- );
1237
- } catch (error) {
1238
- this.adapter.log.error(`[chownFile] ERROR: ${error.toString()}`);
1239
- SocketCommands._fixCallback(callback, error);
1240
- }
1241
- }
1242
- };
1243
-
1244
- this.commands['fileExists'] = (socket, _adapter, fileName, callback) => {
1245
- // Check if the file or folder exists in ioBroker DB
1246
- // @param {string} _adapter - instance name, e.g. `vis.0`
1247
- // @param {string} fileName - file name, e.g. `main/vis-views.json`
1248
- // @param {function} callback - `function (error, isExist)`
1249
- if (this._checkPermissions(socket, 'fileExists', callback, fileName)) {
1250
- try {
1251
- this.adapter.fileExists(_adapter, fileName, { user: socket._acl.user }, (error, ...args) =>
1252
- SocketCommands._fixCallback(callback, error, ...args)
1253
- );
1254
- } catch (error) {
1255
- this.adapter.log.error(`[fileExists] ERROR: ${error.toString()}`);
1256
- SocketCommands._fixCallback(callback, error);
1257
- }
1258
- }
1259
- };
1260
-
1261
- this.commands['subscribeFiles'] = (socket, id, pattern, callback) => {
1262
- // Subscribe to file changes in ioBroker DB
1263
- // @param {string} id - instance name, e.g. `vis.0` or any object ID of type `meta`. `id` could have wildcards `*` too.
1264
- // @param {string} pattern - file name pattern, e.g. `main/*.json`
1265
- // @param {function} callback - `function (error)`
1266
- return this._subscribeFiles(socket, id, pattern, callback);
1267
- };
1268
-
1269
- this.commands['unsubscribeFiles'] = (socket, id, pattern, callback) => {
1270
- // Unsubscribe from file changes in ioBroker DB
1271
- // @param {string} id - instance name, e.g. `vis.0` or any object ID of type `meta`. `id` could have wildcards `*` too.
1272
- // @param {string} pattern - file name pattern, e.g. `main/*.json`
1273
- // @param {function} callback - `function (error)`
1274
-
1275
- return this._unsubscribeFiles(socket, id, pattern, callback);
1276
- };
1277
-
1278
- this.commands['getAdapterInstances'] = (socket, adapterName, callback) => {
1279
- // Read all instances of the given adapter, or all instances of all adapters if adapterName is not defined
1280
- // @param {string} adapterName - optional adapter name, e.g. `history`.
1281
- // @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: {...}}`
1282
- if (typeof callback === 'function') {
1283
- if (this._checkPermissions(socket, 'getObject', callback)) {
1284
- let _adapterName =
1285
- adapterName !== undefined && adapterName !== null ? adapterName : this.adapterName || '';
1286
- if (_adapterName) {
1287
- _adapterName += '.';
1288
- }
1289
- try {
1290
- this.adapter.getObjectView(
1291
- 'system',
1292
- 'instance',
1293
- {
1294
- startkey: `system.adapter.${_adapterName}`,
1295
- endkey: `system.adapter.${_adapterName}\u9999`
1296
- },
1297
- { user: socket._acl.user },
1298
- (error, doc) => {
1299
- if (error) {
1300
- callback(error);
1301
- } else {
1302
- callback(
1303
- null,
1304
- doc.rows
1305
- .map(item => {
1306
- const obj = item.value;
1307
- if (obj.common) {
1308
- delete obj.common.news;
1309
- }
1310
- this._fixAdminUI(obj);
1311
- return obj;
1312
- })
1313
- .filter(
1314
- obj =>
1315
- obj &&
1316
- (!adapterName || (obj.common && obj.common.name === adapterName))
1317
- )
1318
- );
1319
- }
1320
- }
1321
- );
1322
- } catch (error) {
1323
- this.adapter.log.error(`[getAdapterInstances] ERROR: ${error.toString()}`);
1324
- SocketCommands._fixCallback(callback, error);
1325
- }
1326
- }
1327
- }
1328
- };
1329
- }
1330
-
1331
- __initCommandsStates() {
1332
- this.commands['getStates'] = (socket, pattern, callback) => {
1333
- // Read states by pattern
1334
- // @param {string} pattern - optional pattern, like `system.adapter.*` or array of state IDs
1335
- // @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': {...}}}`
1336
- if (this._checkPermissions(socket, 'getStates', callback, pattern)) {
1337
- if (typeof pattern === 'function') {
1338
- callback = pattern;
1339
- pattern = null;
1340
- }
1341
- if (typeof callback === 'function') {
1342
- try {
1343
- this.adapter.getForeignStates(pattern || '*', { user: socket._acl.user }, (error, ...args) =>
1344
- SocketCommands._fixCallback(callback, error, ...args)
1345
- );
1346
- } catch (error) {
1347
- this.adapter.log.error(`[getStates] ERROR: ${error.toString()}`);
1348
- SocketCommands._fixCallback(callback, error);
1349
- }
1350
- } else {
1351
- this.adapter.log.warn('[getStates] Invalid callback');
1352
- }
1353
- }
1354
- };
1355
-
1356
- this.commands['getForeignStates'] = (socket, pattern, callback) => {
1357
- // Read all states (which might not belong to this adapter) which match the given pattern
1358
- // @param {string} pattern - pattern like `system.adapter.*` or array of state IDs
1359
- // @param {function} callback - `function (error)`
1360
- if (this._checkPermissions(socket, 'getStates', callback)) {
1361
- if (typeof callback === 'function') {
1362
- try {
1363
- this.adapter.getForeignStates(pattern, { user: socket._acl.user }, (error, ...args) =>
1364
- SocketCommands._fixCallback(callback, error, ...args)
1365
- );
1366
- } catch (error) {
1367
- this.adapter.log.error(`[getForeignStates] ERROR: ${error}`);
1368
- SocketCommands._fixCallback(callback, error);
1369
- }
1370
- } else {
1371
- this.adapter.log.warn('[getForeignStates] Invalid callback');
1372
- }
1373
- }
1374
- };
1375
-
1376
- this.commands['getState'] = (socket, id, callback) => {
1377
- // Read one state.
1378
- // @param {string} id - State ID like, 'system.adapter.admin.0.memRss'
1379
- // @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'}`
1380
- if (this._checkPermissions(socket, 'getState', callback, id)) {
1381
- if (typeof callback === 'function') {
1382
- if (this.states && this.states[id]) {
1383
- callback(null, this.states[id]);
1384
- } else {
1385
- try {
1386
- this.adapter.getForeignState(id, { user: socket._acl.user }, (error, ...args) =>
1387
- SocketCommands._fixCallback(callback, error, ...args)
1388
- );
1389
- } catch (error) {
1390
- this.adapter.log.error(`[getState] ERROR: ${error.toString()}`);
1391
- SocketCommands._fixCallback(callback, error);
1392
- }
1393
- }
1394
- } else {
1395
- this.adapter.log.warn('[getState] Invalid callback');
1396
- }
1397
- }
1398
- };
1399
-
1400
- this.commands['setState'] = (socket, id, state, callback) => {
1401
- // Write one state.
1402
- // @param {string} id - State ID like, 'system.adapter.admin.0.memRss'
1403
- // @param {any} state - value or object like `{val: 123, ack: true}`
1404
- // @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'}`
1405
- if (this._checkPermissions(socket, 'setState', callback, id)) {
1406
- if (typeof state !== 'object') {
1407
- state = { val: state };
1408
- }
1409
-
1410
- // clear cache
1411
- if (this.states && this.states[id]) {
1412
- delete this.states[id];
1413
- }
1414
-
1415
- try {
1416
- this.adapter.setForeignState(id, state, { user: socket._acl.user }, (error, ...args) =>
1417
- SocketCommands._fixCallback(callback, error, ...args)
1418
- );
1419
- } catch (error) {
1420
- this.adapter.log.error(`[setState] ERROR: ${error.toString()}`);
1421
- SocketCommands._fixCallback(callback, error);
1422
- }
1423
- }
1424
- };
1425
-
1426
- this.commands['getBinaryState'] = (socket, id, callback) => {
1427
- // Read one binary state.
1428
- // @param {string} id - State ID like, 'javascript.0.binary'
1429
- // @param {function} callback - `function (error, base64)`
1430
- if (this._checkPermissions(socket, 'getState', callback, id)) {
1431
- if (typeof callback === 'function') {
1432
- try {
1433
- if (this.adapter.getForeignBinaryState) {
1434
- this.adapter.getForeignBinaryState(id, { user: socket._acl.user }, (error, data) => {
1435
- if (data) {
1436
- try {
1437
- data = Buffer.from(data).toString('base64');
1438
- } catch (error) {
1439
- this.adapter.log.error(
1440
- `[getBinaryState] Cannot convert data: ${error.toString()}`
1441
- );
1442
- }
1443
- }
1444
- SocketCommands._fixCallback(callback, error, data);
1445
- });
1446
- } else {
1447
- this.adapter.getBinaryState(id, { user: socket._acl.user }, (error, data) => {
1448
- if (data) {
1449
- try {
1450
- data = Buffer.from(data).toString('base64');
1451
- } catch (error) {
1452
- this.adapter.log.error(
1453
- `[getBinaryState] Cannot convert data: ${error.toString()}`
1454
- );
1455
- }
1456
- }
1457
- SocketCommands._fixCallback(callback, error, data);
1458
- });
1459
- }
1460
- } catch (error) {
1461
- this.adapter.log.error(`[getBinaryState] ERROR: ${error.toString()}`);
1462
- SocketCommands._fixCallback(callback, error);
1463
- }
1464
- } else {
1465
- this.adapter.log.warn('[getBinaryState] Invalid callback');
1466
- }
1467
- }
1468
- };
1469
-
1470
- this.commands['setBinaryState'] = (socket, id, base64, callback) => {
1471
- // Write one binary state.
1472
- // @param {string} id - State ID like, 'javascript.0.binary'
1473
- // @param {string} base64 - State value as base64 string. Binary states have no acknowledged flag.
1474
- // @param {function} callback - `function (error)`
1475
- if (this._checkPermissions(socket, 'setState', callback, id)) {
1476
- if (typeof callback === 'function') {
1477
- let data = null;
1478
- try {
1479
- data = Buffer.from(base64, 'base64');
1480
- } catch (error) {
1481
- this.adapter.log.warn(`[setBinaryState] Cannot convert base64 data: ${error.toString()}`);
1482
- }
1483
-
1484
- try {
1485
- if (this.adapter.setForeignBinaryState) {
1486
- this.adapter.setForeignBinaryState(id, data, { user: socket._acl.user }, (error, ...args) =>
1487
- SocketCommands._fixCallback(callback, error, ...args)
1488
- );
1489
- } else {
1490
- this.adapter.setBinaryState(id, data, { user: socket._acl.user }, (error, ...args) =>
1491
- SocketCommands._fixCallback(callback, error, ...args)
1492
- );
1493
- }
1494
- } catch (error) {
1495
- this.adapter.log.error(`[setBinaryState] ERROR: ${error.toString()}`);
1496
- SocketCommands._fixCallback(callback, error);
1497
- }
1498
- } else {
1499
- this.adapter.log.warn('[setBinaryState] Invalid callback');
1500
- }
1501
- }
1502
- };
1503
-
1504
- this.commands['subscribe'] = (socket, pattern, callback) => {
1505
- // Subscribe to state changes by pattern. The events will come as 'stateChange' events to the socket.
1506
- // @param {string} pattern - pattern like 'system.adapter.*' or array of states like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1507
- // @param {function} callback - `function (error)`
1508
- return this._subscribeStates(socket, pattern, callback);
1509
- };
1510
-
1511
- this.commands['subscribeStates'] = (socket, pattern, callback) => {
1512
- // Subscribe to state changes by pattern. Same as `subscribe`. The events will come as 'stateChange' events to the socket.
1513
- // @param {string} pattern - pattern like 'system.adapter.*' or array of states like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1514
- // @param {function} callback - `function (error)`
1515
- return this._subscribeStates(socket, pattern, callback);
1516
- };
1517
-
1518
- this.commands['unsubscribe'] = (socket, pattern, callback) => {
1519
- // Unsubscribe from state changes by pattern.
1520
- // @param {string} pattern - pattern like 'system.adapter.*' or array of states like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1521
- // @param {function} callback - `function (error)`
1522
- return this._unsubscribeStates(socket, pattern, callback);
1523
- };
1524
-
1525
- this.commands['unsubscribeStates'] = (socket, pattern, callback) => {
1526
- // Unsubscribe from state changes by pattern. Same as `unsubscribe`.
1527
- // @param {string} pattern - pattern like 'system.adapter.*' or array of states like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1528
- // @param {function} callback - `function (error)`
1529
- return this._unsubscribeStates(socket, pattern, callback);
1530
- };
1531
- }
1532
-
1533
- __initCommandsObjects() {
1534
- this.commands['getObject'] = (socket, id, callback) => {
1535
- // Get one object
1536
- // @param {string} id - object ID.
1537
- // @param {function} callback - `function (error, obj)`
1538
- if (this._checkPermissions(socket, 'getObject', callback, id)) {
1539
- try {
1540
- this.adapter.getForeignObject(id, { user: socket._acl.user }, (error, obj) => {
1541
- // overload language from current instance
1542
- if (this.adapter._language && id === 'system.config' && obj.common) {
1543
- obj.common.language = this.adapter._language;
1544
- }
1545
- SocketCommands._fixCallback(callback, error, obj);
1546
- });
1547
- } catch (error) {
1548
- this.adapter.log.error(`[getObject] ERROR: ${error.toString()}`);
1549
- SocketCommands._fixCallback(callback, error);
1550
- }
1551
- }
1552
- };
1553
-
1554
- // not admin version of "all objects"
1555
- // this function is overloaded in admin
1556
- this.commands['getObjects'] = (socket, list, callback) => {
1557
- // Get all objects that are relevant for web: all states and enums with rooms
1558
- // @param {string} id - object ID.
1559
- // @param {string[]} list - optional list of IDs.
1560
- // @param {function} callback - `function (error, obj)`
1561
- if (typeof list === 'function') {
1562
- callback = list;
1563
- list = null;
1564
- }
1565
- if (list && list.length) {
1566
- if (this._checkPermissions(socket, 'getObject', callback)) {
1567
- if (typeof callback === 'function') {
1568
- try {
1569
- this.adapter.getForeignObjects(list, { user: socket._acl.user }, (error, objs) =>
1570
- SocketCommands._fixCallback(callback, error, objs)
1571
- );
1572
- } catch (error) {
1573
- this.adapter.log.error(`[getObjects] ERROR: ${error.toString()}`);
1574
- SocketCommands._fixCallback(callback, error);
1575
- }
1576
- } else {
1577
- this.adapter.log.warn('[getObjects] Invalid callback');
1578
- }
1579
- }
1580
- } else if (this._checkPermissions(socket, 'getObjects', callback)) {
1581
- try {
1582
- if (typeof callback === 'function') {
1583
- this.adapter.getForeignObjects(
1584
- '*',
1585
- 'state',
1586
- 'rooms',
1587
- { user: socket._acl.user },
1588
- async (error, objs) => {
1589
- try {
1590
- const channels = await this.adapter.getForeignObjectsAsync('*', 'channel', null, {
1591
- user: socket._acl.user
1592
- });
1593
- const devices = await this.adapter.getForeignObjectsAsync('*', 'device', null, {
1594
- user: socket._acl.user
1595
- });
1596
- const enums = await this.adapter.getForeignObjectsAsync('*', 'enum', null, {
1597
- user: socket._acl.user
1598
- });
1599
- const config = await this.adapter.getForeignObjectAsync('system.config', {
1600
- user: socket._acl.user
1601
- });
1602
- Object.assign(objs, channels, devices, enums);
1603
- objs['system.config'] = config;
1604
- } catch (e) {
1605
- this.adapter.log.error(`[getObjects] ERROR: ${e.toString()}`);
1606
- }
1607
- // overload language
1608
- if (this.adapter._language && objs['system.config'] && objs['system.config'].common) {
1609
- objs['system.config'].common.language = this.adapter._language;
1610
- }
1611
-
1612
- SocketCommands._fixCallback(callback, error, objs);
1613
- }
1614
- );
1615
- } else {
1616
- this.adapter.log.warn('[getObjects] Invalid callback');
1617
- }
1618
- } catch (error) {
1619
- this.adapter.log.error(`[getObjects] ERROR: ${error.toString()}`);
1620
- SocketCommands._fixCallback(callback, error);
1621
- }
1622
- }
1623
- };
1624
-
1625
- this.commands['subscribeObjects'] = (socket, pattern, callback) => {
1626
- // Subscribe to object changes by pattern. The events will come as 'objectChange' events to the socket.
1627
- // @param {string} pattern - pattern like 'system.adapter.*' or array of IDs like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1628
- // @param {function} callback - `function (error)`
1629
- if (this._checkPermissions(socket, 'subscribeObjects', callback, pattern)) {
1630
- try {
1631
- if (Array.isArray(pattern)) {
1632
- for (let p = 0; p < pattern.length; p++) {
1633
- this.subscribe(socket, 'objectChange', pattern[p]);
1634
- }
1635
- } else {
1636
- this.subscribe(socket, 'objectChange', pattern);
1637
- }
1638
- if (typeof callback === 'function') {
1639
- setImmediate(callback, null);
1640
- }
1641
- } catch (error) {
1642
- if (typeof callback === 'function') {
1643
- setImmediate(callback, error);
1644
- }
1645
- }
1646
- }
1647
- };
1648
-
1649
- this.commands['unsubscribeObjects'] = (socket, pattern, callback) => {
1650
- // Unsubscribe from object changes by pattern.
1651
- // @param {string} pattern - pattern like 'system.adapter.*' or array of IDs like ['system.adapter.admin.0.memRss', 'system.adapter.admin.0.memHeapTotal']
1652
- // @param {function} callback - `function (error)`
1653
- if (this._checkPermissions(socket, 'unsubscribeObjects', callback, pattern)) {
1654
- try {
1655
- if (Array.isArray(pattern)) {
1656
- for (let p = 0; p < pattern.length; p++) {
1657
- this.unsubscribe(socket, 'objectChange', pattern[p]);
1658
- }
1659
- } else {
1660
- this.unsubscribe(socket, 'objectChange', pattern);
1661
- }
1662
- if (typeof callback === 'function') {
1663
- setImmediate(callback, null);
1664
- }
1665
- } catch (error) {
1666
- if (typeof callback === 'function') {
1667
- setImmediate(callback, error);
1668
- }
1669
- }
1670
- }
1671
- };
1672
-
1673
- this.commands['getObjectView'] = (socket, design, search, params, callback) => {
1674
- // Make a query to the object database.
1675
- // @param {string} design - 'system' or other designs like `custom`, but it must exist object `_design/custom`. Too 99,9% use `system`.
1676
- // @param {string} search - object type, like `state`, `instance`, `adapter`, `host`, ...
1677
- // @param {string} params - parameters for the query in form `{startkey: 'system.adapter.', endkey?: 'system.adapter.\u9999', depth?: number}`
1678
- // @param {function} callback - `function (error)`
1679
- if (typeof callback === 'function') {
1680
- if (this._checkPermissions(socket, 'getObjectView', callback, search)) {
1681
- try {
1682
- if (params && (params.root || params.depth)) {
1683
- // To save the bandwidth, the request can define root and depth. Default is depth 1.
1684
- this.adapter.getObjectView(
1685
- design,
1686
- search,
1687
- params,
1688
- { user: socket._acl.user },
1689
- (err, result) => {
1690
- if (result?.rows?.length && result.rows[0].value?._id) {
1691
- const rows = [];
1692
- // filter rows
1693
- const depth = params.depth || 1;
1694
- let root = params.startkey;
1695
- let rootWithoutDot;
1696
- if (!root.endsWith('.')) {
1697
- root += '.';
1698
- rootWithoutDot = root;
1699
- } else {
1700
- rootWithoutDot = root.substring(0, root.length - 1);
1701
- }
1702
-
1703
- const rootDepth = root.split('.').length;
1704
- const virtualObjects = {};
1705
- for (let r = 0; r < result.rows.length; r++) {
1706
- if (
1707
- result.rows[r].value._id.startsWith(root) ||
1708
- result.rows[r].value._id === rootWithoutDot
1709
- ) {
1710
- const parts = result.rows[r].id.split('.');
1711
- if (parts.length - rootDepth <= depth) {
1712
- rows.push(result.rows[r]);
1713
- } else {
1714
- // create virtual objects to show that there are more objects
1715
- for (let d = depth; d < parts.length - rootDepth; d++) {
1716
- const id = parts.slice(0, rootDepth + d).join('.');
1717
- if (!virtualObjects[id]) {
1718
- virtualObjects[id] = {
1719
- id,
1720
- value: {
1721
- _id: id,
1722
- common: {},
1723
- type: 'folder',
1724
- virtual: true,
1725
- hasChildren: 1
1726
- }
1727
- };
1728
- rows.push(virtualObjects[id]);
1729
- } else {
1730
- virtualObjects[id].value.hasChildren++;
1731
- }
1732
- }
1733
- }
1734
- }
1735
- }
1736
- result.rows = rows;
1737
- }
1738
- callback(err, result);
1739
- }
1740
- );
1741
- } else {
1742
- this.adapter.getObjectView(design, search, params, { user: socket._acl.user }, callback);
1743
- }
1744
- } catch (error) {
1745
- this.adapter.log.error(`[getObjectView] ERROR: ${error.toString()}`);
1746
- SocketCommands._fixCallback(callback, error);
1747
- }
1748
- }
1749
- } else {
1750
- this.adapter.log.error('Callback is not a function');
1751
- }
1752
- };
1753
-
1754
- this.commands['setObject'] = (socket, id, obj, callback) => {
1755
- // Set object.
1756
- // @param {string} id - object ID
1757
- // @param {object} obj - object itself
1758
- // @param {function} callback - `function (error)`
1759
- if (this._checkPermissions(socket, 'setObject', callback, id)) {
1760
- try {
1761
- this.adapter.setForeignObject(id, obj, { user: socket._acl.user }, (error, ...args) =>
1762
- SocketCommands._fixCallback(callback, error, ...args)
1763
- );
1764
- } catch (error) {
1765
- this.adapter.log.error(`[setObject] ERROR: ${error.toString()}`);
1766
- SocketCommands._fixCallback(callback, error);
1767
- }
1768
- }
1769
- };
1770
-
1771
- // this function is overloaded in admin
1772
- this.commands['delObject'] = (socket, id, options, callback) => {
1773
- // Delete object. Only deletion of flot objects is allowed
1774
- // @param {string} id - Object ID like, 'flot.0.myChart'
1775
- // @param {string} options - ignored
1776
- // @param {function} callback - `function (error)`
1777
- if (id.startsWith('flot.') || id.startsWith('fullcalendar.')) {
1778
- if (this._checkPermissions(socket, 'delObject', callback, id)) {
1779
- try {
1780
- this.adapter.delForeignObject(id, { user: socket._acl.user }, (error, ...args) =>
1781
- SocketCommands._fixCallback(callback, error, ...args)
1782
- );
1783
- } catch (error) {
1784
- this.adapter.log.error(`[delObject] ERROR: ${error.toString()}`);
1785
- SocketCommands._fixCallback(callback, error);
1786
- }
1787
- }
1788
- } else {
1789
- SocketCommands._fixCallback(callback, SocketCommands.ERROR_PERMISSION);
1790
- }
1791
- };
1792
-
1793
- this.commands['clientSubscribe'] = (socket, targetInstance, messageType, data, callback) => {
1794
- // Client informs specific instance about subscription on its messages. After subscription the socket will receive "im" messages from desired instance
1795
- // @param {string} targetInstance - instance name, e.g. "cameras.0"
1796
- // @param {string} messageType - message type, e.g. "startRecording/cam1"
1797
- // @param {object} data - optional data object, e.g. {width: 640, height: 480}
1798
- // @param {function} callback - `function (error, result)`, target instance MUST acknowledge the subscription and return some object as result
1799
- if (typeof data === 'function') {
1800
- callback = data;
1801
- data = null;
1802
- }
1803
- if (!targetInstance.startsWith('system.adapter.')) {
1804
- targetInstance = `system.adapter.${targetInstance}`;
1805
- }
1806
- const sid = socket.id;
1807
- // GUI subscribes for messages from targetInstance
1808
- this.clientSubscribes[sid] = this.clientSubscribes[sid] || {};
1809
- this.clientSubscribes[sid][targetInstance] = this.clientSubscribes[sid][targetInstance] || [];
1810
- if (!this.clientSubscribes[sid][targetInstance].includes(messageType)) {
1811
- this.clientSubscribes[sid][targetInstance].push(messageType);
1812
- }
1813
- // inform instance about new subscription
1814
- this.adapter.sendTo(targetInstance, 'clientSubscribe', { type: messageType, sid, data }, result =>
1815
- SocketCommands._fixCallback(callback, null, result)
1816
- );
1817
- };
1818
-
1819
- this.commands['clientUnsubscribe'] = (socket, targetInstance, messageType, callback) => {
1820
- // Client unsubscribes from specific instance's messages
1821
- // @param {string} targetInstance - instance name, e.g. "cameras.0"
1822
- // @param {string} messageType - message type, e.g. "startRecording/cam1"
1823
- // @param {function} callback - `function (error, wasSubscribed)`, target instance MUST NOT acknowledge the un-subscription
1824
- const sid = socket.id;
1825
- if (!targetInstance.startsWith('system.adapter.')) {
1826
- targetInstance = `system.adapter.${targetInstance}`;
1827
- }
1828
-
1829
- // GUI unsubscribes for messages from targetInstance
1830
- if (this.clientSubscribes[sid] && this.clientSubscribes[sid][targetInstance]) {
1831
- const pos = this.clientSubscribes[sid][targetInstance].indexOf(messageType);
1832
- if (pos !== -1) {
1833
- this.clientSubscribes[sid][targetInstance].splice(pos, 1);
1834
- // inform instance about unsubscription
1835
- this.adapter.sendTo(targetInstance, 'clientUnsubscribe', {
1836
- type: [messageType],
1837
- sid,
1838
- reason: 'client'
1839
- });
1840
- SocketCommands._fixCallback(callback, null, true);
1841
- return;
1842
- }
1843
- }
1844
- SocketCommands._fixCallback(callback, null, false);
1845
- };
1846
- }
1847
-
1848
- _initCommands() {
1849
- this.__initCommandsCommon();
1850
- this.__initCommandsObjects();
1851
- this.__initCommandsStates();
1852
- this.__initCommandsFiles();
1853
- }
1854
-
1855
- _informAboutDisconnect(socketId) {
1856
- // say to all instances, that this socket was disconnected
1857
- if (this.clientSubscribes[socketId]) {
1858
- Object.keys(this.clientSubscribes[socketId]).forEach(targetInstance => {
1859
- this.adapter.sendTo(targetInstance, 'clientUnsubscribe', {
1860
- type: this.clientSubscribes[socketId][targetInstance],
1861
- sid: socketId,
1862
- reason: 'disconnect'
1863
- });
1864
- });
1865
- delete this.clientSubscribes[socketId];
1866
- }
1867
- }
1868
-
1869
- applyCommands(socket) {
1870
- Object.keys(this.commands).forEach(command =>
1871
- socket.on(command, (...args) => {
1872
- if (this._updateSession(socket)) {
1873
- this.commands[command](socket, ...args);
1874
- }
1875
- })
1876
- );
1877
- }
1878
-
1879
- destroy() {
1880
- // could be overloaded
1881
- }
1882
- }
1883
-
1884
- module.exports = SocketCommands;