@iobroker/db-objects-file 4.0.0-alpha.9-20211115-5dac659e → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Object DB in memory - Server
3
3
  *
4
- * Copyright 2013-2021 bluefox <dogafox@gmail.com>
4
+ * Copyright 2013-2022 bluefox <dogafox@gmail.com>
5
5
  *
6
6
  * MIT License
7
7
  *
@@ -13,19 +13,18 @@
13
13
  /* jshint -W061 */
14
14
  'use strict';
15
15
 
16
- const fs = require('fs-extra');
17
- const path = require('path');
18
- const InMemoryFileDB = require('@iobroker/db-base').inMemoryFileDB;
19
- const tools = require('@iobroker/db-base').tools;
20
- const utils = require('@iobroker/db-objects-redis').objectsUtils;
21
- const deepClone = require('deep-clone');
16
+ const fs = require('fs-extra');
17
+ const path = require('path');
18
+ const InMemoryFileDB = require('@iobroker/db-base').inMemoryFileDB;
19
+ const tools = require('@iobroker/db-base').tools;
20
+ const utils = require('@iobroker/db-objects-redis').objectsUtils;
21
+ const deepClone = require('deep-clone');
22
22
 
23
23
  /**
24
24
  * This class inherits InMemoryFileDB class and adds all relevant logic for objects
25
25
  * including the available methods for use by js-controller directly
26
26
  **/
27
27
  class ObjectsInMemoryFileDB extends InMemoryFileDB {
28
-
29
28
  constructor(settings) {
30
29
  settings = settings || {};
31
30
  settings.fileDB = {
@@ -46,8 +45,10 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
46
45
  this.preserveSettings = ['custom'];
47
46
  this.defaultNewAcl = this.settings.defaultNewAcl || null;
48
47
  this.namespace = this.settings.namespace || this.settings.hostname || '';
49
- this.writeFileInterval = this.settings.connection && typeof this.settings.connection.writeFileInterval === 'number' ?
50
- parseInt(this.settings.connection.writeFileInterval) : 5000;
48
+ this.writeFileInterval =
49
+ this.settings.connection && typeof this.settings.connection.writeFileInterval === 'number'
50
+ ? parseInt(this.settings.connection.writeFileInterval)
51
+ : 5000;
51
52
  this.log.silly(`${this.namespace} Objects DB uses file write interval of ${this.writeFileInterval} ms`);
52
53
 
53
54
  this.objectsDir = path.join(this.dataDir, 'files');
@@ -57,15 +58,18 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
57
58
 
58
59
  // Handle some < js-controller 2.0 broken objects and correct them
59
60
  for (const key of Object.keys(this.dataset)) {
60
- if (typeof this.dataset[key] === 'object' && this.dataset[key].acl && this.dataset[key].acl.permissions && !this.dataset[key].acl.object) {
61
- this.dataset[key].acl.object = this.dataset[key].acl.permissions;
62
- delete this.dataset[key].acl.permissions;
61
+ const obj = this.dataset[key];
62
+ if (tools.isObject(obj) && obj.acl && obj.acl.permissions && !obj.acl.object) {
63
+ obj.acl.object = obj.acl.permissions;
64
+ delete obj.acl.permissions;
65
+ this.dataset[key] = obj;
63
66
  }
64
67
  }
65
68
 
66
69
  // init default new acl
67
- if (this.dataset['system.config'] && this.dataset['system.config'].common && this.dataset['system.config'].common.defaultNewAcl) {
68
- this.defaultNewAcl = deepClone(this.dataset['system.config'].common.defaultNewAcl);
70
+ const configObj = this.dataset['system.config'];
71
+ if (configObj && configObj.common && configObj.common.defaultNewAcl) {
72
+ this.defaultNewAcl = deepClone(configObj.common.defaultNewAcl);
69
73
  }
70
74
  }
71
75
 
@@ -175,17 +179,8 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
175
179
 
176
180
  const res = this._getObjectView('system', 'meta', null);
177
181
 
178
- // collect Meta objects
179
- const metaObjects = {};
180
- res.rows.forEach(obj => {
181
- if (!obj || !obj.value || !obj.value.common || !obj.value.common.type) {
182
- return;
183
- }
184
- if (limitId && obj.id !== limitId) {
185
- return;
186
- }
187
- metaObjects[obj.id] = obj.value.common.type;
188
- });
182
+ // collect meta ids to generate warning if non existing
183
+ const metaIds = res.rows.map(obj => obj.id).filter(id => !limitId || limitId === id);
189
184
 
190
185
  if (!fs.existsSync(this.objectsDir)) {
191
186
  return {
@@ -207,8 +202,10 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
207
202
  if (limitId && dir !== limitId) {
208
203
  return;
209
204
  }
210
- if (!metaObjects[dir]) {
211
- resNotifies.push(`Ignoring Directory "${dir}" because officially not created as meta object. Please remove directory!`);
205
+ if (!metaIds.includes(dir)) {
206
+ resNotifies.push(
207
+ `Ignoring Directory "${dir}" because officially not created as meta object. Please remove directory!`
208
+ );
212
209
  return;
213
210
  }
214
211
  this._loadFileSettings(dir);
@@ -219,21 +216,27 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
219
216
  return;
220
217
  }
221
218
  if (!this.fileOptions[dir][localFile]) {
222
- const fileStat = fs.statSync(file);
223
- const ext = path.extname(localFile);
224
- const mime = utils.getMimeType(ext);
225
- const _mimeType = mime.mimeType;
226
- const isBinary = mime.isBinary;
219
+ const fileStat = fs.statSync(file);
220
+ const ext = path.extname(localFile);
221
+ const mime = utils.getMimeType(ext);
222
+ const _mimeType = mime.mimeType;
223
+ const isBinary = mime.isBinary;
227
224
 
228
225
  this.fileOptions[dir][localFile] = {
229
226
  createdAt: fileStat.ctimeMs,
230
- acl : {
231
- owner: (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
232
- ownerGroup: (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) || utils.CONSTS.SYSTEM_ADMIN_GROUP,
233
- permissions: (this.defaultNewAcl && this.defaultNewAcl.file) || (utils.CONSTS.ACCESS_USER_RW | utils.CONSTS.ACCESS_GROUP_READ | utils.CONSTS.ACCESS_EVERY_READ)// 0x644
227
+ acl: {
228
+ owner: (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
229
+ ownerGroup:
230
+ (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) ||
231
+ utils.CONSTS.SYSTEM_ADMIN_GROUP,
232
+ permissions:
233
+ (this.defaultNewAcl && this.defaultNewAcl.file) ||
234
+ utils.CONSTS.ACCESS_USER_RW |
235
+ utils.CONSTS.ACCESS_GROUP_READ |
236
+ utils.CONSTS.ACCESS_EVERY_READ // 0x644
234
237
  },
235
- mimeType : _mimeType,
236
- binary : isBinary,
238
+ mimeType: _mimeType,
239
+ binary: isBinary,
237
240
  modifiedAt: fileStat.mtimeMs
238
241
  };
239
242
  dirSynced++;
@@ -252,7 +255,7 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
252
255
  // needed by server
253
256
  _writeFile(id, name, data, options) {
254
257
  if (typeof options === 'string') {
255
- options = {mimeType: options};
258
+ options = { mimeType: options };
256
259
  }
257
260
  if (options && options.acl) {
258
261
  options.acl = null;
@@ -276,33 +279,49 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
276
279
  fs.mkdirSync(path.join(this.objectsDir, id));
277
280
  }
278
281
  } catch (e) {
279
- this.log.error(`${this.namespace} Cannot create directories: ${path.join(this.objectsDir, id)}: ${e.message}`);
280
- this.log.error(`${this.namespace} Check the permissions! Or run installation fixer or "iobroker fix" command!`);
282
+ this.log.error(
283
+ `${this.namespace} Cannot create directories: ${path.join(this.objectsDir, id)}: ${e.message}`
284
+ );
285
+ this.log.error(
286
+ `${this.namespace} Check the permissions! Or run installation fixer or "iobroker fix" command!`
287
+ );
281
288
  throw e;
282
289
  }
283
290
 
284
- const ext = path.extname(name);
285
- const mime = utils.getMimeType(ext);
286
- const _mimeType = mime.mimeType;
287
- const isBinary = mime.isBinary;
288
-
289
- this.fileOptions[id][name] = this.fileOptions[id][name] || {createdAt: Date.now()};
290
- this.fileOptions[id][name].acl = this.fileOptions[id][name].acl || {
291
- owner: options.user || (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
292
- ownerGroup: options.group || (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) || utils.CONSTS.SYSTEM_ADMIN_GROUP,
293
- permissions: options.mode || (this.defaultNewAcl && this.defaultNewAcl.file) || (utils.CONSTS.ACCESS_USER_RW | utils.CONSTS.ACCESS_GROUP_READ | utils.CONSTS.ACCESS_EVERY_READ)// 0x644
291
+ const ext = path.extname(name);
292
+ const mime = utils.getMimeType(ext);
293
+ const _mimeType = mime.mimeType;
294
+ const isBinary = mime.isBinary;
295
+
296
+ this.fileOptions[id][name] = this.fileOptions[id][name] || { createdAt: Date.now() };
297
+ this.fileOptions[id][name].acl = this.fileOptions[id][name].acl || {
298
+ owner: options.user || (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
299
+ ownerGroup:
300
+ options.group ||
301
+ (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) ||
302
+ utils.CONSTS.SYSTEM_ADMIN_GROUP,
303
+ permissions:
304
+ options.mode ||
305
+ (this.defaultNewAcl && this.defaultNewAcl.file) ||
306
+ utils.CONSTS.ACCESS_USER_RW | utils.CONSTS.ACCESS_GROUP_READ | utils.CONSTS.ACCESS_EVERY_READ // 0x644
294
307
  };
295
308
 
296
- this.fileOptions[id][name].mimeType = options.mimeType || _mimeType;
297
- this.fileOptions[id][name].binary = isBinary;
298
- this.fileOptions[id][name].acl.ownerGroup = this.fileOptions[id][name].acl.ownerGroup || (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) || utils.CONSTS.SYSTEM_ADMIN_GROUP;
299
- this.fileOptions[id][name].modifiedAt = Date.now();
309
+ this.fileOptions[id][name].mimeType = options.mimeType || _mimeType;
310
+ this.fileOptions[id][name].binary = isBinary;
311
+ this.fileOptions[id][name].acl.ownerGroup =
312
+ this.fileOptions[id][name].acl.ownerGroup ||
313
+ (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) ||
314
+ utils.CONSTS.SYSTEM_ADMIN_GROUP;
315
+ this.fileOptions[id][name].modifiedAt = Date.now();
300
316
 
301
317
  try {
302
318
  // Create directories if complex structure
303
319
  fs.ensureDirSync(path.join(this.objectsDir, id, path.dirname(name)));
304
320
  // Store file
305
- fs.writeFileSync(path.join(this.objectsDir, id, name), data, {'flag': 'w', 'encoding': isBinary ? 'binary' : 'utf8'});
321
+ fs.writeFileSync(path.join(this.objectsDir, id, name), data, {
322
+ flag: 'w',
323
+ encoding: isBinary ? 'binary' : 'utf8'
324
+ });
306
325
 
307
326
  if (isBinary) {
308
327
  // Reload by read
@@ -314,7 +333,9 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
314
333
  // Store dir description
315
334
  this._saveFileSettings(id);
316
335
  } catch (e) {
317
- this.log.error(`${this.namespace} Cannot write files: ${path.join(this.objectsDir, id, name)}: ${e.message}`);
336
+ this.log.error(
337
+ `${this.namespace} Cannot write files: ${path.join(this.objectsDir, id, name)}: ${e.message}`
338
+ );
318
339
  throw e;
319
340
  }
320
341
  }
@@ -341,19 +362,31 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
341
362
  // Create description object if not exists
342
363
  this.fileOptions[id][name] = this.fileOptions[id][name] || {
343
364
  acl: {
344
- owner: (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
345
- ownerGroup: (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) || utils.CONSTS.SYSTEM_ADMIN_GROUP,
346
- permissions: (this.defaultNewAcl && this.defaultNewAcl.file.permissions) || (utils.CONSTS.ACCESS_USER_ALL | utils.CONSTS.ACCESS_GROUP_ALL | utils.CONSTS.ACCESS_EVERY_ALL) // 777
347
-
365
+ owner: (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
366
+ ownerGroup:
367
+ (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) ||
368
+ utils.CONSTS.SYSTEM_ADMIN_GROUP,
369
+ permissions:
370
+ (this.defaultNewAcl && this.defaultNewAcl.file.permissions) ||
371
+ utils.CONSTS.ACCESS_USER_ALL |
372
+ utils.CONSTS.ACCESS_GROUP_ALL |
373
+ utils.CONSTS.ACCESS_EVERY_ALL // 777
348
374
  }
349
375
  };
350
376
  if (typeof this.fileOptions[id][name] !== 'object') {
351
377
  this.fileOptions[id][name] = {
352
- mimeType: this.fileOptions[id][name],
378
+ mimeType: this.fileOptions[id][name],
353
379
  acl: {
354
- owner: (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
355
- ownerGroup: (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) || utils.CONSTS.SYSTEM_ADMIN_GROUP,
356
- permissions: (this.defaultNewAcl && this.defaultNewAcl.file.permissions) || (utils.CONSTS.ACCESS_USER_ALL | utils.CONSTS.ACCESS_GROUP_ALL | utils.CONSTS.ACCESS_EVERY_ALL) // 777
380
+ owner:
381
+ (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
382
+ ownerGroup:
383
+ (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) ||
384
+ utils.CONSTS.SYSTEM_ADMIN_GROUP,
385
+ permissions:
386
+ (this.defaultNewAcl && this.defaultNewAcl.file.permissions) ||
387
+ utils.CONSTS.ACCESS_USER_ALL |
388
+ utils.CONSTS.ACCESS_GROUP_ALL |
389
+ utils.CONSTS.ACCESS_EVERY_ALL // 777
357
390
  }
358
391
  };
359
392
  }
@@ -362,7 +395,7 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
362
395
  if (this.fileOptions[id][name].binary === undefined) {
363
396
  const ext = path.extname(name);
364
397
  const mimeType = utils.getMimeType(ext);
365
- this.fileOptions[id][name].binary = mimeType.isBinary;
398
+ this.fileOptions[id][name].binary = mimeType.isBinary;
366
399
  this.fileOptions[id][name].mimeType = mimeType.mimeType;
367
400
  }
368
401
 
@@ -375,7 +408,7 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
375
408
  if (this.fileOptions[id][name] !== undefined) {
376
409
  delete this.fileOptions[id][name];
377
410
  }
378
- if (this.files[id][name] !== undefined) {
411
+ if (this.files[id][name] !== undefined) {
379
412
  delete this.files[id][name];
380
413
  }
381
414
  }
@@ -384,9 +417,12 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
384
417
  if (this.fileOptions[id][name] && !this.fileOptions[id][name].acl) {
385
418
  // all files belongs to admin by default, but everyone can edit it
386
419
  this.fileOptions[id][name].acl = {
387
- owner: (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
388
- ownerGroup: (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) || utils.CONSTS.SYSTEM_ADMIN_GROUP,
389
- permissions: (this.defaultNewAcl && this.defaultNewAcl.file.permissions) || (utils.CONSTS.ACCESS_USER_ALL | utils.CONSTS.ACCESS_GROUP_ALL | utils.CONSTS.ACCESS_EVERY_RW) // 776
420
+ owner: (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
421
+ ownerGroup:
422
+ (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) || utils.CONSTS.SYSTEM_ADMIN_GROUP,
423
+ permissions:
424
+ (this.defaultNewAcl && this.defaultNewAcl.file.permissions) ||
425
+ utils.CONSTS.ACCESS_USER_ALL | utils.CONSTS.ACCESS_GROUP_ALL | utils.CONSTS.ACCESS_EVERY_RW // 776
390
426
  };
391
427
  }
392
428
 
@@ -487,7 +523,7 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
487
523
  // needed by server
488
524
  _unlink(id, name) {
489
525
  const _path = utils.sanitizePath(id, name);
490
- id = _path.id;
526
+ id = _path.id;
491
527
  name = _path.name;
492
528
 
493
529
  this._loadFileSettings(id);
@@ -514,7 +550,6 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
514
550
  if (this.files[id] && this.files[id]) {
515
551
  delete this.files[id];
516
552
  }
517
-
518
553
  } else {
519
554
  this.log.debug('Delete file ' + path.join(id, name));
520
555
  try {
@@ -563,7 +598,7 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
563
598
 
564
599
  this._loadFileSettings(id);
565
600
 
566
- const len = (name) ? name.length : 0;
601
+ const len = name ? name.length : 0;
567
602
  for (const f of Object.keys(this.fileOptions[id])) {
568
603
  if (!name || f.substring(0, len) === name) {
569
604
  /** @type {string|string[]} */
@@ -599,28 +634,50 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
599
634
  if (fs.existsSync(path.join(location, _files[j]))) {
600
635
  try {
601
636
  const stats = fs.statSync(path.join(location, _files[j]));
602
- const acl = (this.fileOptions[id][name + _files[j]] && this.fileOptions[id][name + _files[j]].acl) ?
603
- JSON.parse(JSON.stringify(this.fileOptions[id][name + _files[j]].acl)) : // copy settings
604
- {
605
- read: true,
606
- write : true,
607
- owner: (this.defaultNewAcl && this.defaultNewAcl.owner) || utils.CONSTS.SYSTEM_ADMIN_USER,
608
- ownerGroup: (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) || utils.CONSTS.SYSTEM_ADMIN_GROUP,
609
- permissions: (this.defaultNewAcl && this.defaultNewAcl.file.permissions) || (utils.CONSTS.ACCESS_USER_RW | utils.CONSTS.ACCESS_GROUP_READ | utils.CONSTS.ACCESS_EVERY_READ)
610
- };
637
+ const acl =
638
+ this.fileOptions[id][name + _files[j]] && this.fileOptions[id][name + _files[j]].acl
639
+ ? JSON.parse(JSON.stringify(this.fileOptions[id][name + _files[j]].acl)) // copy settings
640
+ : {
641
+ read: true,
642
+ write: true,
643
+ owner:
644
+ (this.defaultNewAcl && this.defaultNewAcl.owner) ||
645
+ utils.CONSTS.SYSTEM_ADMIN_USER,
646
+ ownerGroup:
647
+ (this.defaultNewAcl && this.defaultNewAcl.ownerGroup) ||
648
+ utils.CONSTS.SYSTEM_ADMIN_GROUP,
649
+ permissions:
650
+ (this.defaultNewAcl && this.defaultNewAcl.file.permissions) ||
651
+ utils.CONSTS.ACCESS_USER_RW |
652
+ utils.CONSTS.ACCESS_GROUP_READ |
653
+ utils.CONSTS.ACCESS_EVERY_READ
654
+ };
611
655
 
612
656
  // if filter for user
613
657
  if (options.filter && acl) {
614
658
  // If user may not write
615
- if (!options.acl.file.write) {// write
616
- acl.permissions &= ~(utils.CONSTS.ACCESS_USER_WRITE | utils.CONSTS.ACCESS_GROUP_WRITE | utils.CONSTS.ACCESS_EVERY_WRITE);
659
+ if (!options.acl.file.write) {
660
+ // write
661
+ acl.permissions &= ~(
662
+ utils.CONSTS.ACCESS_USER_WRITE |
663
+ utils.CONSTS.ACCESS_GROUP_WRITE |
664
+ utils.CONSTS.ACCESS_EVERY_WRITE
665
+ );
617
666
  }
618
667
  // If user may not read
619
- if (!options.acl.file.read) {// read
620
- acl.permissions &= ~(utils.CONSTS.ACCESS_USER_READ | utils.CONSTS.ACCESS_GROUP_READ | utils.CONSTS.ACCESS_EVERY_READ);
668
+ if (!options.acl.file.read) {
669
+ // read
670
+ acl.permissions &= ~(
671
+ utils.CONSTS.ACCESS_USER_READ |
672
+ utils.CONSTS.ACCESS_GROUP_READ |
673
+ utils.CONSTS.ACCESS_EVERY_READ
674
+ );
621
675
  }
622
676
 
623
- if (options.user !== utils.CONSTS.SYSTEM_ADMIN_USER && options.groups.includes(utils.CONSTS.SYSTEM_ADMIN_GROUP)) {
677
+ if (
678
+ options.user !== utils.CONSTS.SYSTEM_ADMIN_USER &&
679
+ options.groups.includes(utils.CONSTS.SYSTEM_ADMIN_GROUP)
680
+ ) {
624
681
  if (acl.owner !== options.user) {
625
682
  // Check if the user is in the group
626
683
  if (options.groups.includes(acl.ownerGroup)) {
@@ -628,14 +685,14 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
628
685
  if (!(acl.permissions & utils.CONSTS.ACCESS_GROUP_RW)) {
629
686
  continue;
630
687
  }
631
- acl.read = !!(acl.permissions & utils.CONSTS.ACCESS_GROUP_READ);
688
+ acl.read = !!(acl.permissions & utils.CONSTS.ACCESS_GROUP_READ);
632
689
  acl.write = !!(acl.permissions & utils.CONSTS.ACCESS_GROUP_WRITE);
633
690
  } else {
634
691
  // everybody
635
692
  if (!(acl.permissions & utils.CONSTS.ACCESS_EVERY_RW)) {
636
693
  continue;
637
694
  }
638
- acl.read = !!(acl.permissions & utils.CONSTS.ACCESS_EVERY_READ);
695
+ acl.read = !!(acl.permissions & utils.CONSTS.ACCESS_EVERY_READ);
639
696
  acl.write = !!(acl.permissions & utils.CONSTS.ACCESS_EVERY_WRITE);
640
697
  }
641
698
  } else {
@@ -643,26 +700,36 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
643
700
  if (!(acl.permissions & utils.CONSTS.ACCESS_USER_RW)) {
644
701
  continue;
645
702
  }
646
- acl.read = !!(acl.permissions & utils.CONSTS.ACCESS_USER_READ);
703
+ acl.read = !!(acl.permissions & utils.CONSTS.ACCESS_USER_READ);
647
704
  acl.write = !!(acl.permissions & utils.CONSTS.ACCESS_USER_WRITE);
648
705
  }
649
706
  } else {
650
- acl.read = true;
707
+ acl.read = true;
651
708
  acl.write = true;
652
709
  }
653
710
  }
654
711
 
655
712
  res.push({
656
- file: _files[j],
657
- stats: stats,
658
- isDir: stats.isDirectory(),
659
- acl: acl,
660
- modifiedAt: this.fileOptions[id][name + _files[j]] ? this.fileOptions[id][name + _files[j]].modifiedAt : undefined,
661
- createdAt: this.fileOptions[id][name + _files[j]] ? this.fileOptions[id][name + _files[j]].createdAt : undefined
713
+ file: _files[j],
714
+ stats: stats,
715
+ isDir: stats.isDirectory(),
716
+ acl: acl,
717
+ modifiedAt: this.fileOptions[id][name + _files[j]]
718
+ ? this.fileOptions[id][name + _files[j]].modifiedAt
719
+ : undefined,
720
+ createdAt: this.fileOptions[id][name + _files[j]]
721
+ ? this.fileOptions[id][name + _files[j]].createdAt
722
+ : undefined
662
723
  });
663
-
664
724
  } catch (e) {
665
- this.log.error(`${this.namespace} Cannot read permissions of ${path.join(this.objectsDir, id, name, _files[j])}: ${e.message}`);
725
+ this.log.error(
726
+ `${this.namespace} Cannot read permissions of ${path.join(
727
+ this.objectsDir,
728
+ id,
729
+ name,
730
+ _files[j]
731
+ )}: ${e.message}`
732
+ );
666
733
  }
667
734
  }
668
735
  }
@@ -723,6 +790,9 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
723
790
  this.handleSubscribe(client, 'objects', pattern);
724
791
  }
725
792
 
793
+ _subscribeMeta(client, pattern) {
794
+ this.handleSubscribe(client, 'meta', pattern);
795
+ }
726
796
  // needed by server
727
797
  _unsubscribeConfigForClient(client, pattern) {
728
798
  this.handleUnsubscribe(client, 'objects', pattern); // ignore options => unsubscribe may everyone
@@ -750,12 +820,55 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
750
820
  return keys.map(id => this.dataset[id]);
751
821
  }
752
822
 
823
+ _ensureMetaDict() {
824
+ let meta = this.dataset['**META**'];
825
+ if (!meta) {
826
+ meta = {};
827
+ this.dataset['**META**'] = meta;
828
+ }
829
+ return meta;
830
+ }
831
+
832
+ /**
833
+ * Get value of given meta id
834
+ *
835
+ * @param {string} id
836
+ * @returns {*}
837
+ */
838
+ getMeta(id) {
839
+ const meta = this._ensureMetaDict();
840
+ return meta[id];
841
+ }
842
+
843
+ /**
844
+ * Sets given value to id in metaNamespace
845
+ *
846
+ * @param {string} id
847
+ * @param {string} value
848
+ */
849
+ setMeta(id, value) {
850
+ const meta = this._ensureMetaDict();
851
+ meta[id] = value;
852
+ // Make sure the object gets re-written, especially when using an external DB
853
+ this.dataset['**META**'] = meta;
854
+
855
+ setImmediate(() => {
856
+ // publish event in states
857
+ this.log.silly(`${this.namespace} memory publish meta ${id} ${value}`);
858
+ this.publishAll('meta', id, value);
859
+ });
860
+
861
+ if (!this.stateTimer) {
862
+ this.stateTimer = setTimeout(() => this.saveState(), this.writeFileInterval);
863
+ }
864
+ }
865
+
753
866
  // needed by server
754
867
  _setObjectDirect(id, obj) {
755
868
  this.dataset[id] = obj;
756
869
 
757
870
  // object updated -> if type changed to meta -> cache
758
- if (this.dataset[id].type === 'meta' && this.existingMetaObjects[id] === false) {
871
+ if (obj.type === 'meta' && this.existingMetaObjects[id] === false) {
759
872
  this.existingMetaObjects[id] = true;
760
873
  }
761
874
 
@@ -766,11 +879,12 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
766
879
 
767
880
  // needed by server
768
881
  _delObject(id) {
769
- if (!this.dataset[id]) {
770
- throw new Error (utils.ERRORS.ERROR_NOT_FOUND);
882
+ const obj = this.dataset[id];
883
+ if (!obj) {
884
+ throw new Error(utils.ERRORS.ERROR_NOT_FOUND);
771
885
  }
772
886
 
773
- if (this.dataset[id].common && this.dataset[id].common.dontDelete) {
887
+ if (obj.common && obj.common.dontDelete) {
774
888
  throw new Error('Object is marked as non deletable');
775
889
  }
776
890
 
@@ -796,7 +910,7 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
796
910
 
797
911
  // eslint-disable-next-line no-unused-vars
798
912
  function _emit_(id, obj) {
799
- result.rows.push({id: id, value: obj});
913
+ result.rows.push({ id: id, value: obj });
800
914
  }
801
915
 
802
916
  const f = eval('(' + func.map.replace(/emit/g, '_emit_') + ')');
@@ -806,13 +920,14 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
806
920
  if (params.startkey && id < params.startkey) {
807
921
  continue;
808
922
  }
809
- if (params.endkey && id > params.endkey) {
923
+ if (params.endkey && id > params.endkey) {
810
924
  continue;
811
925
  }
812
926
  }
813
- if (this.dataset[id]) {
927
+ const obj = this.dataset[id];
928
+ if (obj) {
814
929
  try {
815
- f(this.dataset[id]);
930
+ f(obj);
816
931
  } catch (e) {
817
932
  this.log.warn(`${this.namespace} Cannot execute map: ${e.message}`);
818
933
  }
@@ -827,7 +942,7 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
827
942
  }
828
943
  }
829
944
  if (max !== null) {
830
- result.rows = [{id: '_stats', value: {max: max}}];
945
+ result.rows = [{ id: '_stats', value: { max: max } }];
831
946
  } else {
832
947
  result.rows = [];
833
948
  }
@@ -838,15 +953,16 @@ class ObjectsInMemoryFileDB extends InMemoryFileDB {
838
953
 
839
954
  // needed by server
840
955
  _getObjectView(design, search, params) {
841
- if (!this.dataset['_design/' + design]) {
956
+ const designObj = this.dataset[`_design/${design}`];
957
+ if (!designObj) {
842
958
  this.log.error(`${this.namespace} Cannot find view "${design}"`);
843
959
  throw new Error(`Cannot find view "${design}"`);
844
960
  }
845
- if (!this.dataset[`_design/${design}`].views && this.dataset['_design/' + design].views[search]) {
961
+ if (!(designObj.views && designObj.views[search])) {
846
962
  this.log.warn(`${this.namespace} Cannot find search "${search}" in "${design}"`);
847
963
  throw new Error(`Cannot find search "${search}" in "${design}"`);
848
964
  }
849
- return this._applyView(this.dataset[`_design/${design}`].views[search], params);
965
+ return this._applyView(designObj.views[search], params);
850
966
  }
851
967
 
852
968
  // Destructor of the class. Called by shutting down.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * States DB in memory - Server with Redis protocol
3
3
  *
4
- * Copyright 2013-2021 bluefox <dogafox@gmail.com>
4
+ * Copyright 2013-2022 bluefox <dogafox@gmail.com>
5
5
  *
6
6
  * MIT License
7
7
  *
@@ -18,28 +18,12 @@ const ObjectsInRedisClient = require('@iobroker/db-objects-redis').Client;
18
18
  const ObjectsInMemServer = require('./objectsInMemServerRedis');
19
19
 
20
20
  class ObjectsInMemoryServerClass extends ObjectsInRedisClient {
21
-
22
21
  constructor(settings) {
23
22
  settings.autoConnect = false; // delay Client connection to when we need it
24
-
25
- // hack around testing problem where subscribe was called before connect
26
- // Should be removed for a later release
27
- const origConnected = settings.connected;
28
- settings.connected = () => {
29
- this.clientConnected = true;
30
- if (Array.isArray(this.storedSubscribes) && this.storedSubscribes.length) {
31
- this.log.warn(`${this.namespace} Replay ${this.storedSubscribes.length} subscription calls for Objects Server that were done before the client was connected initially`);
32
- this.storedSubscribes.forEach((s => this.subscribe(s.pattern, s.options, s.callback)));
33
- this.storedSubscribes = [];
34
- }
35
- origConnected();
36
- };
37
23
  super(settings);
38
- this.clientConnected = false;
39
- this.storedSubscribes = [];
40
24
 
41
25
  const serverSettings = {
42
- namespace: settings.namespace ? `${settings.namespace}-Server` : 'Server',
26
+ namespace: settings.namespace ? `${settings.namespace}-Server` : 'Server',
43
27
  connection: settings.connection,
44
28
  logger: settings.logger,
45
29
  hostname: settings.hostname,
@@ -66,13 +50,5 @@ class ObjectsInMemoryServerClass extends ObjectsInRedisClient {
66
50
  dirExists(id, name) {
67
51
  return this.objectsServer.dirExists(id, name);
68
52
  }
69
-
70
- subscribe(pattern, options, callback) {
71
- if (!this.clientConnected) {
72
- this.storedSubscribes.push({pattern, options, callback}); // we ignore the promise return because not used for this testing issue we work around here
73
- } else {
74
- return super.subscribe(pattern, options, callback);
75
- }
76
- }
77
53
  }
78
54
  module.exports = ObjectsInMemoryServerClass;