@iobroker/socket-classes 1.6.2 → 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,1492 +0,0 @@
1
- const SocketCommands = require('./socketCommands');
2
- const axios = require('axios');
3
- const path = require('node:path');
4
- const fs = require('node:fs');
5
-
6
- class SocketCommandsAdmin extends SocketCommands {
7
- static ALLOW_CACHE = [
8
- 'getRepository',
9
- 'getInstalled',
10
- 'getInstalledAdapter',
11
- 'getVersion',
12
- 'getDiagData',
13
- 'getLocationOnDisk',
14
- 'getDevList',
15
- 'getLogs',
16
- 'getHostInfo'
17
- ];
18
-
19
- constructor(adapter, updateSession, objects, states) {
20
- super(adapter, updateSession);
21
-
22
- this.objects = objects;
23
- this.states = states;
24
-
25
- this.thersholdInterval = null;
26
- this.cmdSessions = {};
27
-
28
- this.eventsThreshold = {
29
- count: 0,
30
- timeActivated: 0,
31
- active: false,
32
- accidents: 0,
33
- repeatSeconds: 3, // how many seconds continuously must be number of events > value
34
- value: parseInt(adapter.config.thresholdValue, 10) || 200, // how many events allowed in one check interval
35
- checkInterval: 1000 // duration of one check interval
36
- };
37
-
38
- this.cache = {};
39
- this.cacheGB = null; // cache garbage collector
40
- // do not send too many state updates
41
- }
42
-
43
- start(onThresholdChanged) {
44
- // detect event bursts
45
- this.thersholdInterval = setInterval(() => {
46
- if (!this.eventsThreshold.active) {
47
- if (this.eventsThreshold.count > this.eventsThreshold.value) {
48
- this.eventsThreshold.accidents++;
49
-
50
- if (this.eventsThreshold.accidents >= this.eventsThreshold.repeatSeconds) {
51
- this._enableEventThreshold();
52
- }
53
- } else {
54
- this.eventsThreshold.accidents = 0;
55
- }
56
- this.eventsThreshold.count = 0;
57
- } else if (Date.now() - this.eventsThreshold.timeActivated > 60000) {
58
- this.disableEventThreshold();
59
- }
60
- }, this.eventsThreshold.checkInterval);
61
-
62
- this.onThresholdChanged = onThresholdChanged;
63
- }
64
-
65
- async updateRatings(uuid) {
66
- if (!uuid) {
67
- const obj = await this.adapter.getForeignObjectAsync('system.meta.uuid');
68
- uuid = obj.native.uuid;
69
- }
70
-
71
- try {
72
- const response = await axios.get(`https://rating.iobroker.net/rating?uuid=${uuid}`, {
73
- timeout: 15000,
74
- validateStatus: status => status < 400
75
- });
76
- this.adapter._ratings = response.data;
77
- if (
78
- !this.adapter._ratings ||
79
- typeof this.adapter._ratings !== 'object' ||
80
- Array.isArray(this.adapter._ratings)
81
- ) {
82
- this.adapter._ratings = {};
83
- }
84
- this.adapter._ratings.uuid = uuid;
85
-
86
- // auto update only in admin
87
- if (this.adapter.name === 'admin') {
88
- this.adapter.ratingTimeout && clearTimeout(this.adapter.ratingTimeout);
89
- this.adapter.ratingTimeout = setTimeout(() => {
90
- this.adapter.ratingTimeout = null;
91
- this.updateRatings(uuid, true).then(() => this.adapter.log.info('Adapter rating updated'));
92
- }, 24 * 3600000);
93
- }
94
-
95
- return this.adapter._ratings;
96
- } catch (error) {
97
- this.adapter.log.warn(
98
- `Cannot update rating: ${error.response ? error.response.data : error.message || error.code}`
99
- );
100
- }
101
- }
102
-
103
- _readInstanceConfig(id, user, isTab, configs) {
104
- return new Promise(resolve =>
105
- this.adapter.getForeignObject(`system.adapter.${id}`, { user }, (error, obj) => {
106
- if (obj && obj.common) {
107
- const instance = id.split('.').pop();
108
- const config = {
109
- id,
110
- title: obj.common.titleLang || obj.common.title,
111
- desc: obj.common.desc,
112
- color: obj.common.color,
113
- url: `/adapter/${obj.common.name}/${isTab ? 'tab' : 'index'}${
114
- !isTab && obj.common.materialize ? '_m' : ''
115
- }.html${instance ? `?${instance}` : ''}`,
116
- icon: obj.common.icon,
117
- materialize: obj.common.materialize,
118
- jsonConfig: obj.common.jsonConfig,
119
- version: obj.common.version
120
- };
121
- if (isTab) {
122
- config.tab = true;
123
- } else {
124
- config.config = true;
125
- }
126
- /*if (typeof config.title === 'object') {
127
- config.title = config.title[adapter.systemConfig.language] || config.title.en;
128
- }
129
- if (typeof config.desc === 'object') {
130
- config.desc = config.desc[adapter.systemConfig.language] || config.desc.en;
131
- }*/
132
- configs.push(config);
133
- }
134
- resolve();
135
- })
136
- );
137
- }
138
-
139
- _sendToHost(host, command, message, callback) {
140
- const hash = `${host}_${command}`;
141
- if (!message && SocketCommandsAdmin.ALLOW_CACHE.includes(command) && this.cache[hash]) {
142
- if (Date.now() - this.cache[hash].ts < 500) {
143
- return (
144
- typeof callback === 'function' &&
145
- setImmediate(data => callback(data), JSON.parse(this.cache[hash].res))
146
- );
147
- } else {
148
- delete this.cache[hash];
149
- }
150
- }
151
-
152
- try {
153
- this.adapter.sendToHost(host, command, message, res => {
154
- if (!message && SocketCommandsAdmin.ALLOW_CACHE.includes(command)) {
155
- this.cache[hash] = { ts: Date.now(), res: JSON.stringify(res) };
156
-
157
- this.cacheGB =
158
- this.cacheGB ||
159
- setInterval(() => {
160
- const commands = Object.keys(this.cache);
161
- commands.forEach(cmd => {
162
- if (Date.now() - this.cache[cmd].ts > 500) {
163
- delete this.cache[cmd];
164
- }
165
- });
166
- if (!commands.length) {
167
- clearInterval(this.cacheGB);
168
- this.cacheGB = null;
169
- }
170
- }, 2000);
171
- }
172
- typeof callback === 'function' && setImmediate(() => callback(res));
173
- });
174
- } catch (error) {
175
- this.adapter.log.error(`[sendToHost] ERROR: ${error.toString()}`);
176
- typeof callback === 'function' && setImmediate(() => callback({ error }));
177
- }
178
- }
179
-
180
- // remove this function when js.controller 4.x will be mainstream
181
- _readLicenses(login, password) {
182
- const config = {
183
- headers: { Authorization: `Basic ${Buffer.from(`${login}:${password}`).toString('base64')}` },
184
- timeout: 4000,
185
- validateStatus: status => status < 400
186
- };
187
-
188
- return axios
189
- .get(`https://iobroker.net:3001/api/v1/licenses`, config)
190
- .then(response => {
191
- if (response.data && response.data.length) {
192
- const now = Date.now();
193
- response.data = response.data.filter(
194
- license =>
195
- !license.validTill ||
196
- license.validTill === '0000-00-00 00:00:00' ||
197
- new Date(license.validTill).getTime() > now
198
- );
199
- }
200
- return response.data;
201
- })
202
- .catch(error => {
203
- if (error.response) {
204
- throw new Error(
205
- (error.response.data && error.response.data.error) ||
206
- error.response.data ||
207
- error.response.status
208
- );
209
- } else if (error.request) {
210
- throw new Error('no response');
211
- } else {
212
- throw error;
213
- }
214
- });
215
- }
216
-
217
- // remove this function when js.controller 4.x will be mainstream
218
- _updateLicenses(login, password, options) {
219
- // if login and password provided in the message, just try to read without saving it in system.licenses
220
- if (login && password) {
221
- return this._readLicenses(login, password);
222
- } else {
223
- // get actual object
224
- return this.adapter.getForeignObjectAsync('system.licenses', options).then(systemLicenses => {
225
- // If password and login exist
226
- if (
227
- systemLicenses &&
228
- systemLicenses.native &&
229
- systemLicenses.native.password &&
230
- systemLicenses.native.login
231
- ) {
232
- // get the secret to decode the password
233
- return this.adapter
234
- .getForeignObjectAsync('system.config', options)
235
- .then(systemConfig => {
236
- // decode the password
237
- let password;
238
- try {
239
- password = this.adapter.decrypt(
240
- systemConfig.native.secret,
241
- systemLicenses.native.password
242
- );
243
- } catch {
244
- throw new Error('Cannot decode password');
245
- }
246
-
247
- // read licenses from iobroker.net
248
- return this._readLicenses(systemLicenses.native.login, password);
249
- })
250
- .then(licenses => {
251
- // save licenses to system.licenses and remember the time
252
- // merge the information together
253
- const oldLicenses = systemLicenses.native.licenses || [];
254
- systemLicenses.native.licenses = licenses;
255
- oldLicenses.forEach(oldLicense => {
256
- if (oldLicense.usedBy) {
257
- const newLicense = licenses.find(item => item.json === oldLicense.json);
258
- if (newLicense) {
259
- newLicense.usedBy = oldLicense.usedBy;
260
- }
261
- }
262
- });
263
-
264
- systemLicenses.native.readTime = new Date().toISOString();
265
-
266
- // save only if an object changed
267
- return this.adapter
268
- .setForeignObjectAsync('system.licenses', systemLicenses, options)
269
- .then(() => licenses);
270
- })
271
- .catch(error => {
272
- // if password is invalid
273
- if (
274
- error.message.includes('Authentication required') ||
275
- error.message.includes('Cannot decode password')
276
- ) {
277
- // clear existing licenses if exist
278
- if (
279
- systemLicenses &&
280
- systemLicenses.native &&
281
- systemLicenses.native.licenses &&
282
- systemLicenses.native.licenses.length
283
- ) {
284
- systemLicenses.native.licenses = [];
285
- systemLicenses.native.readTime = new Date().toISOString();
286
- return this.adapter
287
- .setForeignObjectAsync('system.licenses', systemLicenses, options)
288
- .then(() => {
289
- throw error;
290
- });
291
- } else {
292
- throw error;
293
- }
294
- } else {
295
- throw error;
296
- }
297
- });
298
- } else {
299
- // if password or login are empty => clear existing licenses if exist
300
- if (
301
- systemLicenses &&
302
- systemLicenses.native &&
303
- systemLicenses.native.licenses &&
304
- systemLicenses.native.licenses.length
305
- ) {
306
- systemLicenses.native.licenses = [];
307
- systemLicenses.native.readTime = new Date().toISOString();
308
- return this.adapter
309
- .setForeignObjectAsync('system.licenses', systemLicenses, options)
310
- .then(() => {
311
- throw new Error('No password or login');
312
- });
313
- } else {
314
- throw new Error('No password or login');
315
- }
316
- }
317
- });
318
- }
319
- }
320
-
321
- disableEventThreshold() {
322
- if (this.eventsThreshold.active) {
323
- this.eventsThreshold.accidents = 0;
324
- this.eventsThreshold.count = 0;
325
- this.eventsThreshold.active = false;
326
- this.eventsThreshold.timeActivated = 0;
327
- this.adapter.log.info('Subscribe to all states again');
328
-
329
- setTimeout(async () => {
330
- this.onThresholdChanged && this.onThresholdChanged(false);
331
- try {
332
- await this.adapter.unsubscribeForeignStatesAsync('system.adapter.*');
333
- } catch (e) {
334
- this.adapter.log.error(`Cannot unsubscribe "system.adapter.*": ${e.message}`);
335
- }
336
-
337
- for (const pattern of Object.keys(this.subscribes.stateChange)) {
338
- try {
339
- await this.adapter.subscribeForeignStatesAsync(pattern);
340
- } catch (e) {
341
- this.adapter.log.error(`Cannot subscribe "${pattern}": ${e.message}`);
342
- }
343
- }
344
- }, 50);
345
- }
346
- }
347
-
348
- _enableEventThreshold() {
349
- if (!this.eventsThreshold.active) {
350
- this.eventsThreshold.active = true;
351
-
352
- setTimeout(async () => {
353
- this.adapter.log.info(
354
- `Unsubscribe from all states, except system's, because over ${this.eventsThreshold.repeatSeconds} seconds the number of events is over ${this.eventsThreshold.value} (in last second ${this.eventsThreshold.count})`
355
- );
356
- this.eventsThreshold.timeActivated = Date.now();
357
-
358
- this.onThresholdChanged && this.onThresholdChanged(true);
359
-
360
- for (const pattern of Object.keys(this.subscribes.stateChange)) {
361
- try {
362
- await this.adapter.unsubscribeForeignStatesAsync(pattern);
363
- } catch (e) {
364
- this.adapter.log.error(`Cannot unsubscribe "${pattern}": ${e.message}`);
365
- }
366
- }
367
-
368
- try {
369
- await this.adapter.subscribeForeignStatesAsync('system.adapter.*');
370
- } catch (e) {
371
- this.adapter.log.error(`Cannot subscribe "system.adapter.*": ${e.message}`);
372
- }
373
- }, 100);
374
- }
375
- }
376
-
377
- _addUser(user, pw, options, callback) {
378
- if (typeof options === 'function') {
379
- callback = options;
380
- options = null;
381
- }
382
-
383
- if (!user.match(/^[-.A-Za-züäößÖÄÜа-яА-Я@+$§0-9=?!&# ]+$/)) {
384
- return SocketCommands._fixCallback(
385
- callback,
386
- 'Invalid characters in the name. Only following special characters are allowed: -@+$§=?!&# and letters'
387
- );
388
- }
389
-
390
- try {
391
- this.adapter.getForeignObject(`system.user.${user}`, options, (error, obj) => {
392
- if (obj) {
393
- SocketCommands._fixCallback(callback, 'User yet exists');
394
- } else {
395
- try {
396
- this.adapter.setForeignObject(
397
- `system.user.${user}`,
398
- {
399
- type: 'user',
400
- common: {
401
- name: user,
402
- enabled: true,
403
- groups: []
404
- }
405
- },
406
- options,
407
- () => {
408
- try {
409
- this.adapter.setPassword(user, pw, options, callback);
410
- } catch (error) {
411
- this.adapter.log.error(`[_addUser] cannot set password: ${error.toString()}`);
412
- SocketCommands._fixCallback(callback, error);
413
- }
414
- }
415
- );
416
- } catch (error) {
417
- this.adapter.log.error(`[_addUser] cannot save user: ${error.toString()}`);
418
- SocketCommands._fixCallback(callback, error);
419
- }
420
- }
421
- });
422
- } catch (error) {
423
- this.adapter.log.error(`[_addUser] cannot read user: ${error.toString()}`);
424
- SocketCommands._fixCallback(callback, error);
425
- }
426
- }
427
-
428
- _delUser(user, options, callback) {
429
- try {
430
- this.adapter.getForeignObject(`system.user.${user}`, options, (error, obj) => {
431
- if (error || !obj) {
432
- SocketCommands._fixCallback(callback, 'User does not exist');
433
- } else {
434
- if (obj.common.dontDelete) {
435
- SocketCommands._fixCallback(callback, 'Cannot delete user, while is system user');
436
- } else {
437
- try {
438
- this.adapter.delForeignObject(`system.user.${user}`, options, error =>
439
- // Remove this user from all groups in web client
440
- SocketCommands._fixCallback(callback, error)
441
- );
442
- } catch (error) {
443
- this.adapter.log.error(`[_delUser] cannot delete user: ${error.toString()}`);
444
- SocketCommands._fixCallback(callback, error);
445
- }
446
- }
447
- }
448
- });
449
- } catch (error) {
450
- this.adapter.log.error(`[_delUser] cannot read user: ${error.toString()}`);
451
- SocketCommands._fixCallback(callback, error);
452
- }
453
- }
454
-
455
- _addGroup(group, desc, acl, options, callback) {
456
- let name = group;
457
- if (typeof acl === 'function') {
458
- callback = acl;
459
- acl = null;
460
- }
461
- if (typeof desc === 'function') {
462
- callback = desc;
463
- desc = null;
464
- }
465
- if (typeof options === 'function') {
466
- callback = options;
467
- options = null;
468
- }
469
- if (name && name.substring(0, 1) !== name.substring(0, 1).toUpperCase()) {
470
- name = name.substring(0, 1).toUpperCase() + name.substring(1);
471
- }
472
- group = group.substring(0, 1).toLowerCase() + group.substring(1);
473
-
474
- if (!group.match(/^[-.A-Za-züäößÖÄÜа-яА-Я@+$§0-9=?!&#_ ]+$/)) {
475
- return SocketCommands._fixCallback(
476
- callback,
477
- 'Invalid characters in the group name. Only following special characters are allowed: -@+$§=?!&# and letters'
478
- );
479
- }
480
-
481
- try {
482
- this.adapter.getForeignObject(`system.group.${group}`, options, (error, obj) => {
483
- if (obj) {
484
- SocketCommands._fixCallback(callback, 'Group yet exists');
485
- } else {
486
- obj = {
487
- _id: 'system.group.' + group,
488
- type: 'group',
489
- common: {
490
- name,
491
- desc,
492
- members: [],
493
- acl
494
- }
495
- };
496
- try {
497
- this.adapter.setForeignObject(`system.group.${group}`, obj, options, error =>
498
- SocketCommands._fixCallback(callback, error, obj)
499
- );
500
- } catch (error) {
501
- this.adapter.log.error(`[_addGroup] cannot write group: ${error.toString()}`);
502
- SocketCommands._fixCallback(callback, error);
503
- }
504
- }
505
- });
506
- } catch (error) {
507
- this.adapter.log.error(`[_addGroup] cannot read group: ${error.toString()}`);
508
- SocketCommands._fixCallback(callback, error);
509
- }
510
- }
511
-
512
- _delGroup(group, options, callback) {
513
- try {
514
- this.adapter.getForeignObject(`system.group.${group}`, options, (error, obj) => {
515
- if (error || !obj) {
516
- SocketCommands._fixCallback(callback, 'Group does not exist');
517
- } else {
518
- if (obj.common.dontDelete) {
519
- SocketCommands._fixCallback(callback, 'Cannot delete group, while is system group');
520
- } else {
521
- try {
522
- this.adapter.delForeignObject(`system.group.${group}`, options, error =>
523
- // Remove this group from all users in the web client
524
- SocketCommands._fixCallback(callback, error)
525
- );
526
- } catch (error) {
527
- this.adapter.log.error(`[_delGroup] cannot delete group: ${error.toString()}`);
528
- SocketCommands._fixCallback(callback, error);
529
- }
530
- }
531
- }
532
- });
533
- } catch (error) {
534
- this.adapter.log.error(`[_delGroup] cannot read group: ${error.toString()}`);
535
- SocketCommands._fixCallback(callback, error);
536
- }
537
- }
538
-
539
- static _checkObject(obj, options, flag) {
540
- // read rights of the object
541
- if (!obj || !obj.common || !obj.acl || flag === 'list') {
542
- return true;
543
- }
544
-
545
- if (options.user !== 'system.user.admin' && !options.groups.includes('system.group.administrator')) {
546
- if (obj.acl.owner !== options.user) {
547
- // Check if the user is in the group
548
- if (options.groups.includes(obj.acl.ownerGroup)) {
549
- // Check group rights
550
- if (!(obj.acl.object & (flag << 4))) {
551
- return false;
552
- }
553
- } else {
554
- // everybody
555
- if (!(obj.acl.object & flag)) {
556
- return false;
557
- }
558
- }
559
- } else {
560
- // Check group rights
561
- if (!(obj.acl.object & (flag << 8))) {
562
- return false;
563
- }
564
- }
565
- }
566
- return true;
567
- }
568
-
569
- _getAllObjects(socket, callback) {
570
- if (typeof callback !== 'function') {
571
- return this.adapter.log.warn('[_getAllObjects] Invalid callback');
572
- }
573
-
574
- if (this._checkPermissions(socket, 'getObjects', callback)) {
575
- if (this.objects) {
576
- if (
577
- socket._acl &&
578
- socket._acl.user !== 'system.user.admin' &&
579
- !socket._acl.groups.includes('system.group.administrator')
580
- ) {
581
- const result = {};
582
- for (const id in this.objects) {
583
- if (
584
- Object.prototype.hasOwnProperty.call(this.objects, id) &&
585
- SocketCommandsAdmin._checkObject(this.objects[id], socket._acl, 4 /* 'read' */)
586
- ) {
587
- result[id] = this.objects[id];
588
- }
589
- }
590
- callback(null, result);
591
- } else {
592
- callback(null, this.objects);
593
- }
594
- } else {
595
- try {
596
- this.adapter.getObjectList({ include_docs: true }, { user: socket._acl.user }, (error, res) => {
597
- this.adapter.log.info('received all objects');
598
- res = res.rows;
599
- const objects = {};
600
-
601
- if (
602
- socket._acl &&
603
- socket._acl.user !== 'system.user.admin' &&
604
- !socket._acl.groups.includes('system.group.administrator')
605
- ) {
606
- for (let i = 0; i < res.length; i++) {
607
- if (SocketCommandsAdmin._checkObject(res[i].doc, socket._acl, 4 /* 'read' */)) {
608
- objects[res[i].doc._id] = res[i].doc;
609
- }
610
- }
611
- callback(null, objects);
612
- } else {
613
- for (let j = 0; j < res.length; j++) {
614
- objects[res[j].doc._id] = res[j].doc;
615
- }
616
- callback(null, objects);
617
- }
618
- });
619
- } catch (error) {
620
- this.adapter.log.error(`[_getAllObjects] ERROR: ${error.toString()}`);
621
- SocketCommands._fixCallback(callback, error);
622
- }
623
- }
624
- }
625
- }
626
-
627
- _initCommandsUser() {
628
- this.commands['addUser'] = (socket, user, pass, callback) => {
629
- // Add new user
630
- // @param {string} user - user name, like `benjamin`
631
- // @param {string} pass - user password
632
- // @param {function} callback - `function (error)`
633
- if (this._checkPermissions(socket, 'addUser', callback, user)) {
634
- this._addUser(user, pass, { user: socket._acl.user }, (error, ...args) =>
635
- SocketCommands._fixCallback(callback, error, ...args)
636
- );
637
- }
638
- };
639
-
640
- this.commands['delUser'] = (socket, user, callback) => {
641
- // Delete existing user. Admin cannot be deleted.
642
- // @param {string} user - user name, like 'benjamin
643
- // @param {function} callback - `function (error)`
644
- if (this._checkPermissions(socket, 'delUser', callback, user)) {
645
- this._delUser(user, { user: socket._acl.user }, (error, ...args) =>
646
- SocketCommands._fixCallback(callback, error, ...args)
647
- );
648
- }
649
- };
650
-
651
- this.commands['addGroup'] = (socket, group, desc, acl, callback) => {
652
- // Add a new group.
653
- // @param {string} group - user name, like 'benjamin
654
- // @param {string} desc - optional description
655
- // @param {object} acl - optional access control list object, like `{"object":{"list":true,"read":true,"write":false,"delete":false},"state":{"list":true,"read":true,"write":true,"create":true,"delete":false},"users":{"list":true,"read":true,"write":false,"create":false,"delete":false},"other":{"execute":false,"http":true,"sendto":false},"file":{"list":true,"read":true,"write":false,"create":false,"delete":false}}`
656
- // @param {function} callback - `function (error)`
657
- if (this._checkPermissions(socket, 'addGroup', callback, group)) {
658
- this._addGroup(group, desc, acl, { user: socket._acl.user }, (error, ...args) =>
659
- SocketCommands._fixCallback(callback, error, ...args)
660
- );
661
- }
662
- };
663
-
664
- this.commands['delGroup'] = (socket, group, callback) => {
665
- // Delete the existing group. Administrator group cannot be deleted.
666
- // @param {string} group - group name, like 'users`
667
- // @param {function} callback - `function (error)`
668
- if (this._checkPermissions(socket, 'delGroup', callback, group)) {
669
- this._delGroup(group, { user: socket._acl.user }, (error, ...args) =>
670
- SocketCommands._fixCallback(callback, error, ...args)
671
- );
672
- }
673
- };
674
-
675
- this.commands['changePassword'] = (socket, user, pass, callback) => {
676
- // Change user password
677
- // @param {string} user - user name, like 'benjamin`
678
- // @param {string} pass - new password
679
- // @param {function} callback - `function (error)`
680
- if (user === socket._acl.user || this._checkPermissions(socket, 'changePassword', callback, user)) {
681
- try {
682
- this.adapter.setPassword(user, pass, { user: socket._acl.user }, (error, ...args) =>
683
- SocketCommands._fixCallback(callback, error, ...args)
684
- );
685
- } catch (error) {
686
- this.adapter.log.error(`[_changePassword] ERROR: ${error.toString()}`);
687
- SocketCommands._fixCallback(callback, error);
688
- }
689
- }
690
- };
691
- }
692
-
693
- _initCommandsAdmin() {
694
- this.commands['getHostByIp'] = (socket, ip, callback) => {
695
- // Read the host object by IP address
696
- // @param {string} ip - ip address. IPv4 or IPv6
697
- // @param {function} callback - `function (ip, obj)`. If host is not found, obj is null
698
- if (typeof callback !== 'function') {
699
- return this.adapter.log.warn('[getHostByIp] Invalid callback');
700
- }
701
- if (this._checkPermissions(socket, 'getHostByIp', ip)) {
702
- try {
703
- this.adapter.getObjectView('system', 'host', {}, { user: socket._acl.user }, (error, data) => {
704
- if (data && data.rows && data.rows.length) {
705
- for (let i = 0; i < data.rows.length; i++) {
706
- const obj = data.rows[i].value;
707
- // if we requested specific name
708
- if (obj.common.hostname === ip) {
709
- return callback(ip, obj);
710
- } else if (obj.native.hardware && obj.native.hardware.networkInterfaces) {
711
- // try to find this IP in the list
712
- const net = obj.native.hardware.networkInterfaces;
713
- for (const eth in net) {
714
- if (!Object.prototype.hasOwnProperty.call(net, eth)) {
715
- continue;
716
- }
717
- for (let j = 0; j < net[eth].length; j++) {
718
- if (net[eth][j].address === ip) {
719
- return callback(ip, obj);
720
- }
721
- }
722
- }
723
- }
724
- }
725
- }
726
-
727
- callback(ip, null);
728
- });
729
- } catch (error) {
730
- this.adapter.log.error(`[_changePassword] ERROR: ${error.toString()}`);
731
- SocketCommands._fixCallback(callback, error);
732
- }
733
- }
734
- };
735
-
736
- this.commands['requireLog'] = (socket, isEnabled, callback) => {
737
- // Activate or deactivate logging events. Events will be sent to the socket as `log` event. Adapter must have `common.logTransporter = true`
738
- // @param {boolean} isEnabled - is logging enabled
739
- // @param {function} callback - `function (error)`
740
- if (this._checkPermissions(socket, 'setObject', callback)) {
741
- if (isEnabled) {
742
- this.subscribe(socket, 'log', 'dummy');
743
- } else {
744
- this.unsubscribe(socket, 'log', 'dummy');
745
- }
746
-
747
- this.adapter.log.level === 'debug' && this._showSubscribes(socket, 'log');
748
-
749
- typeof callback === 'function' && setImmediate(callback, null);
750
- }
751
- };
752
-
753
- this.commands['readLogs'] = (socket, host, callback) => {
754
- // Get logs file from given host
755
- // @param {string} host - host id, like 'system.host.raspberrypi'
756
- // @param {function} callback - `function (error, files)`, where `files` is array of `{fileName: `log/hostname/transport/file`, size: 123}`
757
- if (this._checkPermissions(socket, 'readLogs', callback)) {
758
- let timeout = setTimeout(() => {
759
- if (timeout) {
760
- let result = { list: [] };
761
-
762
- // deliver the file list
763
- try {
764
- const config = this.adapter.systemConfig;
765
- // detect file log
766
- if (config && config.log && config.log.transport) {
767
- for (const transport in config.log.transport) {
768
- if (
769
- Object.prototype.hasOwnProperty.call(config.log.transport, transport) &&
770
- config.log.transport[transport].type === 'file'
771
- ) {
772
- let fileName = config.log.transport[transport].filename || 'log/';
773
- const parts = fileName.replace(/\\/g, '/').split('/');
774
- parts.pop();
775
- fileName = parts.join('/');
776
- if (fileName[0] !== '/' && !fileName.match(/^\W:/)) {
777
- const _filename = path.normalize(__dirname + '/../../../') + fileName;
778
- if (!fs.existsSync(_filename)) {
779
- fileName = path.normalize(__dirname + '/../../') + fileName;
780
- } else {
781
- fileName = _filename;
782
- }
783
- }
784
- if (fs.existsSync(fileName)) {
785
- const files = fs.readdirSync(fileName);
786
-
787
- for (let f = 0; f < files.length; f++) {
788
- try {
789
- if (!files[f].endsWith('-audit.json')) {
790
- const stat = fs.lstatSync(`${fileName}/${files[f]}`);
791
- if (!stat.isDirectory()) {
792
- result.list.push({
793
- fileName: `log/${transport}/${files[f]}`,
794
- size: stat.size
795
- });
796
- }
797
- }
798
- } catch {
799
- // push unchecked
800
- // result.list.push('log/' + transport + '/' + files[f]);
801
- this.adapter.log.error(
802
- `Cannot check file: ${fileName}/${files[f]}`
803
- );
804
- }
805
- }
806
- }
807
- }
808
- }
809
- } else {
810
- result = { error: 'no file loggers' };
811
- }
812
- } catch (error) {
813
- this.adapter.log.error(`Cannot read logs: ${error}`);
814
- result = { error };
815
- }
816
- SocketCommands._fixCallback(callback, result.error, result.list);
817
- }
818
- }, 500);
819
-
820
- this._sendToHost(host, 'getLogFiles', null, result => {
821
- clearTimeout(timeout);
822
- timeout = null;
823
- SocketCommands._fixCallback(callback, result.error, result.list);
824
- });
825
- }
826
- };
827
-
828
- this.commands['delState'] = (socket, id, callback) => {
829
- // Delete state. The corresponding object will be deleted too.
830
- // @param {string} id - state ID
831
- // @param {function} callback - `function (error)`
832
- if (this._checkPermissions(socket, 'delState', callback, id)) {
833
- // clear cache
834
- if (this.states && this.states[id]) {
835
- delete this.states[id];
836
- }
837
- try {
838
- this.adapter.delForeignState(id, { user: socket._acl.user }, (error, ...args) =>
839
- SocketCommands._fixCallback(callback, error, ...args)
840
- );
841
- } catch (error) {
842
- this.adapter.log.error(`[delState] ERROR: ${error.toString()}`);
843
- SocketCommands._fixCallback(callback, error);
844
- }
845
- }
846
- };
847
-
848
- // commands will be executed on host/controller
849
- // following response commands are expected: cmdStdout, cmdStderr, cmdExit
850
- this.commands['cmdExec'] = (socket, host, id, cmd, callback) => {
851
- // Execute the shell command on host/controller. Following response commands are expected: ´cmdStdout, cmdStderr, cmdExit´
852
- // @param {string} host - host name, like 'system.host.raspberrypi'
853
- // @param {string} id - session ID, like `Date.now()´. This session ID will come in events `cmdStdout, cmdStderr, cmdExit`
854
- // @param {string} cmd - command
855
- // @param {function} callback - `function (error)`
856
- if (this._checkPermissions(socket, 'cmdExec', callback, cmd)) {
857
- this.adapter.log.debug(`cmdExec on ${host}(${id}): ${cmd}`);
858
- // remember socket for this ID.
859
- this.cmdSessions[id] = { socket };
860
- try {
861
- this.adapter.sendToHost(host, 'cmdExec', { data: cmd, id });
862
- SocketCommands._fixCallback(callback, null);
863
- } catch (error) {
864
- this.adapter.log.error(`[cmdExec] ERROR: ${error.toString()}`);
865
- SocketCommands._fixCallback(callback, error);
866
- }
867
- }
868
- };
869
-
870
- this.commands['eventsThreshold'] = (socket, isActive) => {
871
- // Used only for admin to the limited number of events to front-end.
872
- // @param {boolean} isActive - if true, then events will be limited
873
- if (!isActive) {
874
- this.disableEventThreshold(true);
875
- } else {
876
- this._enableEventThreshold();
877
- }
878
- };
879
-
880
- this.commands['getRatings'] = (socket, update, callback) => {
881
- // Read ratings of adapters
882
- // @param {boolean} update - if true, the ratings will be read from central server, if false from local cache
883
- // @param {function} callback - `function (error, ratings)`, where `ratings` is object like `{accuweather: {rating: {r: 3.33, c: 3}, 1.2.1: {r: 3, c: 1}},…}`
884
- if (update || !this.adapter._ratings) {
885
- this.updateRatings().then(() => SocketCommands._fixCallback(callback, null, this.adapter._ratings));
886
- } else {
887
- SocketCommands._fixCallback(callback, null, this.adapter._ratings);
888
- }
889
- };
890
-
891
- this.commands['getCurrentInstance'] = (socket, callback) => {
892
- // Return current instance name like `admin.0`
893
- // @param {function} callback - `function (error, namespace)`
894
- SocketCommands._fixCallback(callback, null, this.adapter.namespace);
895
- };
896
-
897
- this.commands['decrypt'] = (socket, encryptedText, callback) => {
898
- // Decrypts text with the system secret key
899
- // @param {string} encryptedText - encrypted text
900
- // @param {function} callback - `function (error, decryptedText)`
901
- if (this.secret) {
902
- SocketCommands._fixCallback(callback, null, this.adapter.decrypt(this.secret, encryptedText));
903
- } else {
904
- try {
905
- this.adapter.getForeignObject('system.config', { user: socket._acl.user }, (error, obj) => {
906
- if (obj && obj.native && obj.native.secret) {
907
- this.secret = obj.native.secret;
908
- SocketCommands._fixCallback(
909
- callback,
910
- null,
911
- this.adapter.decrypt(this.secret, encryptedText)
912
- );
913
- } else {
914
- this.adapter.log.error(`No system.config found: ${error}`);
915
- SocketCommands._fixCallback(callback, error);
916
- }
917
- });
918
- } catch (error) {
919
- this.adapter.log.error(`Cannot decrypt: ${error}`);
920
- SocketCommands._fixCallback(callback, error);
921
- }
922
- }
923
- };
924
-
925
- this.commands['encrypt'] = (socket, plainText, callback) => {
926
- // Encrypts text with the system secret key
927
- // @param {string} plainText - normal text
928
- // @param {function} callback - `function (error, encryptedText)`
929
- if (this.secret) {
930
- SocketCommands._fixCallback(callback, null, this.adapter.encrypt(this.secret, plainText));
931
- } else {
932
- this.adapter.getForeignObject('system.config', { user: socket._acl.user }, (error, obj) => {
933
- if (obj && obj.native && obj.native.secret) {
934
- this.secret = obj.native.secret;
935
- try {
936
- const encrypted = this.adapter.encrypt(this.secret, plainText);
937
- SocketCommands._fixCallback(callback, null, encrypted);
938
- } catch (error) {
939
- this.adapter.log.error(`Cannot encrypt: ${error}`);
940
- SocketCommands._fixCallback(callback, error);
941
- }
942
- } else {
943
- this.adapter.log.error(`No system.config found: ${error}`);
944
- SocketCommands._fixCallback(callback, error);
945
- }
946
- });
947
- }
948
- };
949
-
950
- this.commands['getIsEasyModeStrict'] = (socket, callback) => {
951
- // Returns if admin has easy mode enabled
952
- // @param {function} callback - `function (error, isEasyModeStrict)`
953
- SocketCommands._fixCallback(callback, null, this.adapter.config.accessLimit);
954
- };
955
-
956
- this.commands['getEasyMode'] = (socket, callback) => {
957
- // Get easy mode configuration
958
- // @param {function} callback - `function (error, easyModeConfig)`, where `easyModeConfig` is object like `{strict: true, configs: [{_id: 'system.adapter.javascript.0', common: {...}}, {...}]}`
959
- // }`
960
- if (this._checkPermissions(socket, 'getObject', callback)) {
961
- let user;
962
- if (this.adapter.config.auth) {
963
- user = socket._acl.user;
964
- if (!user.startsWith('system.user.')) {
965
- user = `system.user.${user}`;
966
- }
967
- } else {
968
- user = this.adapter.config.defaultUser;
969
- }
970
-
971
- if (this.adapter.config.accessLimit) {
972
- const configs = [];
973
- const promises = [];
974
- this.adapter.config.accessAllowedConfigs.forEach(id =>
975
- promises.push(this._readInstanceConfig(id, user, false, configs))
976
- );
977
- this.adapter.config.accessAllowedTabs.forEach(id =>
978
- promises.push(this._readInstanceConfig(id, user, true, configs))
979
- );
980
-
981
- Promise.all(promises).then(() => {
982
- callback(null, {
983
- strict: true,
984
- configs
985
- });
986
- });
987
- } else {
988
- this.adapter.getObjectView(
989
- 'system',
990
- 'instance',
991
- { startkey: 'system.adapter.', endkey: 'system.adapter.\u9999' },
992
- { user },
993
- (error, doc) => {
994
- const promises = [];
995
- const configs = [];
996
- if (!error && doc.rows.length) {
997
- for (let i = 0; i < doc.rows.length; i++) {
998
- const obj = doc.rows[i].value;
999
- if (obj.common.noConfig && !obj.common.adminTab) {
1000
- continue;
1001
- }
1002
- if (!obj.common.enabled) {
1003
- continue;
1004
- }
1005
- if (!obj.common.noConfig) {
1006
- promises.push(
1007
- this._readInstanceConfig(
1008
- obj._id.substring('system.adapter.'.length),
1009
- user,
1010
- false,
1011
- configs
1012
- )
1013
- );
1014
- }
1015
- }
1016
- }
1017
- Promise.all(promises).then(() =>
1018
- callback(null, {
1019
- strict: false,
1020
- configs
1021
- })
1022
- );
1023
- }
1024
- );
1025
- }
1026
- }
1027
- };
1028
-
1029
- this.commands['getAdapters'] = (socket, adapterName, callback) => {
1030
- // Read all adapters objects
1031
- // @param {string} adapterName - optional adapter name
1032
- // @param {function} callback - `function (error, results)`, where `results` is array of objects like `{_id: 'system.adapter.javascript', common: {...}}`
1033
- if (typeof callback === 'function' && this._checkPermissions(socket, 'getObject', callback)) {
1034
- this.adapter.getObjectView(
1035
- 'system',
1036
- 'adapter',
1037
- {
1038
- startkey: `system.adapter.${adapterName || ''}`,
1039
- endkey: `system.adapter.${adapterName || '\u9999'}`
1040
- },
1041
- { user: socket._acl.user },
1042
- (error, doc) => {
1043
- if (error) {
1044
- callback(error);
1045
- } else {
1046
- callback(
1047
- null,
1048
- doc.rows
1049
- .filter(
1050
- obj =>
1051
- obj &&
1052
- (!adapterName || (obj.common && obj.common.name === this.adapterName))
1053
- )
1054
- .map(item => {
1055
- const obj = item.value;
1056
- if (obj.common) {
1057
- delete obj.common.news;
1058
- delete obj.native;
1059
- }
1060
- this._fixAdminUI(obj);
1061
- return obj;
1062
- })
1063
- );
1064
- }
1065
- }
1066
- );
1067
- }
1068
- };
1069
-
1070
- this.commands['updateLicenses'] = (socket, login, password, callback) => {
1071
- // Read software licenses (vis, knx, ...) from ioBroker.net cloud for given user
1072
- // @param {string} login - cloud login
1073
- // @param {string} password - cloud password
1074
- // @param {function} callback - `function (error, results)`, where `results` is array of objects like `[{"json":"xxx","id":"ab","email":"dogafox@gmail.com","product":"iobroker.knx.year","version":"2","invoice":"Pxx","uuid":"uuid","time":"2021-11-16T19:53:02.000Z","validTill":"2022-11-16T22:59:59.000Z","datapoints":1000}]`
1075
- if (this._checkPermissions(socket, 'setObject', callback, login, password)) {
1076
- if (this.adapter.supportsFeature('CONTROLLER_LICENSE_MANAGER')) {
1077
- let timeout = setTimeout(() => {
1078
- if (timeout) {
1079
- timeout = null;
1080
- SocketCommands._fixCallback(callback, 'updateLicenses timeout');
1081
- }
1082
- }, 7000);
1083
-
1084
- this._sendToHost(this.adapter.common.host, 'updateLicenses', { login, password }, result => {
1085
- if (timeout) {
1086
- clearTimeout(timeout);
1087
- timeout = null;
1088
- SocketCommands._fixCallback(callback, result.error, result && result.result);
1089
- }
1090
- });
1091
- } else {
1092
- // remove this branch when js-controller 4.x will be mainstream
1093
- this._updateLicenses(login, password, { user: socket._acl.user })
1094
- .then(licenses => SocketCommands._fixCallback(callback, null, licenses))
1095
- .catch(error => SocketCommands._fixCallback(callback, error));
1096
- }
1097
- }
1098
- };
1099
-
1100
- this.commands['getCompactInstances'] = (socket, callback) => {
1101
- // Read all instances in short form to save bandwidth
1102
- // @param {function} callback - `function (error, results)`, where `results` is an object like `{'system.adapter.javascript.0': {adminTab, name, icon, enabled}}`
1103
- if (typeof callback === 'function') {
1104
- if (this._checkPermissions(socket, 'getObject', callback)) {
1105
- this.adapter.getObjectView(
1106
- 'system',
1107
- 'instance',
1108
- { startkey: `system.adapter.`, endkey: `system.adapter.\u9999` },
1109
- { user: socket._acl.user },
1110
- (error, doc) => {
1111
- if (error) {
1112
- callback(error);
1113
- } else {
1114
- // calculate
1115
- const result = {};
1116
-
1117
- doc.rows.forEach(item => {
1118
- const obj = item.value;
1119
- result[item.id] = {
1120
- adminTab: obj.common.adminTab,
1121
- name: obj.common.name,
1122
- icon: obj.common.icon,
1123
- enabled: obj.common.enabled,
1124
- version: obj.common.version
1125
- };
1126
- });
1127
-
1128
- callback(null, result);
1129
- }
1130
- }
1131
- );
1132
- }
1133
- }
1134
- };
1135
-
1136
- this.commands['getCompactAdapters'] = (socket, callback) => {
1137
- // Read all adapters in short for to save bandwidth
1138
- // @param {function} callback - `function (error, results)`, where `results` is an object like `{'javascript': {icon, v: '1.0.1', iv: 'ignoredVersion}}`
1139
- if (typeof callback === 'function') {
1140
- if (this._checkPermissions(socket, 'getObject', callback)) {
1141
- this.adapter.getObjectView(
1142
- 'system',
1143
- 'adapter',
1144
- { startkey: `system.adapter.`, endkey: `system.adapter.\u9999` },
1145
- { user: socket._acl.user },
1146
- (error, doc) => {
1147
- if (error) {
1148
- callback(error);
1149
- } else {
1150
- // calculate
1151
- const result = {};
1152
-
1153
- doc.rows.forEach(item => {
1154
- const obj = item.value;
1155
- if (obj && obj.common && obj.common.name) {
1156
- result[obj.common.name] = { icon: obj.common.icon, v: obj.common.version };
1157
- if (obj.common.ignoreVersion) {
1158
- result[obj.common.name].iv = obj.common.ignoreVersion;
1159
- }
1160
- }
1161
- });
1162
-
1163
- callback(null, result);
1164
- }
1165
- }
1166
- );
1167
- }
1168
- }
1169
- };
1170
-
1171
- this.commands['getCompactInstalled'] = (socket, host, callback) => {
1172
- // Read all installed adapters in short form to save bandwidth
1173
- // @param {function} callback - `function (error, results)`, where `results` is an object like `{'javascript': {version: '1.0.1'}}``
1174
- if (typeof callback === 'function') {
1175
- if (this._checkPermissions(socket, 'sendToHost', callback)) {
1176
- this._sendToHost(host, 'getInstalled', null, data => {
1177
- const result = {};
1178
- Object.keys(data).forEach(name => (result[name] = { version: data[name].version }));
1179
- callback(result);
1180
- });
1181
- }
1182
- }
1183
- };
1184
-
1185
- this.commands['getCompactSystemConfig'] = (socket, callback) => {
1186
- // Read system config in short form to save bandwidth
1187
- // @param {function} callback - `function (error, systemConfig)`, where `systemConfig` is an object like `{common: {...}, native: {secret: 'aaa'}}`
1188
- if (this._checkPermissions(socket, 'getObject', callback)) {
1189
- this.adapter.getForeignObject('system.config', { user: socket._acl.user }, (error, obj) => {
1190
- obj = obj || {};
1191
- const secret = obj && obj.native && obj.native.secret;
1192
- delete obj.native;
1193
- if (secret) {
1194
- obj.native = { secret };
1195
- }
1196
- callback(error, obj);
1197
- });
1198
- }
1199
- };
1200
-
1201
- this.commands['getCompactSystemRepositories'] = (socket, callback) => {
1202
- // Read repositories from cache in short form to save bandwidth
1203
- // @param {function} callback - `function (error, repositories)`, where `repositories` is an object like `{_id: 'system.repositories', common: {...}, native: {repositories: {default: {json: {_repoInfo: {...}}}}}}`
1204
- if (this._checkPermissions(socket, 'getObject', callback)) {
1205
- this.adapter.getForeignObject('system.repositories', { user: socket._acl.user }, (error, obj) => {
1206
- obj &&
1207
- obj.native &&
1208
- obj.native.repositories &&
1209
- Object.keys(obj.native.repositories).forEach(name => {
1210
- if (obj.native.repositories[name].json) {
1211
- // limit information to _repoInfo
1212
- obj.native.repositories[name].json = {
1213
- _repoInfo: obj.native.repositories[name].json._repoInfo
1214
- };
1215
- }
1216
- });
1217
- callback(error, obj);
1218
- });
1219
- }
1220
- };
1221
-
1222
- this.commands['getCompactRepository'] = (socket, host, callback) => {
1223
- // Read current repository in short form to save bandwidth
1224
- // @param {function} callback - `function (error, repository)`, where `repository` is an object like `{'javascript': {version: '1.0.1', icon}, 'admin': {version: '1.0.1', icon}}`
1225
- if (this._checkPermissions(socket, 'sendToHost', callback)) {
1226
- this._sendToHost(host, 'getRepository', null, data => {
1227
- // Extract only the version and icon
1228
- const result = {};
1229
- data &&
1230
- Object.keys(data).forEach(
1231
- name =>
1232
- (result[name] = {
1233
- version: data[name].version,
1234
- icon: data[name].extIcon
1235
- })
1236
- );
1237
- callback(result);
1238
- });
1239
- }
1240
- };
1241
-
1242
- this.commands['getCompactHosts'] = (socket, callback) => {
1243
- // Read all hosts in short form to save bandwidth
1244
- // @param {function} callback - `function (error, hosts)`, where `hosts` is an array of objects like `[{_id:'system.host.raspi',common:{name:'raspi',icon:'icon',color:'blue',installedVersion:'2.1.0'},native:{hardware:{networkInterfaces:[...]}}}]`
1245
- if (this._checkPermissions(socket, 'getObject', callback)) {
1246
- this.adapter.getObjectView(
1247
- 'system',
1248
- 'host',
1249
- { startkey: 'system.host.', endkey: 'system.host.\u9999' },
1250
- { user: socket._acl.user },
1251
- (error, doc) => {
1252
- if (error) {
1253
- callback(error);
1254
- } else {
1255
- const result = [];
1256
- doc.rows.map(item => {
1257
- const host = item.value;
1258
- if (host) {
1259
- host.common = host.common || {};
1260
- result.push({
1261
- _id: host._id,
1262
- common: {
1263
- name: host.common.name,
1264
- icon: host.common.icon,
1265
- color: host.common.color,
1266
- installedVersion: host.common.installedVersion
1267
- },
1268
- native: {
1269
- hardware: {
1270
- networkInterfaces:
1271
- (host.native &&
1272
- host.native.hardware &&
1273
- host.native.hardware.networkInterfaces) ||
1274
- undefined
1275
- }
1276
- }
1277
- });
1278
- }
1279
- });
1280
- callback(null, result);
1281
- }
1282
- }
1283
- );
1284
- }
1285
- };
1286
- }
1287
-
1288
- __initCommandsCommon() {
1289
- super.__initCommandsCommon();
1290
-
1291
- this._initCommandsAdmin();
1292
- this._initCommandsUser();
1293
- }
1294
-
1295
- __initCommandsFiles() {
1296
- super.__initCommandsFiles();
1297
-
1298
- this.commands['writeFile'] = (socket, _adapter, fileName, data64, options, callback) => {
1299
- // Write file into ioBroker DB as base64 string
1300
- // @param {string} _adapter - instance name, e.g. `vis.0`
1301
- // @param {string} fileName - file name, e.g `main/vis-views.json`
1302
- // @param {string} data64 - file content as base64 string
1303
- // @param {object} options - optional `{mode: 0x0644}`
1304
- // @param {function} callback - `function (error)`
1305
- if (this._checkPermissions(socket, 'writeFile', callback, fileName)) {
1306
- if (typeof options === 'function') {
1307
- callback = options;
1308
- options = { user: socket._acl.user };
1309
- }
1310
- options = options || {};
1311
- options.user = socket._acl.user;
1312
-
1313
- try {
1314
- const buffer = Buffer.from(data64, 'base64');
1315
- this.adapter.writeFile(_adapter, fileName, buffer, { user: socket._acl.user }, (error, ...args) =>
1316
- SocketCommands._fixCallback(callback, error, ...args)
1317
- );
1318
- } catch (error) {
1319
- this.adapter.log.error(`[writeFile] Cannot convert data: ${error.toString()}`);
1320
- callback && callback(`Cannot convert data: ${error.toString()}`);
1321
- }
1322
- }
1323
- };
1324
- }
1325
-
1326
- __initCommandsObjects() {
1327
- super.__initCommandsObjects();
1328
-
1329
- this.commands['getAllObjects'] = (socket, callback) => {
1330
- // Read absolutely all objects
1331
- // @param {function} callback - `function (error, objects)`, where `objects` is an object like `{'system.adapter.admin.0': {...}, 'system.adapter.web.0': {...}}`
1332
- return this._getAllObjects(socket, callback);
1333
- };
1334
-
1335
- // Identical to getAllObjects
1336
- this.commands['getObjects'] = (socket, list, callback) => {
1337
- // Read absolutely all objects. Same as `getAllObjects`.
1338
- // @param {string[]} list - optional list of IDs.
1339
- // @param {function} callback - `function (error, objects)`, where `objects` is an object like `{'system.adapter.admin.0': {...}, 'system.adapter.web.0': {...}}`
1340
- if (typeof list === 'function') {
1341
- callback = list;
1342
- list = null;
1343
- }
1344
- if (list && list.length) {
1345
- if (this._checkPermissions(socket, 'getObject', callback)) {
1346
- if (typeof callback === 'function') {
1347
- try {
1348
- this.adapter.getForeignObjects(list, { user: socket._acl.user }, (error, objs) =>
1349
- SocketCommands._fixCallback(callback, error, objs)
1350
- );
1351
- } catch (error) {
1352
- this.adapter.log.error(`[getObjects] ERROR: ${error.toString()}`);
1353
- SocketCommands._fixCallback(callback, error);
1354
- }
1355
- } else {
1356
- this.adapter.log.warn('[getObjects] Invalid callback');
1357
- }
1358
- }
1359
- } else {
1360
- return this._getAllObjects(socket, callback);
1361
- }
1362
- };
1363
-
1364
- this.commands['extendObject'] = (socket, id, obj, callback) => {
1365
- // Extend the existing object
1366
- // @param {string} id - object ID
1367
- // @param {object} obj - new parts of the object, like `{common: {name: 'new name'}}`
1368
- // @param {function} callback - `function (error)`
1369
- if (this._checkPermissions(socket, 'extendObject', callback, id)) {
1370
- try {
1371
- this.adapter.extendForeignObject(id, obj, { user: socket._acl.user }, (error, ...args) =>
1372
- SocketCommands._fixCallback(callback, error, ...args)
1373
- );
1374
- } catch (error) {
1375
- this.adapter.log.error(`[extendObject] ERROR: ${error}`);
1376
- SocketCommands._fixCallback(callback, error);
1377
- }
1378
- }
1379
- };
1380
-
1381
- this.commands['getForeignObjects'] = (socket, pattern, type, callback) => {
1382
- // Read objects by pattern
1383
- // @param {string} pattern - pattern like `system.adapter.admin.0.*`
1384
- // @param {string} type - type of objects to delete, like `state`, `channel`, `device`, `host`, `adapter`. Default - `state`
1385
- // @param {function} callback - `function (error, objects)`, where `objects` is an object like `{'system.adapter.admin.0': {...}, 'system.adapter.web.0': {...}}`
1386
- if (this._checkPermissions(socket, 'getObjects', callback)) {
1387
- if (typeof type === 'function') {
1388
- callback = type;
1389
- type = undefined;
1390
- }
1391
-
1392
- if (typeof callback === 'function') {
1393
- try {
1394
- this.adapter.getForeignObjects(pattern, type, { user: socket._acl.user }, (error, ...args) =>
1395
- SocketCommands._fixCallback(callback, error, ...args)
1396
- );
1397
- } catch (error) {
1398
- this.adapter.log.error(`[extendObject] ERROR: ${error}`);
1399
- SocketCommands._fixCallback(callback, error);
1400
- }
1401
- } else {
1402
- this.adapter.log.warn('[getObjects] Invalid callback');
1403
- }
1404
- }
1405
- };
1406
-
1407
- this.commands['delObject'] = (socket, id, options, callback) => {
1408
- // Delete an object or objects recursively. Objects with `dontDelete` cannot be deleted.
1409
- // @param {string} id - Object ID like, 'adapterName.0.channel'
1410
- // @param {string} options - `{recursive: true}`
1411
- // @param {function} callback - `function (error)`
1412
- if (this._checkPermissions(socket, 'delObject', callback, id)) {
1413
- if (typeof options === 'function') {
1414
- callback = options;
1415
- options = null;
1416
- }
1417
- if (!options || typeof options !== 'object') {
1418
- options = {};
1419
- }
1420
- options.user = socket._acl.user;
1421
- try {
1422
- // options.recursive = true; // the only difference between delObject and delObjects is this line
1423
- this.adapter.delForeignObject(id, options, (error, ...args) =>
1424
- SocketCommands._fixCallback(callback, error, ...args)
1425
- );
1426
- } catch (error) {
1427
- this.adapter.log.error(`[delObject] ERROR: ${error}`);
1428
- SocketCommands._fixCallback(callback, error);
1429
- }
1430
- }
1431
- };
1432
-
1433
- this.commands['delObjects'] = (socket, id, options, callback) => {
1434
- // Delete objects recursively. Objects with `dontDelete` cannot be deleted. Same as `delObject` but with `recursive: true`.
1435
- // @param {string} id - Object ID like, 'adapterName.0.channel'
1436
- // @param {string} options - optional
1437
- // @param {function} callback - `function (error)`
1438
- if (this._checkPermissions(socket, 'delObject', callback, id)) {
1439
- if (!options || typeof options !== 'object') {
1440
- options = {};
1441
- }
1442
- options.user = socket._acl.user;
1443
- options.recursive = true; // the only difference between delObject and delObjects is this line
1444
- try {
1445
- this.adapter.delForeignObject(id, options, (error, ...args) =>
1446
- SocketCommands._fixCallback(callback, error, ...args)
1447
- );
1448
- } catch (error) {
1449
- this.adapter.log.error(`[delObjects] ERROR: ${error}`);
1450
- SocketCommands._fixCallback(callback, error);
1451
- }
1452
- }
1453
- };
1454
- }
1455
-
1456
- stateChange(id, state) {
1457
- if (this.states) {
1458
- if (!state) {
1459
- if (this.states[id]) {
1460
- delete this.states[id];
1461
- }
1462
- } else {
1463
- this.states[id] = state;
1464
- }
1465
- }
1466
-
1467
- if (!this.eventsThreshold.active) {
1468
- this.eventsThreshold.count++;
1469
- }
1470
- }
1471
-
1472
- sendCommand(obj) {
1473
- if (this.cmdSessions[obj.message.id]) {
1474
- if (obj.command === 'cmdExit') {
1475
- delete this.cmdSessions[obj.message.id];
1476
- }
1477
- return true;
1478
- }
1479
- }
1480
-
1481
- destroy() {
1482
- this.thersholdInterval && clearInterval(this.thersholdInterval);
1483
- this.thersholdInterval = null;
1484
-
1485
- this.cacheGB && clearInterval(this.cacheGB);
1486
- this.cacheGB = null;
1487
-
1488
- super.destroy();
1489
- }
1490
- }
1491
-
1492
- module.exports = SocketCommandsAdmin;