@iobroker/db-objects-file
Version:
The Library contains the Database classes for File based objects database client and server.
823 lines (822 loc) • 33.6 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var objectsInMemFileDB_exports = {};
__export(objectsInMemFileDB_exports, {
ObjectsInMemoryFileDB: () => ObjectsInMemoryFileDB
});
module.exports = __toCommonJS(objectsInMemFileDB_exports);
var import_fs_extra = __toESM(require("fs-extra"), 1);
var import_node_path = __toESM(require("node:path"), 1);
var import_db_base = require("@iobroker/db-base");
var import_db_base2 = require("@iobroker/db-base");
var import_db_objects_redis = require("@iobroker/db-objects-redis");
var import_deep_clone = __toESM(require("deep-clone"), 1);
class ObjectsInMemoryFileDB extends import_db_base.InMemoryFileDB {
constructor(settings) {
settings = settings || {};
settings.fileDB = settings.fileDB || {
fileName: "objects.json",
backupDirName: "backup-objects"
};
super(settings);
if (!this.change) {
this.change = (id) => {
this.log.silly(`${this.namespace} objects change: ${id} ${JSON.stringify(this.change)}`);
};
}
this.META_ID = "**META**";
this.fileOptions = {};
this.files = {};
this.writeTimer = null;
this.writeIds = [];
this.preserveSettings = ["custom"];
this.defaultNewAcl = this.settings.defaultNewAcl || null;
this.namespace = this.settings.namespace || this.settings.hostname || "";
this.writeFileInterval = this.settings.connection && typeof this.settings.connection.writeFileInterval === "number" ? parseInt(this.settings.connection.writeFileInterval) : 5e3;
if (!settings.jsonlDB) {
this.log.silly(`${this.namespace} Objects DB uses file write interval of ${this.writeFileInterval} ms`);
}
this.objectsDir = import_node_path.default.join(this.dataDir, "files");
this.existingMetaObjects = {};
for (const obj of Object.values(this.dataset)) {
if (import_db_base2.tools.isObject(obj) && obj.acl && obj.acl.permissions && !obj.acl.object) {
obj.acl.object = obj.acl.permissions;
delete obj.acl.permissions;
}
}
const configObj = this.dataset["system.config"];
if (configObj && configObj.common && configObj.common.defaultNewAcl) {
this.defaultNewAcl = (0, import_deep_clone.default)(configObj.common.defaultNewAcl);
}
}
// internal functionality
_normalizeFilename(name) {
return name ? name.replace(/[/\\]+/g, "/") : name;
}
// -------------- FILE FUNCTIONS -------------------------------------------
// internal functionality
_saveFileSettings(id, force) {
if (typeof id === "boolean") {
force = id;
id = void 0;
}
id !== void 0 && !this.writeIds.includes(id) && this.writeIds.push(id);
this.writeTimer && clearTimeout(this.writeTimer);
if (force) {
this.writeTimer = null;
for (const writeId of this.writeIds) {
const location = import_node_path.default.join(this.objectsDir, writeId, "_data.json");
try {
if (import_fs_extra.default.existsSync(import_node_path.default.join(this.objectsDir, writeId))) {
import_fs_extra.default.writeFileSync(location, JSON.stringify(this.fileOptions[writeId]));
}
} catch (e) {
this.log.error(`${this.namespace} Cannot write files: ${location}: ${e.message}`);
}
}
this.writeIds = [];
} else {
this.writeTimer = setTimeout(() => {
for (const writeId of this.writeIds) {
const location = import_node_path.default.join(this.objectsDir, writeId, "_data.json");
try {
import_fs_extra.default.writeFileSync(location, JSON.stringify(this.fileOptions[writeId]));
} catch (e) {
this.log.error(`${this.namespace} Cannot write files: ${location}: ${e.message}`);
}
}
this.writeIds = [];
}, 1e3);
}
}
// internal functionality
_loadFileSettings(id) {
if (!this.fileOptions[id]) {
const location = import_node_path.default.join(this.objectsDir, id, "_data.json");
if (import_fs_extra.default.existsSync(location)) {
try {
this.fileOptions[id] = import_fs_extra.default.readJSONSync(location);
} catch (e) {
this.log.error(`${this.namespace} Cannot parse ${location}: ${e.message}`);
this.fileOptions[id] = {};
}
let corrected = false;
Object.keys(this.fileOptions[id]).forEach((filename) => {
const normalized = this._normalizeFilename(filename);
if (normalized !== filename) {
const options = this.fileOptions[id][filename];
delete this.fileOptions[id][filename];
this.fileOptions[id][normalized] = options;
corrected = true;
}
if (corrected) {
try {
import_fs_extra.default.writeFileSync(location, JSON.stringify(this.fileOptions[id]));
} catch (e) {
this.log.error(`${this.namespace} Cannot write files: ${location}: ${e.message}`);
}
}
});
} else {
this.fileOptions[id] = {};
}
}
}
// server only functionality
syncFileDirectory(limitId) {
const resNotifies = [];
let resSynced = 0;
function getAllFiles(dir) {
let results = [];
const list = import_fs_extra.default.readdirSync(dir);
list.forEach((file) => {
file = `${dir}/${file}`;
const stat = import_fs_extra.default.statSync(file);
if (stat && stat.isDirectory()) {
results = results.concat(getAllFiles(file));
} else {
results.push(file);
}
});
return results;
}
const res = this._getObjectView("system", "meta", null);
const metaIds = res.rows.map((obj) => obj.id).filter((id) => !limitId || limitId === id);
if (!import_fs_extra.default.existsSync(this.objectsDir)) {
return {
numberSuccess: resSynced,
notifications: resNotifies
};
}
const baseDirs = import_fs_extra.default.readdirSync(this.objectsDir);
baseDirs.forEach((dir) => {
let dirSynced = 0;
if (dir === ".." || dir === ".") {
return;
}
const dirPath = import_node_path.default.join(this.objectsDir, dir);
const stat = import_fs_extra.default.statSync(dirPath);
if (!stat.isDirectory()) {
return;
}
if (limitId && dir !== limitId) {
return;
}
if (!metaIds.includes(dir)) {
resNotifies.push(`Ignoring Directory "${dir}" because officially not created as meta object. Please remove directory!`);
return;
}
this._loadFileSettings(dir);
const files = getAllFiles(dirPath);
files.forEach((file) => {
const localFile = file.substr(dirPath.length + 1);
if (localFile === "_data.json") {
return;
}
if (!this.fileOptions[dir][localFile]) {
const fileStat = import_fs_extra.default.statSync(file);
const ext = import_node_path.default.extname(localFile);
const mime = import_db_objects_redis.objectsUtils.getMimeType(ext);
const _mimeType = mime.mimeType;
const isBinary = mime.isBinary;
this.fileOptions[dir][localFile] = {
createdAt: fileStat.ctimeMs,
acl: {
owner: this.defaultNewAcl && this.defaultNewAcl.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
ownerGroup: this.defaultNewAcl && this.defaultNewAcl.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
permissions: this.defaultNewAcl && 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
// 0x644
},
mimeType: _mimeType,
binary: isBinary,
modifiedAt: fileStat.mtimeMs
};
dirSynced++;
}
});
this._saveFileSettings(dir);
resSynced += dirSynced;
dirSynced && resNotifies.push(`Added ${dirSynced} Files in Directory "${dir}"`);
});
return {
numberSuccess: resSynced,
notifications: resNotifies
};
}
// needed by server
_writeFile(id, name, data, options) {
if (typeof options === "string") {
options = { mimeType: options };
}
if (options && options.acl) {
options.acl = null;
}
const _path = import_db_objects_redis.objectsUtils.sanitizePath(id, name);
id = _path.id;
name = _path.name;
options = options || {};
this._loadFileSettings(id);
this.files[id] = this.files[id] || {};
try {
if (!import_fs_extra.default.existsSync(this.objectsDir)) {
import_fs_extra.default.mkdirSync(this.objectsDir);
}
if (!import_fs_extra.default.existsSync(import_node_path.default.join(this.objectsDir, id))) {
import_fs_extra.default.mkdirSync(import_node_path.default.join(this.objectsDir, id));
}
} catch (e) {
this.log.error(`${this.namespace} Cannot create directories: ${import_node_path.default.join(this.objectsDir, id)}: ${e.message}`);
this.log.error(`${this.namespace} Check the permissions! Or run installation fixer or "iobroker fix" command!`);
throw e;
}
const ext = import_node_path.default.extname(name);
const mime = import_db_objects_redis.objectsUtils.getMimeType(ext);
const _mimeType = mime.mimeType;
const isBinary = mime.isBinary;
this.fileOptions[id][name] = this.fileOptions[id][name] || { createdAt: Date.now() };
this.fileOptions[id][name].acl = this.fileOptions[id][name].acl || {
owner: options.user || this.defaultNewAcl && this.defaultNewAcl.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
ownerGroup: options.group || this.defaultNewAcl && this.defaultNewAcl.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
permissions: options.mode || this.defaultNewAcl && 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
// 0x644
};
this.fileOptions[id][name].mimeType = options.mimeType || _mimeType;
this.fileOptions[id][name].binary = isBinary;
this.fileOptions[id][name].acl.ownerGroup = this.fileOptions[id][name].acl.ownerGroup || this.defaultNewAcl && this.defaultNewAcl.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP;
this.fileOptions[id][name].modifiedAt = Date.now();
try {
import_fs_extra.default.ensureDirSync(import_node_path.default.join(this.objectsDir, id, import_node_path.default.dirname(name)));
import_fs_extra.default.writeFileSync(import_node_path.default.join(this.objectsDir, id, name), data, {
flag: "w",
encoding: isBinary ? "binary" : "utf8"
});
if (isBinary) {
delete this.files[id][name];
} else {
this.files[id][name] = data;
}
this._saveFileSettings(id);
} catch (e) {
this.log.error(`${this.namespace} Cannot write files: ${import_node_path.default.join(this.objectsDir, id, name)}: ${e.message}`);
throw e;
}
setImmediate((name2, size) => {
this.log.silly(`${this.namespace} memory publish ${id} ${JSON.stringify({ name: name2, file: true, size })}`);
this.publishAll("files", `${id}$%$${name2}`, size);
}, name, data.byteLength);
}
// needed by server
_readFile(id, name, options) {
if (options && options.acl) {
options.acl = null;
}
const _path = import_db_objects_redis.objectsUtils.sanitizePath(id, name);
id = _path.id;
name = _path.name;
options = options || {};
try {
this._loadFileSettings(id);
this.files[id] = this.files[id] || {};
if (!this.files[id][name] || this.settings.connection.noFileCache || options.noFileCache) {
const location = import_node_path.default.join(this.objectsDir, id, name);
if (import_fs_extra.default.existsSync(location)) {
this.fileOptions[id][name] = this.fileOptions[id][name] || {
acl: {
owner: this.defaultNewAcl && this.defaultNewAcl.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
ownerGroup: this.defaultNewAcl && this.defaultNewAcl.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
permissions: this.defaultNewAcl && this.defaultNewAcl.file.permissions || 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
// 777
}
};
if (typeof this.fileOptions[id][name] !== "object") {
this.fileOptions[id][name] = {
mimeType: this.fileOptions[id][name],
acl: {
owner: this.defaultNewAcl && this.defaultNewAcl.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
ownerGroup: this.defaultNewAcl && this.defaultNewAcl.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
permissions: this.defaultNewAcl && this.defaultNewAcl.file.permissions || 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
// 777
}
};
}
this.files[id][name] = import_fs_extra.default.readFileSync(location);
if (this.fileOptions[id][name].binary === void 0) {
const ext = import_node_path.default.extname(name);
const mimeType = import_db_objects_redis.objectsUtils.getMimeType(ext);
this.fileOptions[id][name].binary = mimeType.isBinary;
this.fileOptions[id][name].mimeType = mimeType.mimeType;
}
if (!this.fileOptions[id][name].binary) {
if (this.files[id][name]) {
this.files[id][name] = this.files[id][name].toString();
}
}
} else {
if (this.fileOptions[id][name] !== void 0) {
delete this.fileOptions[id][name];
}
if (this.files[id][name] !== void 0) {
delete this.files[id][name];
}
}
}
if (this.fileOptions[id][name] && !this.fileOptions[id][name].acl) {
this.fileOptions[id][name].acl = {
owner: this.defaultNewAcl && this.defaultNewAcl.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
ownerGroup: this.defaultNewAcl && this.defaultNewAcl.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
permissions: this.defaultNewAcl && this.defaultNewAcl.file.permissions || 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
// 776
};
}
if (this.fileOptions[id][name] !== null && this.fileOptions[id][name] !== void 0) {
if (!this.fileOptions[id][name].mimeType) {
const _ext = import_node_path.default.extname(name);
const _mimeType = import_db_objects_redis.objectsUtils.getMimeType(_ext);
this.fileOptions[id][name].mimeType = _mimeType.mimeType;
}
return {
fileContent: this.files[id][name],
fileMime: this.fileOptions[id][name].mimeType
};
}
} catch (e) {
this.log.warn(`${this.namespace} Cannot read file ${id} / ${name}: ${e.message}`);
throw e;
}
throw new Error(import_db_objects_redis.objectsUtils.ERRORS.ERROR_NOT_FOUND);
}
/**
* Check if given object exists
*
* @param id id of the object
* @returns if the object exists
*/
// needed by server
_objectExists(id) {
if (!id || typeof id !== "string") {
throw new Error(`invalid id ${JSON.stringify(id)}`);
}
try {
return Object.prototype.hasOwnProperty.call(this.dataset, id);
} catch (e) {
this.log.error(`${this.namespace} Cannot check object existence of "${id}": ${e.message}`);
throw new Error(`Cannot check object existence of "${id}": ${e.message}`);
}
}
/**
* Check if given file exists
*
* @param id id of the namespace
* @param [name] name of the file
* @returns
*/
// needed by server
_fileExists(id, name) {
if (typeof name !== "string") {
name = "";
}
const location = import_node_path.default.join(this.objectsDir, id, name);
try {
const stat = import_fs_extra.default.statSync(location);
return stat.isFile();
} catch (e) {
if (e.code !== "ENOENT") {
this.log.error(`${this.namespace} Cannot check file existence of "${location}": ${e.message}`);
throw new Error(`Cannot check file existence of "${location}": ${e.message}`);
}
return false;
}
}
/**
* Check if given directory exists
*
* @param id id of the namespace
* @param [name] name of the directory
* @returns
*/
// special functionality only for Server (used together with SyncFileDirectory)
dirExists(id, name) {
if (typeof name !== "string") {
name = "";
}
const location = import_node_path.default.join(this.objectsDir, id, name);
try {
const stat = import_fs_extra.default.statSync(location);
return stat.isDirectory();
} catch (e) {
if (e.code !== "ENOENT") {
this.log.error(`${this.namespace} Cannot check directory existence of "${location}": ${e.message}`);
throw new Error(`Cannot check directory existence of "${location}": ${e.message}`);
}
return false;
}
}
// needed by server
_unlink(id, name) {
const _path = import_db_objects_redis.objectsUtils.sanitizePath(id, name);
id = _path.id;
name = _path.name;
this._loadFileSettings(id);
const location = import_node_path.default.join(this.objectsDir, id, name);
if (import_fs_extra.default.existsSync(location)) {
const stat = import_fs_extra.default.statSync(location);
if (stat.isDirectory()) {
import_fs_extra.default.readdirSync(location).forEach((dir) => this._unlink(id, `${name}/${dir}`));
this.log.debug(`Delete directory ${import_node_path.default.join(id, name)}`);
try {
import_fs_extra.default.removeSync(location);
} catch (e) {
this.log.error(`${this.namespace} Cannot delete directory "${import_node_path.default.join(id, name)}": ${e.message}`);
throw e;
}
if (this.fileOptions[id]) {
delete this.fileOptions[id];
}
if (this.files[id] && this.files[id]) {
delete this.files[id];
}
} else {
this.log.debug(`Delete file ${import_node_path.default.join(id, name)}`);
try {
import_fs_extra.default.removeSync(location);
} catch (e) {
this.log.error(`${this.namespace} Cannot delete file "${import_node_path.default.join(id, name)}": ${e.message}`);
throw e;
}
if (this.fileOptions[id][name]) {
delete this.fileOptions[id][name];
}
if (this.files[id] && this.files[id][name]) {
delete this.files[id][name];
}
this._saveFileSettings(id, true);
}
setImmediate((id2, name2) => {
this.log.silly(`${this.namespace} memory publish ${id2} ${JSON.stringify({ name: name2, file: true, size: null })}`);
this.publishAll("files", `${id2}$%$${name2}`, null);
}, id, name);
}
}
// needed by server
_readDir(id, name, options) {
if (options && options.acl) {
options.acl = null;
}
if ((id === "" || id === "/" || id === "*") && (name === "" || name === "*")) {
} else {
const _path = import_db_objects_redis.objectsUtils.sanitizePath(id, name);
id = _path.id;
name = _path.name;
}
options = options || {};
const _files = [];
if (id && id === "*") {
id = "";
}
if (name && name[name.length - 1] !== "/") {
name += "/";
}
this._loadFileSettings(id);
const len = name ? name.length : 0;
for (const f2 of Object.keys(this.fileOptions[id])) {
if (!name || f2.substring(0, len) === name) {
let rest = f2.substring(len);
rest = rest.split("/", 2);
if (rest[0] && _files.indexOf(rest[0]) === -1) {
_files.push(rest[0]);
}
}
}
const location = import_node_path.default.join(this.objectsDir, id, name);
if (import_fs_extra.default.existsSync(location) && import_fs_extra.default.statSync(location).isDirectory()) {
const dirFiles = import_fs_extra.default.readdirSync(location);
for (let i = 0; i < dirFiles.length; i++) {
if (dirFiles[i] === ".." || dirFiles[i] === ".") {
continue;
}
if (dirFiles[i] !== "_data.json" && _files.indexOf(dirFiles[i]) === -1) {
_files.push(dirFiles[i]);
}
}
} else {
throw new Error(import_db_objects_redis.objectsUtils.ERRORS.ERROR_NOT_FOUND);
}
_files.sort();
const res = [];
for (const file of _files) {
if (file === ".." || file === ".") {
continue;
}
if (import_fs_extra.default.existsSync(import_node_path.default.join(location, file))) {
try {
const stats = import_fs_extra.default.statSync(import_node_path.default.join(location, file));
const acl = this.fileOptions[id][name + file] && this.fileOptions[id][name + file].acl ? (0, import_deep_clone.default)(this.fileOptions[id][name + file].acl) : {
read: true,
write: true,
owner: this.defaultNewAcl && this.defaultNewAcl.owner || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER,
ownerGroup: this.defaultNewAcl && this.defaultNewAcl.ownerGroup || import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP,
permissions: this.defaultNewAcl && this.defaultNewAcl.file.permissions || 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
};
if (options.filter && acl) {
if (!options.acl.file.write) {
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);
}
if (!options.acl.file.read) {
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);
}
if (options.user !== import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_USER && options.groups.includes(import_db_objects_redis.objectsUtils.CONSTS.SYSTEM_ADMIN_GROUP)) {
if (acl.owner !== options.user) {
if (options.groups.includes(acl.ownerGroup)) {
if (!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_RW)) {
continue;
}
acl.read = !!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_READ);
acl.write = !!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_GROUP_WRITE);
} else {
if (!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_RW)) {
continue;
}
acl.read = !!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_READ);
acl.write = !!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_EVERY_WRITE);
}
} else {
if (!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_RW)) {
continue;
}
acl.read = !!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_READ);
acl.write = !!(acl.permissions & import_db_objects_redis.objectsUtils.CONSTS.ACCESS_USER_WRITE);
}
} else {
acl.read = true;
acl.write = true;
}
}
res.push({
file,
stats,
isDir: stats.isDirectory(),
acl,
modifiedAt: this.fileOptions[id][name + file] ? this.fileOptions[id][name + file].modifiedAt : void 0,
createdAt: this.fileOptions[id][name + file] ? this.fileOptions[id][name + file].createdAt : void 0
});
} catch (e) {
this.log.error(`${this.namespace} Cannot read permissions of ${import_node_path.default.join(this.objectsDir, id, name, file)}: ${e.message}`);
}
}
}
return res;
}
// needed by server
_rename(id, oldName, newName) {
const _path = import_db_objects_redis.objectsUtils.sanitizePath(id, oldName);
id = _path.id;
oldName = _path.name;
if (newName[0] === "/") {
newName = newName.substring(1);
}
this._loadFileSettings(id);
if (import_fs_extra.default.existsSync(import_node_path.default.join(this.objectsDir, id, oldName))) {
import_fs_extra.default.renameSync(import_node_path.default.join(this.objectsDir, id, oldName), import_node_path.default.join(this.objectsDir, id, newName));
} else {
throw new Error(import_db_objects_redis.objectsUtils.ERRORS.ERROR_NOT_FOUND);
}
Object.keys(this.fileOptions[id]).forEach((name) => {
const type = this.fileOptions[id][name];
if (name.startsWith(oldName)) {
delete this.fileOptions[id][name];
this.fileOptions[id][name.replace(oldName, newName)] = type;
}
});
Object.keys(this.files[id]).forEach((name) => {
const data = this.files[id][name];
if (name.startsWith(oldName)) {
delete this.files[id][name];
this.files[id][name.replace(oldName, newName)] = data;
}
});
this._saveFileSettings(id, true);
}
// internal functionality
_clone(obj) {
if (obj === null || obj === void 0 || !import_db_base2.tools.isObject(obj)) {
return obj;
}
const temp = obj.constructor();
for (const key of Object.keys(obj)) {
temp[key] = this._clone(obj[key]);
}
return temp;
}
_subscribeMeta(client, pattern) {
this.handleSubscribe(client, "meta", pattern);
}
// needed by server
_subscribeConfigForClient(client, pattern) {
this.handleSubscribe(client, "objects", pattern);
}
// needed by server
_unsubscribeConfigForClient(client, pattern) {
this.handleUnsubscribe(client, "objects", pattern);
}
// needed by server
_subscribeFileForClient(client, id, pattern) {
if (Array.isArray(pattern)) {
pattern.forEach((pattern2) => this.handleSubscribe(client, "files", `${id}$%$${pattern2}`));
} else {
this.handleSubscribe(client, "files", `${id}$%$${pattern}`);
}
}
// needed by server
_unsubscribeFileForClient(client, id, pattern) {
if (Array.isArray(pattern)) {
pattern.forEach((pattern2) => this.handleUnsubscribe(client, "files", `${id}$%$${pattern2}`));
} else {
this.handleUnsubscribe(client, "files", `${id}$%$${pattern}`);
}
}
// needed by server
_getObject(id) {
return this.dataset[id];
}
// needed by server
_getKeys(pattern) {
const r = new RegExp(import_db_base2.tools.pattern2RegEx(pattern));
const result2 = Object.keys(this.dataset).filter((id) => r.test(id) && id !== this.META_ID);
result2.sort();
return result2;
}
// needed by server
_getObjects(keys) {
if (!keys) {
throw new Error("no keys");
}
return keys.map((id) => this.dataset[id]);
}
_ensureMetaDict() {
let meta = this.dataset[this.META_ID];
if (!meta) {
meta = {};
this.dataset[this.META_ID] = meta;
}
return meta;
}
/**
* Get value of given meta id
*
* @param id
* @returns
*/
getMeta(id) {
const meta = this._ensureMetaDict();
return meta[id];
}
/**
* Sets given value to id in metaNamespace
*
* @param id
* @param value
*/
setMeta(id, value) {
const meta = this._ensureMetaDict();
meta[id] = value;
this.dataset[this.META_ID] = meta;
setImmediate(() => {
this.log.silly(`${this.namespace} memory publish meta ${id} ${value}`);
this.publishAll("meta", id, value);
});
if (!this.stateTimer) {
this.stateTimer = setTimeout(() => this.saveState(), this.writeFileInterval);
}
}
// needed by server
_setObjectDirect(id, obj) {
this.dataset[id] = obj;
if (obj.type === "meta" && this.existingMetaObjects[id] === false) {
this.existingMetaObjects[id] = true;
}
setImmediate(() => this.publishAll("objects", id, obj));
this.stateTimer = this.stateTimer || setTimeout(() => this.saveState(), this.writeFileInterval);
}
/**
* Delete the given object from the dataset
*
* @param id unique id of the object
*/
_delObject(id) {
const obj = this.dataset[id];
if (!obj) {
return;
}
if (obj.common?.dontDelete) {
throw new Error("Object is marked as non deletable");
}
delete this.dataset[id];
if (this.existingMetaObjects[id]) {
this.existingMetaObjects[id] = false;
}
setImmediate(() => this.publishAll("objects", id, null));
if (!this.stateTimer) {
this.stateTimer = setTimeout(() => this.saveState(), this.writeFileInterval);
}
}
// internal functionality
_applyView(func, params) {
const result = {
rows: []
};
function _emit_(id, obj) {
result.rows.push({ id, value: obj });
}
const f = eval(`(${func.map.replace(/emit/g, "_emit_")})`);
for (const [id, obj] of Object.entries(this.dataset)) {
if (params) {
if (params.startkey && id < params.startkey) {
continue;
}
if (params.endkey && id > params.endkey) {
continue;
}
}
if (obj) {
try {
f(obj);
} catch (e) {
this.log.warn(`${this.namespace} Cannot execute map: ${e.message}`);
}
}
}
if (func.reduce === "_stats") {
let max = null;
for (const row of result.rows) {
if (max === null || row.value > max) {
max = row.value;
}
}
if (max !== null) {
result.rows = [{ id: "_stats", value: { max } }];
} else {
result.rows = [];
}
}
return result;
}
// needed by server
_getObjectView(design, search, params2) {
const designObj = this.dataset[`_design/${design}`];
if (!designObj) {
this.log.error(`${this.namespace} Cannot find view "${design}"`);
throw new Error(`Cannot find view "${design}"`);
}
if (!(designObj.views && designObj.views[search])) {
this.log.warn(`${this.namespace} Cannot find search "${search}" in "${design}"`);
throw new Error(`Cannot find search "${search}" in "${design}"`);
}
return this._applyView(designObj.views[search], params2);
}
/**
* Destructor of the class. Called by shutting down.
*/
async destroy() {
await super.destroy();
this._saveFileSettings(true);
if (this.stateTimer) {
clearTimeout(this.stateTimer);
this.stateTimer = null;
}
if (this.writeTimer) {
clearTimeout(this.writeTimer);
this.writeTimer = null;
}
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ObjectsInMemoryFileDB
});
//# sourceMappingURL=objectsInMemFileDB.js.map