@iobroker/db-objects-file 7.2.3 → 8.0.0-alpha.2-20260923-99da17fcc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/index.js +5 -3
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/lib/objects/objectsInMemFileDB.d.ts +288 -59
- package/build/cjs/lib/objects/objectsInMemFileDB.js +225 -109
- package/build/cjs/lib/objects/objectsInMemFileDB.js.map +3 -3
- package/build/cjs/lib/objects/objectsInMemServerClass.d.ts +41 -8
- package/build/cjs/lib/objects/objectsInMemServerClass.js +27 -2
- package/build/cjs/lib/objects/objectsInMemServerClass.js.map +3 -3
- package/build/cjs/lib/objects/objectsInMemServerRedis.d.ts +50 -30
- package/build/cjs/lib/objects/objectsInMemServerRedis.js +72 -37
- package/build/cjs/lib/objects/objectsInMemServerRedis.js.map +4 -4
- package/build/esm/lib/objects/objectsInMemFileDB.d.ts +288 -59
- package/build/esm/lib/objects/objectsInMemFileDB.d.ts.map +1 -1
- package/build/esm/lib/objects/objectsInMemFileDB.js +228 -126
- package/build/esm/lib/objects/objectsInMemFileDB.js.map +1 -1
- package/build/esm/lib/objects/objectsInMemServerClass.d.ts +41 -8
- package/build/esm/lib/objects/objectsInMemServerClass.d.ts.map +1 -1
- package/build/esm/lib/objects/objectsInMemServerClass.js +25 -1
- package/build/esm/lib/objects/objectsInMemServerClass.js.map +1 -1
- package/build/esm/lib/objects/objectsInMemServerRedis.d.ts +50 -30
- package/build/esm/lib/objects/objectsInMemServerRedis.d.ts.map +1 -1
- package/build/esm/lib/objects/objectsInMemServerRedis.js +89 -70
- package/build/esm/lib/objects/objectsInMemServerRedis.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +7 -7
|
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
9
|
var __export = (target, all) => {
|
|
9
10
|
for (var name in all)
|
|
10
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -38,56 +39,69 @@ var import_db_base2 = require("@iobroker/db-base");
|
|
|
38
39
|
var import_db_objects_redis = require("@iobroker/db-objects-redis");
|
|
39
40
|
var import_deep_clone = __toESM(require("deep-clone"), 1);
|
|
40
41
|
class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
42
|
+
static {
|
|
43
|
+
__name(this, "ObjectsInMemoryFileDB");
|
|
44
|
+
}
|
|
45
|
+
META_ID = "**META**";
|
|
46
|
+
fileOptions = {};
|
|
47
|
+
files = {};
|
|
48
|
+
writeTimer = null;
|
|
49
|
+
writeIds = [];
|
|
50
|
+
defaultNewAcl;
|
|
51
|
+
writeFileInterval;
|
|
52
|
+
objectsDir;
|
|
53
|
+
// cached meta information for file operations
|
|
54
|
+
existingMetaObjects = {};
|
|
55
|
+
/**
|
|
56
|
+
* @param settings Settings for the objects database
|
|
57
|
+
*/
|
|
41
58
|
constructor(settings) {
|
|
42
|
-
settings
|
|
43
|
-
settings.fileDB = settings.fileDB || {
|
|
59
|
+
settings.fileDB ??= {
|
|
44
60
|
fileName: "objects.json",
|
|
45
61
|
backupDirName: "backup-objects"
|
|
46
62
|
};
|
|
47
63
|
super(settings);
|
|
48
|
-
|
|
49
|
-
this.change
|
|
50
|
-
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
this.META_ID = "**META**";
|
|
54
|
-
this.fileOptions = {};
|
|
55
|
-
this.files = {};
|
|
56
|
-
this.writeTimer = null;
|
|
57
|
-
this.writeIds = [];
|
|
58
|
-
this.preserveSettings = ["custom"];
|
|
64
|
+
this.change ||= (id) => {
|
|
65
|
+
this.log.silly(`${this.namespace} objects change: ${id} ${JSON.stringify(this.change)}`);
|
|
66
|
+
};
|
|
59
67
|
this.defaultNewAcl = this.settings.defaultNewAcl || null;
|
|
60
68
|
this.namespace = this.settings.namespace || this.settings.hostname || "";
|
|
61
|
-
this.writeFileInterval = this.settings.connection && typeof this.settings.connection.writeFileInterval === "number" ?
|
|
69
|
+
this.writeFileInterval = this.settings.connection && typeof this.settings.connection.writeFileInterval === "number" ? this.settings.connection.writeFileInterval : 5e3;
|
|
62
70
|
if (!settings.jsonlDB) {
|
|
63
71
|
this.log.silly(`${this.namespace} Objects DB uses file write interval of ${this.writeFileInterval} ms`);
|
|
64
72
|
}
|
|
65
73
|
this.objectsDir = import_node_path.default.join(this.dataDir, "files");
|
|
66
|
-
this.existingMetaObjects = {};
|
|
67
|
-
for (const obj of Object.values(this.dataset)) {
|
|
68
|
-
if (import_db_base2.tools.isObject(obj) && obj.acl && obj.acl.permissions && !obj.acl.object) {
|
|
69
|
-
obj.acl.object = obj.acl.permissions;
|
|
70
|
-
delete obj.acl.permissions;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
74
|
const configObj = this.dataset["system.config"];
|
|
74
|
-
if (configObj
|
|
75
|
+
if (configObj?.common?.defaultNewAcl) {
|
|
75
76
|
this.defaultNewAcl = (0, import_deep_clone.default)(configObj.common.defaultNewAcl);
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Normalize a file name by collapsing slashes and backslashes into a single forward slash
|
|
81
|
+
*
|
|
82
|
+
* @param name The file name to normalize
|
|
83
|
+
*/
|
|
79
84
|
_normalizeFilename(name) {
|
|
80
85
|
return name ? name.replace(/[/\\]+/g, "/") : name;
|
|
81
86
|
}
|
|
82
87
|
// -------------- FILE FUNCTIONS -------------------------------------------
|
|
83
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Schedule writing the file settings (_data.json) to disk
|
|
90
|
+
*
|
|
91
|
+
* @param id The object ID whose file settings should be saved, or a boolean used as the force flag
|
|
92
|
+
* @param force If true, write the settings immediately instead of debounced
|
|
93
|
+
*/
|
|
84
94
|
_saveFileSettings(id, force) {
|
|
85
95
|
if (typeof id === "boolean") {
|
|
86
96
|
force = id;
|
|
87
97
|
id = void 0;
|
|
88
98
|
}
|
|
89
|
-
id !== void 0 && !this.writeIds.includes(id)
|
|
90
|
-
|
|
99
|
+
if (id !== void 0 && !this.writeIds.includes(id)) {
|
|
100
|
+
this.writeIds.push(id);
|
|
101
|
+
}
|
|
102
|
+
if (this.writeTimer) {
|
|
103
|
+
clearTimeout(this.writeTimer);
|
|
104
|
+
}
|
|
91
105
|
if (force) {
|
|
92
106
|
this.writeTimer = null;
|
|
93
107
|
for (const writeId of this.writeIds) {
|
|
@@ -115,7 +129,11 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
115
129
|
}, 1e3);
|
|
116
130
|
}
|
|
117
131
|
}
|
|
118
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Load the file settings (_data.json) for the given object ID into memory
|
|
134
|
+
*
|
|
135
|
+
* @param id The object ID whose file settings should be loaded
|
|
136
|
+
*/
|
|
119
137
|
_loadFileSettings(id) {
|
|
120
138
|
if (!this.fileOptions[id]) {
|
|
121
139
|
const location = import_node_path.default.join(this.objectsDir, id, "_data.json");
|
|
@@ -148,7 +166,11 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
148
166
|
}
|
|
149
167
|
}
|
|
150
168
|
}
|
|
151
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Synchronize the in-memory file metadata with the files actually present on disk (server only)
|
|
171
|
+
*
|
|
172
|
+
* @param limitId Optional object ID to limit the synchronization to
|
|
173
|
+
*/
|
|
152
174
|
syncFileDirectory(limitId) {
|
|
153
175
|
const resNotifies = [];
|
|
154
176
|
let resSynced = 0;
|
|
@@ -158,7 +180,7 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
158
180
|
list.forEach((file) => {
|
|
159
181
|
file = `${dir}/${file}`;
|
|
160
182
|
const stat = import_fs_extra.default.statSync(file);
|
|
161
|
-
if (stat
|
|
183
|
+
if (stat?.isDirectory()) {
|
|
162
184
|
results = results.concat(getAllFiles(file));
|
|
163
185
|
} else {
|
|
164
186
|
results.push(file);
|
|
@@ -166,6 +188,7 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
166
188
|
});
|
|
167
189
|
return results;
|
|
168
190
|
}
|
|
191
|
+
__name(getAllFiles, "getAllFiles");
|
|
169
192
|
const res = this._getObjectView("system", "meta", null);
|
|
170
193
|
const metaIds = res.rows.map((obj) => obj.id).filter((id) => !limitId || limitId === id);
|
|
171
194
|
if (!import_fs_extra.default.existsSync(this.objectsDir)) {
|
|
@@ -208,9 +231,9 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
208
231
|
this.fileOptions[dir][localFile] = {
|
|
209
232
|
createdAt: fileStat.ctimeMs,
|
|
210
233
|
acl: {
|
|
211
|
-
owner: this.defaultNewAcl
|
|
212
|
-
ownerGroup: this.defaultNewAcl
|
|
213
|
-
permissions: this.defaultNewAcl
|
|
234
|
+
owner: this.defaultNewAcl?.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
|
|
235
|
+
ownerGroup: this.defaultNewAcl?.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
|
|
236
|
+
permissions: this.defaultNewAcl?.file || import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_RW | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_READ | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_READ
|
|
214
237
|
// 0x644
|
|
215
238
|
},
|
|
216
239
|
mimeType: _mimeType,
|
|
@@ -222,27 +245,36 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
222
245
|
});
|
|
223
246
|
this._saveFileSettings(dir);
|
|
224
247
|
resSynced += dirSynced;
|
|
225
|
-
|
|
248
|
+
if (dirSynced) {
|
|
249
|
+
resNotifies.push(`Added ${dirSynced} Files in Directory "${dir}"`);
|
|
250
|
+
}
|
|
226
251
|
});
|
|
227
252
|
return {
|
|
228
253
|
numberSuccess: resSynced,
|
|
229
254
|
notifications: resNotifies
|
|
230
255
|
};
|
|
231
256
|
}
|
|
232
|
-
|
|
257
|
+
/**
|
|
258
|
+
* Write a file into an object's file storage (used by the server)
|
|
259
|
+
*
|
|
260
|
+
* @param id The object ID owning the file
|
|
261
|
+
* @param name The file name
|
|
262
|
+
* @param data The file content
|
|
263
|
+
* @param options Optional write options, or the mime type as a string
|
|
264
|
+
*/
|
|
233
265
|
_writeFile(id, name, data, options) {
|
|
234
266
|
if (typeof options === "string") {
|
|
235
267
|
options = { mimeType: options };
|
|
236
268
|
}
|
|
237
|
-
if (options
|
|
269
|
+
if (options?.acl) {
|
|
238
270
|
options.acl = null;
|
|
239
271
|
}
|
|
240
272
|
const _path = import_db_objects_redis.objectsUtils.sanitizePath(id, name);
|
|
241
273
|
id = _path.id;
|
|
242
274
|
name = _path.name;
|
|
243
|
-
options
|
|
275
|
+
options ||= {};
|
|
244
276
|
this._loadFileSettings(id);
|
|
245
|
-
this.files[id]
|
|
277
|
+
this.files[id] ||= {};
|
|
246
278
|
try {
|
|
247
279
|
if (!import_fs_extra.default.existsSync(this.objectsDir)) {
|
|
248
280
|
import_fs_extra.default.mkdirSync(this.objectsDir);
|
|
@@ -259,16 +291,16 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
259
291
|
const mime = import_db_objects_redis.objectsUtils.getMimeType(ext);
|
|
260
292
|
const _mimeType = mime.mimeType;
|
|
261
293
|
const isBinary = mime.isBinary;
|
|
262
|
-
this.fileOptions[id][name]
|
|
263
|
-
this.fileOptions[id][name].acl
|
|
264
|
-
owner: options.user || this.defaultNewAcl
|
|
265
|
-
ownerGroup: options.group || this.defaultNewAcl
|
|
266
|
-
permissions: options.mode || this.defaultNewAcl
|
|
294
|
+
this.fileOptions[id][name] ||= { createdAt: Date.now() };
|
|
295
|
+
this.fileOptions[id][name].acl ||= {
|
|
296
|
+
owner: options.user || this.defaultNewAcl?.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
|
|
297
|
+
ownerGroup: options.group || this.defaultNewAcl?.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
|
|
298
|
+
permissions: options.mode || this.defaultNewAcl?.file || import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_RW | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_READ | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_READ
|
|
267
299
|
// 0x644
|
|
268
300
|
};
|
|
269
301
|
this.fileOptions[id][name].mimeType = options.mimeType || _mimeType;
|
|
270
302
|
this.fileOptions[id][name].binary = isBinary;
|
|
271
|
-
this.fileOptions[id][name].acl.ownerGroup
|
|
303
|
+
this.fileOptions[id][name].acl.ownerGroup ||= this.defaultNewAcl?.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP;
|
|
272
304
|
this.fileOptions[id][name].modifiedAt = Date.now();
|
|
273
305
|
try {
|
|
274
306
|
import_fs_extra.default.ensureDirSync(import_node_path.default.join(this.objectsDir, id, import_node_path.default.dirname(name)));
|
|
@@ -289,28 +321,34 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
289
321
|
setImmediate((name2, size) => {
|
|
290
322
|
this.log.silly(`${this.namespace} memory publish ${id} ${JSON.stringify({ name: name2, file: true, size })}`);
|
|
291
323
|
this.publishAll("files", `${id}$%$${name2}`, size);
|
|
292
|
-
}, name,
|
|
324
|
+
}, name, Buffer.byteLength(data));
|
|
293
325
|
}
|
|
294
|
-
|
|
326
|
+
/**
|
|
327
|
+
* Read a file from an object's file storage (used by the server)
|
|
328
|
+
*
|
|
329
|
+
* @param id The object ID owning the file
|
|
330
|
+
* @param name The file name
|
|
331
|
+
* @param options Optional read options
|
|
332
|
+
*/
|
|
295
333
|
_readFile(id, name, options) {
|
|
296
|
-
if (options
|
|
334
|
+
if (options?.acl) {
|
|
297
335
|
options.acl = null;
|
|
298
336
|
}
|
|
299
337
|
const _path = import_db_objects_redis.objectsUtils.sanitizePath(id, name);
|
|
300
338
|
id = _path.id;
|
|
301
339
|
name = _path.name;
|
|
302
|
-
options
|
|
340
|
+
options ||= {};
|
|
303
341
|
try {
|
|
304
342
|
this._loadFileSettings(id);
|
|
305
|
-
this.files[id]
|
|
343
|
+
this.files[id] ||= {};
|
|
306
344
|
if (!this.files[id][name] || this.settings.connection.noFileCache || options.noFileCache) {
|
|
307
345
|
const location = import_node_path.default.join(this.objectsDir, id, name);
|
|
308
346
|
if (import_fs_extra.default.existsSync(location)) {
|
|
309
|
-
this.fileOptions[id][name]
|
|
347
|
+
this.fileOptions[id][name] ||= {
|
|
310
348
|
acl: {
|
|
311
|
-
owner: this.defaultNewAcl
|
|
312
|
-
ownerGroup: this.defaultNewAcl
|
|
313
|
-
permissions: this.defaultNewAcl
|
|
349
|
+
owner: this.defaultNewAcl?.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
|
|
350
|
+
ownerGroup: this.defaultNewAcl?.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
|
|
351
|
+
permissions: this.defaultNewAcl?.file || import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_ALL | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_ALL | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_ALL
|
|
314
352
|
// 777
|
|
315
353
|
}
|
|
316
354
|
};
|
|
@@ -318,9 +356,9 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
318
356
|
this.fileOptions[id][name] = {
|
|
319
357
|
mimeType: this.fileOptions[id][name],
|
|
320
358
|
acl: {
|
|
321
|
-
owner: this.defaultNewAcl
|
|
322
|
-
ownerGroup: this.defaultNewAcl
|
|
323
|
-
permissions: this.defaultNewAcl
|
|
359
|
+
owner: this.defaultNewAcl?.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
|
|
360
|
+
ownerGroup: this.defaultNewAcl?.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
|
|
361
|
+
permissions: this.defaultNewAcl?.file || import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_ALL | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_ALL | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_ALL
|
|
324
362
|
// 777
|
|
325
363
|
}
|
|
326
364
|
};
|
|
@@ -332,10 +370,8 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
332
370
|
this.fileOptions[id][name].binary = mimeType.isBinary;
|
|
333
371
|
this.fileOptions[id][name].mimeType = mimeType.mimeType;
|
|
334
372
|
}
|
|
335
|
-
if (!this.fileOptions[id][name].binary) {
|
|
336
|
-
|
|
337
|
-
this.files[id][name] = this.files[id][name].toString();
|
|
338
|
-
}
|
|
373
|
+
if (!this.fileOptions[id][name].binary && this.files[id][name]) {
|
|
374
|
+
this.files[id][name] = this.files[id][name].toString();
|
|
339
375
|
}
|
|
340
376
|
} else {
|
|
341
377
|
if (this.fileOptions[id][name] !== void 0) {
|
|
@@ -348,9 +384,9 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
348
384
|
}
|
|
349
385
|
if (this.fileOptions[id][name] && !this.fileOptions[id][name].acl) {
|
|
350
386
|
this.fileOptions[id][name].acl = {
|
|
351
|
-
owner: this.defaultNewAcl
|
|
352
|
-
ownerGroup: this.defaultNewAcl
|
|
353
|
-
permissions: this.defaultNewAcl
|
|
387
|
+
owner: this.defaultNewAcl?.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
|
|
388
|
+
ownerGroup: this.defaultNewAcl?.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
|
|
389
|
+
permissions: this.defaultNewAcl?.file || import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_ALL | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_ALL | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_RW
|
|
354
390
|
// 776
|
|
355
391
|
};
|
|
356
392
|
}
|
|
@@ -394,7 +430,7 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
394
430
|
*
|
|
395
431
|
* @param id id of the namespace
|
|
396
432
|
* @param [name] name of the file
|
|
397
|
-
* @returns
|
|
433
|
+
* @returns true if the file exists
|
|
398
434
|
*/
|
|
399
435
|
// needed by server
|
|
400
436
|
_fileExists(id, name) {
|
|
@@ -418,7 +454,7 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
418
454
|
*
|
|
419
455
|
* @param id id of the namespace
|
|
420
456
|
* @param [name] name of the directory
|
|
421
|
-
* @returns
|
|
457
|
+
* @returns true if the directory exists
|
|
422
458
|
*/
|
|
423
459
|
// special functionality only for Server (used together with SyncFileDirectory)
|
|
424
460
|
dirExists(id, name) {
|
|
@@ -437,7 +473,12 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
437
473
|
return false;
|
|
438
474
|
}
|
|
439
475
|
}
|
|
440
|
-
|
|
476
|
+
/**
|
|
477
|
+
* Delete a file or directory from an object's file storage (used by the server)
|
|
478
|
+
*
|
|
479
|
+
* @param id The object ID owning the file
|
|
480
|
+
* @param name The file or directory name to delete
|
|
481
|
+
*/
|
|
441
482
|
_unlink(id, name) {
|
|
442
483
|
const _path = import_db_objects_redis.objectsUtils.sanitizePath(id, name);
|
|
443
484
|
id = _path.id;
|
|
@@ -458,7 +499,7 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
458
499
|
if (this.fileOptions[id]) {
|
|
459
500
|
delete this.fileOptions[id];
|
|
460
501
|
}
|
|
461
|
-
if (this.files[id]
|
|
502
|
+
if (this.files[id]) {
|
|
462
503
|
delete this.files[id];
|
|
463
504
|
}
|
|
464
505
|
} else {
|
|
@@ -469,10 +510,10 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
469
510
|
this.log.error(`${this.namespace} Cannot delete file "${import_node_path.default.join(id, name)}": ${e.message}`);
|
|
470
511
|
throw e;
|
|
471
512
|
}
|
|
472
|
-
if (this.fileOptions[id][name]) {
|
|
513
|
+
if (this.fileOptions[id]?.[name]) {
|
|
473
514
|
delete this.fileOptions[id][name];
|
|
474
515
|
}
|
|
475
|
-
if (this.files[id]
|
|
516
|
+
if (this.files[id]?.[name]) {
|
|
476
517
|
delete this.files[id][name];
|
|
477
518
|
}
|
|
478
519
|
this._saveFileSettings(id, true);
|
|
@@ -483,9 +524,15 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
483
524
|
}, id, name);
|
|
484
525
|
}
|
|
485
526
|
}
|
|
486
|
-
|
|
527
|
+
/**
|
|
528
|
+
* List the contents of a directory in an object's file storage (used by the server)
|
|
529
|
+
*
|
|
530
|
+
* @param id The object ID owning the files
|
|
531
|
+
* @param name The directory name to list
|
|
532
|
+
* @param options Optional read options
|
|
533
|
+
*/
|
|
487
534
|
_readDir(id, name, options) {
|
|
488
|
-
if (options
|
|
535
|
+
if (options?.acl) {
|
|
489
536
|
options.acl = null;
|
|
490
537
|
}
|
|
491
538
|
if ((id === "" || id === "/" || id === "*") && (name === "" || name === "*")) {
|
|
@@ -494,7 +541,7 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
494
541
|
id = _path.id;
|
|
495
542
|
name = _path.name;
|
|
496
543
|
}
|
|
497
|
-
options
|
|
544
|
+
options ||= {};
|
|
498
545
|
const _files = [];
|
|
499
546
|
if (id && id === "*") {
|
|
500
547
|
id = "";
|
|
@@ -506,9 +553,8 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
506
553
|
const len = name ? name.length : 0;
|
|
507
554
|
for (const f2 of Object.keys(this.fileOptions[id])) {
|
|
508
555
|
if (!name || f2.substring(0, len) === name) {
|
|
509
|
-
|
|
510
|
-
rest
|
|
511
|
-
if (rest[0] && _files.indexOf(rest[0]) === -1) {
|
|
556
|
+
const rest = f2.substring(len).split("/", 2);
|
|
557
|
+
if (rest[0] && !_files.includes(rest[0])) {
|
|
512
558
|
_files.push(rest[0]);
|
|
513
559
|
}
|
|
514
560
|
}
|
|
@@ -520,7 +566,7 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
520
566
|
if (dirFiles[i] === ".." || dirFiles[i] === ".") {
|
|
521
567
|
continue;
|
|
522
568
|
}
|
|
523
|
-
if (dirFiles[i] !== "_data.json" && _files.
|
|
569
|
+
if (dirFiles[i] !== "_data.json" && !_files.includes(dirFiles[i])) {
|
|
524
570
|
_files.push(dirFiles[i]);
|
|
525
571
|
}
|
|
526
572
|
}
|
|
@@ -536,23 +582,23 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
536
582
|
if (import_fs_extra.default.existsSync(import_node_path.default.join(location, file))) {
|
|
537
583
|
try {
|
|
538
584
|
const stats = import_fs_extra.default.statSync(import_node_path.default.join(location, file));
|
|
539
|
-
const acl = this.fileOptions[id][name + file]
|
|
585
|
+
const acl = this.fileOptions[id][name + file]?.acl ? (0, import_deep_clone.default)(this.fileOptions[id][name + file].acl) : {
|
|
540
586
|
read: true,
|
|
541
587
|
write: true,
|
|
542
|
-
owner: this.defaultNewAcl
|
|
543
|
-
ownerGroup: this.defaultNewAcl
|
|
544
|
-
permissions: this.defaultNewAcl
|
|
588
|
+
owner: this.defaultNewAcl?.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
|
|
589
|
+
ownerGroup: this.defaultNewAcl?.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
|
|
590
|
+
permissions: this.defaultNewAcl?.file || import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_RW | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_READ | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_READ
|
|
545
591
|
};
|
|
546
592
|
if (options.filter && acl) {
|
|
547
|
-
if (!options.acl
|
|
593
|
+
if (!options.acl?.file.write) {
|
|
548
594
|
acl.permissions &= ~(import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_WRITE | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_WRITE | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_WRITE);
|
|
549
595
|
}
|
|
550
|
-
if (!options.acl
|
|
596
|
+
if (!options.acl?.file.read) {
|
|
551
597
|
acl.permissions &= ~(import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_READ | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_READ | import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_READ);
|
|
552
598
|
}
|
|
553
|
-
if (options.user !== import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER && options.groups
|
|
599
|
+
if (options.user !== import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER && options.groups?.includes(import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP)) {
|
|
554
600
|
if (acl.owner !== options.user) {
|
|
555
|
-
if (options.groups
|
|
601
|
+
if (options.groups?.includes(acl.ownerGroup)) {
|
|
556
602
|
if (!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_RW)) {
|
|
557
603
|
continue;
|
|
558
604
|
}
|
|
@@ -592,7 +638,13 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
592
638
|
}
|
|
593
639
|
return res;
|
|
594
640
|
}
|
|
595
|
-
|
|
641
|
+
/**
|
|
642
|
+
* Rename a file or directory in an object's file storage (used by the server)
|
|
643
|
+
*
|
|
644
|
+
* @param id The object ID owning the file
|
|
645
|
+
* @param oldName The current file or directory name
|
|
646
|
+
* @param newName The new file or directory name
|
|
647
|
+
*/
|
|
596
648
|
_rename(id, oldName, newName) {
|
|
597
649
|
const _path = import_db_objects_redis.objectsUtils.sanitizePath(id, oldName);
|
|
598
650
|
id = _path.id;
|
|
@@ -622,7 +674,11 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
622
674
|
});
|
|
623
675
|
this._saveFileSettings(id, true);
|
|
624
676
|
}
|
|
625
|
-
|
|
677
|
+
/**
|
|
678
|
+
* Create a deep clone of the given object
|
|
679
|
+
*
|
|
680
|
+
* @param obj The object to clone
|
|
681
|
+
*/
|
|
626
682
|
_clone(obj) {
|
|
627
683
|
if (obj === null || obj === void 0 || !import_db_base2.tools.isObject(obj)) {
|
|
628
684
|
return obj;
|
|
@@ -633,18 +689,40 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
633
689
|
}
|
|
634
690
|
return temp;
|
|
635
691
|
}
|
|
692
|
+
/**
|
|
693
|
+
* Subscribe a client to meta changes
|
|
694
|
+
*
|
|
695
|
+
* @param client The client to subscribe
|
|
696
|
+
* @param pattern The pattern of meta IDs to subscribe to
|
|
697
|
+
*/
|
|
636
698
|
_subscribeMeta(client, pattern) {
|
|
637
699
|
this.handleSubscribe(client, "meta", pattern);
|
|
638
700
|
}
|
|
639
|
-
|
|
701
|
+
/**
|
|
702
|
+
* Subscribe a client to object changes (used by the server)
|
|
703
|
+
*
|
|
704
|
+
* @param client The client to subscribe
|
|
705
|
+
* @param pattern The pattern of object IDs to subscribe to
|
|
706
|
+
*/
|
|
640
707
|
_subscribeConfigForClient(client, pattern) {
|
|
641
708
|
this.handleSubscribe(client, "objects", pattern);
|
|
642
709
|
}
|
|
643
|
-
|
|
710
|
+
/**
|
|
711
|
+
* Unsubscribe a client from object changes (used by the server)
|
|
712
|
+
*
|
|
713
|
+
* @param client The client to unsubscribe
|
|
714
|
+
* @param pattern The pattern of object IDs to unsubscribe from
|
|
715
|
+
*/
|
|
644
716
|
_unsubscribeConfigForClient(client, pattern) {
|
|
645
|
-
this.handleUnsubscribe(client, "objects", pattern);
|
|
717
|
+
this.handleUnsubscribe(client, "objects", pattern).catch((e) => this.log.error(`${this.namespace} Cannot unsubscribe client from objects: ${e.message}`));
|
|
646
718
|
}
|
|
647
|
-
|
|
719
|
+
/**
|
|
720
|
+
* Subscribe a client to file changes of an object (used by the server)
|
|
721
|
+
*
|
|
722
|
+
* @param client The client to subscribe
|
|
723
|
+
* @param id The object ID owning the files
|
|
724
|
+
* @param pattern One or more file name patterns to subscribe to
|
|
725
|
+
*/
|
|
648
726
|
_subscribeFileForClient(client, id, pattern) {
|
|
649
727
|
if (Array.isArray(pattern)) {
|
|
650
728
|
pattern.forEach((pattern2) => this.handleSubscribe(client, "files", `${id}$%$${pattern2}`));
|
|
@@ -652,32 +730,53 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
652
730
|
this.handleSubscribe(client, "files", `${id}$%$${pattern}`);
|
|
653
731
|
}
|
|
654
732
|
}
|
|
655
|
-
|
|
733
|
+
/**
|
|
734
|
+
* Unsubscribe a client from file changes of an object (used by the server)
|
|
735
|
+
*
|
|
736
|
+
* @param client The client to unsubscribe
|
|
737
|
+
* @param id The object ID owning the files
|
|
738
|
+
* @param pattern One or more file name patterns to unsubscribe from
|
|
739
|
+
*/
|
|
656
740
|
_unsubscribeFileForClient(client, id, pattern) {
|
|
657
741
|
if (Array.isArray(pattern)) {
|
|
658
742
|
pattern.forEach((pattern2) => this.handleUnsubscribe(client, "files", `${id}$%$${pattern2}`));
|
|
659
743
|
} else {
|
|
660
|
-
this.handleUnsubscribe(client, "files", `${id}$%$${pattern}`);
|
|
744
|
+
this.handleUnsubscribe(client, "files", `${id}$%$${pattern}`).catch((e) => this.log.error(`${this.namespace} Cannot unsubscribe client from files: ${e.message}`));
|
|
661
745
|
}
|
|
662
746
|
}
|
|
663
|
-
|
|
747
|
+
/**
|
|
748
|
+
* Get a single object by its ID (used by the server)
|
|
749
|
+
*
|
|
750
|
+
* @param id The object ID to read
|
|
751
|
+
*/
|
|
664
752
|
_getObject(id) {
|
|
665
753
|
return this.dataset[id];
|
|
666
754
|
}
|
|
667
|
-
|
|
755
|
+
/**
|
|
756
|
+
* Get all object IDs matching the given pattern, sorted (used by the server)
|
|
757
|
+
*
|
|
758
|
+
* @param pattern The pattern to match object IDs against
|
|
759
|
+
*/
|
|
668
760
|
_getKeys(pattern) {
|
|
669
761
|
const r = new RegExp(import_db_base2.tools.pattern2RegEx(pattern));
|
|
670
762
|
const result2 = Object.keys(this.dataset).filter((id) => r.test(id) && id !== this.META_ID);
|
|
671
763
|
result2.sort();
|
|
672
764
|
return result2;
|
|
673
765
|
}
|
|
674
|
-
|
|
766
|
+
/**
|
|
767
|
+
* Get the values of the given object IDs (used by the server)
|
|
768
|
+
*
|
|
769
|
+
* @param keys The object IDs to read
|
|
770
|
+
*/
|
|
675
771
|
_getObjects(keys) {
|
|
676
772
|
if (!keys) {
|
|
677
773
|
throw new Error("no keys");
|
|
678
774
|
}
|
|
679
|
-
return keys.map((id) => this.dataset[id]);
|
|
775
|
+
return keys.map((id) => id ? this.dataset[id] : void 0);
|
|
680
776
|
}
|
|
777
|
+
/**
|
|
778
|
+
* Get the meta dictionary, creating it if it does not exist yet
|
|
779
|
+
*/
|
|
681
780
|
_ensureMetaDict() {
|
|
682
781
|
let meta = this.dataset[this.META_ID];
|
|
683
782
|
if (!meta) {
|
|
@@ -689,8 +788,8 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
689
788
|
/**
|
|
690
789
|
* Get value of given meta id
|
|
691
790
|
*
|
|
692
|
-
* @param id
|
|
693
|
-
* @returns
|
|
791
|
+
* @param id The meta ID to read
|
|
792
|
+
* @returns the stored meta value
|
|
694
793
|
*/
|
|
695
794
|
getMeta(id) {
|
|
696
795
|
const meta = this._ensureMetaDict();
|
|
@@ -699,8 +798,8 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
699
798
|
/**
|
|
700
799
|
* Sets given value to id in metaNamespace
|
|
701
800
|
*
|
|
702
|
-
* @param id
|
|
703
|
-
* @param value
|
|
801
|
+
* @param id The meta ID to write
|
|
802
|
+
* @param value The value to store
|
|
704
803
|
*/
|
|
705
804
|
setMeta(id, value) {
|
|
706
805
|
const meta = this._ensureMetaDict();
|
|
@@ -710,18 +809,21 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
710
809
|
this.log.silly(`${this.namespace} memory publish meta ${id} ${value}`);
|
|
711
810
|
this.publishAll("meta", id, value);
|
|
712
811
|
});
|
|
713
|
-
|
|
714
|
-
this.stateTimer = setTimeout(() => this.saveState(), this.writeFileInterval);
|
|
715
|
-
}
|
|
812
|
+
this.stateTimer ||= setTimeout(() => this.saveState(), this.writeFileInterval);
|
|
716
813
|
}
|
|
717
|
-
|
|
814
|
+
/**
|
|
815
|
+
* Directly set an object value and publish the change (used by the server)
|
|
816
|
+
*
|
|
817
|
+
* @param id The object ID to set
|
|
818
|
+
* @param obj The object to store
|
|
819
|
+
*/
|
|
718
820
|
_setObjectDirect(id, obj) {
|
|
719
821
|
this.dataset[id] = obj;
|
|
720
822
|
if (obj.type === "meta" && this.existingMetaObjects[id] === false) {
|
|
721
823
|
this.existingMetaObjects[id] = true;
|
|
722
824
|
}
|
|
723
825
|
setImmediate(() => this.publishAll("objects", id, obj));
|
|
724
|
-
this.stateTimer
|
|
826
|
+
this.stateTimer ||= setTimeout(() => this.saveState(), this.writeFileInterval);
|
|
725
827
|
}
|
|
726
828
|
/**
|
|
727
829
|
* Delete the given object from the dataset
|
|
@@ -745,14 +847,22 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
745
847
|
this.stateTimer = setTimeout(() => this.saveState(), this.writeFileInterval);
|
|
746
848
|
}
|
|
747
849
|
}
|
|
748
|
-
|
|
850
|
+
/**
|
|
851
|
+
* Apply a view's map function over all objects and collect the matching rows
|
|
852
|
+
*
|
|
853
|
+
* @param func The view definition containing the map function
|
|
854
|
+
* @param func.map The map function source code to apply
|
|
855
|
+
* @param func.reduce Optional reduce function (only the built-in '_stats' is supported)
|
|
856
|
+
* @param params Query parameters such as startkey and endkey
|
|
857
|
+
*/
|
|
749
858
|
_applyView(func, params) {
|
|
750
859
|
const result = {
|
|
751
860
|
rows: []
|
|
752
861
|
};
|
|
753
|
-
function _emit_(id,
|
|
754
|
-
result.rows.push({ id, value
|
|
862
|
+
function _emit_(id, value) {
|
|
863
|
+
result.rows.push({ id, value });
|
|
755
864
|
}
|
|
865
|
+
__name(_emit_, "_emit_");
|
|
756
866
|
const f = eval(`(${func.map.replace(/emit/g, "_emit_")})`);
|
|
757
867
|
for (const [id, obj] of Object.entries(this.dataset)) {
|
|
758
868
|
if (params) {
|
|
@@ -786,14 +896,20 @@ class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
|
|
|
786
896
|
}
|
|
787
897
|
return result;
|
|
788
898
|
}
|
|
789
|
-
|
|
899
|
+
/**
|
|
900
|
+
* Run a predefined object view (design document) and return the matching rows (used by the server)
|
|
901
|
+
*
|
|
902
|
+
* @param design The design document name
|
|
903
|
+
* @param search The view name within the design document
|
|
904
|
+
* @param params Query parameters such as startkey and endkey
|
|
905
|
+
*/
|
|
790
906
|
_getObjectView(design, search, params2) {
|
|
791
907
|
const designObj = this.dataset[`_design/${design}`];
|
|
792
908
|
if (!designObj) {
|
|
793
909
|
this.log.error(`${this.namespace} Cannot find view "${design}"`);
|
|
794
910
|
throw new Error(`Cannot find view "${design}"`);
|
|
795
911
|
}
|
|
796
|
-
if (!
|
|
912
|
+
if (!designObj.views?.[search]) {
|
|
797
913
|
this.log.warn(`${this.namespace} Cannot find search "${search}" in "${design}"`);
|
|
798
914
|
throw new Error(`Cannot find search "${search}" in "${design}"`);
|
|
799
915
|
}
|