@iobroker/db-base 7.2.3-alpha.8-20260709-8d8c9c5ed → 7.2.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.
- package/build/cjs/index.d.ts +1 -1
- package/build/cjs/index.js +3 -3
- package/build/cjs/index.js.map +2 -2
- package/build/cjs/lib/inMemFileDB.d.ts +44 -155
- package/build/cjs/lib/inMemFileDB.js +46 -108
- package/build/cjs/lib/inMemFileDB.js.map +2 -2
- package/build/cjs/lib/redisHandler.d.ts +1 -1
- package/build/cjs/lib/redisHandler.js +11 -11
- package/build/cjs/lib/redisHandler.js.map +2 -2
- package/build/esm/index.d.ts +1 -1
- package/build/esm/index.d.ts.map +1 -1
- package/build/esm/index.js +1 -1
- package/build/esm/index.js.map +1 -1
- package/build/esm/lib/inMemFileDB.d.ts +44 -155
- package/build/esm/lib/inMemFileDB.d.ts.map +1 -1
- package/build/esm/lib/inMemFileDB.js +49 -107
- package/build/esm/lib/inMemFileDB.js.map +1 -1
- package/build/esm/lib/redisHandler.d.ts +1 -1
- package/build/esm/lib/redisHandler.d.ts.map +1 -1
- package/build/esm/lib/redisHandler.js +11 -7
- package/build/esm/lib/redisHandler.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -6
package/build/cjs/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { InMemoryFileDB
|
|
1
|
+
export { InMemoryFileDB } from './lib/inMemFileDB.js';
|
|
2
2
|
export { RedisHandler } from './lib/redisHandler.js';
|
|
3
3
|
export { tools } from '@iobroker/js-controller-common-db';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/build/cjs/index.js
CHANGED
|
@@ -16,13 +16,13 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var
|
|
20
|
-
__export(
|
|
19
|
+
var esm_exports = {};
|
|
20
|
+
__export(esm_exports, {
|
|
21
21
|
InMemoryFileDB: () => import_inMemFileDB.InMemoryFileDB,
|
|
22
22
|
RedisHandler: () => import_redisHandler.RedisHandler,
|
|
23
23
|
tools: () => import_js_controller_common_db.tools
|
|
24
24
|
});
|
|
25
|
-
module.exports = __toCommonJS(
|
|
25
|
+
module.exports = __toCommonJS(esm_exports);
|
|
26
26
|
var import_inMemFileDB = require("./lib/inMemFileDB.js");
|
|
27
27
|
var import_redisHandler = require("./lib/redisHandler.js");
|
|
28
28
|
var import_js_controller_common_db = require("@iobroker/js-controller-common-db");
|
package/build/cjs/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;;;;;;;AAAA,
|
|
4
|
+
"sourcesContent": ["export { InMemoryFileDB } from './lib/inMemFileDB.js';\nexport { RedisHandler } from './lib/redisHandler.js';\nexport { tools } from '@iobroker/js-controller-common-db';\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;;;;;;;AAAA,yBAA+B;AAC/B,0BAA6B;AAC7B,qCAAsB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,120 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* States DB in memory - Server
|
|
3
3
|
*
|
|
4
|
-
* Copyright 2013-
|
|
4
|
+
* Copyright 2013-2024 bluefox <dogafox@gmail.com>
|
|
5
5
|
*
|
|
6
6
|
* MIT License
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
import type { InternalLogger } from '@iobroker/js-controller-common-db/tools';
|
|
10
|
-
interface BackupOptions {
|
|
11
|
-
/** deactivates backup if true */
|
|
12
|
-
disabled: boolean;
|
|
13
|
-
/** minimum number of files */
|
|
14
|
-
files: number;
|
|
15
|
-
hours: number;
|
|
16
|
-
/** minutes */
|
|
17
|
-
period: number;
|
|
18
|
-
path: string;
|
|
19
|
-
}
|
|
20
|
-
export type MetaObject = Record<string, string>;
|
|
21
|
-
export type FileSize = number;
|
|
22
|
-
/** Options describing how to connect to the database server */
|
|
23
10
|
export interface ConnectionOptions {
|
|
24
|
-
/** Password for authentication, if required */
|
|
25
11
|
pass?: string;
|
|
26
|
-
/** Name of the sentinel master to connect to */
|
|
27
12
|
sentinelName?: string;
|
|
28
13
|
/** array on sentinel */
|
|
29
14
|
host: string | string[];
|
|
30
15
|
/** array on sentinel */
|
|
31
16
|
port: number | number[];
|
|
32
|
-
|
|
33
|
-
options: ioBroker.ObjectsDatabaseOptions['options'];
|
|
34
|
-
/** Options forwarded to the JSONL database backend */
|
|
35
|
-
jsonlOptions?: ioBroker.ObjectsDatabaseOptions['jsonlOptions'];
|
|
36
|
-
/** Redis key prefix used by the in-memory server */
|
|
37
|
-
redisNamespace?: string;
|
|
38
|
-
/** Enable more verbose connection logging */
|
|
17
|
+
options: Record<string, any>;
|
|
39
18
|
enhancedLogging?: boolean;
|
|
40
|
-
/** Disable the in-memory file cache and always read files from disk */
|
|
41
|
-
noFileCache?: boolean;
|
|
42
|
-
/** Whether the connection should be secured via TLS */
|
|
43
|
-
secure?: boolean;
|
|
44
|
-
/** Backup configuration */
|
|
45
19
|
backup?: BackupOptions;
|
|
46
20
|
/** relative path to the data dir */
|
|
47
21
|
dataDir?: string;
|
|
48
|
-
/** Interval in milliseconds in which the in-memory states are persisted to disk */
|
|
49
|
-
writeFileInterval?: number;
|
|
50
22
|
}
|
|
51
|
-
type ChangeFunction
|
|
52
|
-
/** Status information about the database */
|
|
23
|
+
type ChangeFunction = (id: string, state: any) => void;
|
|
53
24
|
export interface DbStatus {
|
|
54
|
-
|
|
55
|
-
type: 'file' | 'redis' | 'jsonl';
|
|
56
|
-
/** Whether this process runs the database server */
|
|
25
|
+
type: string;
|
|
57
26
|
server: boolean;
|
|
58
27
|
}
|
|
59
|
-
|
|
28
|
+
interface BackupOptions {
|
|
29
|
+
/** deactivates backup if true */
|
|
30
|
+
disabled: boolean;
|
|
31
|
+
/** minimum number of files */
|
|
32
|
+
files: number;
|
|
33
|
+
hours: number;
|
|
34
|
+
/** minutes */
|
|
35
|
+
period: number;
|
|
36
|
+
path: string;
|
|
37
|
+
}
|
|
60
38
|
export interface DbOptions {
|
|
61
|
-
/** Name of the directory used for backups */
|
|
62
39
|
backupDirName: string;
|
|
63
|
-
/** Name of the database file */
|
|
64
40
|
fileName: string;
|
|
65
41
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
backup?: BackupOptions;
|
|
74
|
-
/** Callback invoked when a value in the database changes */
|
|
75
|
-
change?: ChangeFunction<TObject>;
|
|
76
|
-
/** Callback invoked once the database server is ready */
|
|
77
|
-
connected: (nameOfServer?: string) => void;
|
|
78
|
-
/** Logger instance (or logger configuration) used for all database logging */
|
|
79
|
-
logger?: InternalLogger;
|
|
80
|
-
/** Options describing how to connect to the database server */
|
|
42
|
+
interface FileDbSettings {
|
|
43
|
+
fileDB: DbOptions;
|
|
44
|
+
jsonlDB: DbOptions;
|
|
45
|
+
backup: BackupOptions;
|
|
46
|
+
change?: ChangeFunction;
|
|
47
|
+
connected: (nameOfServer: string) => void;
|
|
48
|
+
logger: InternalLogger;
|
|
81
49
|
connection: ConnectionOptions;
|
|
82
50
|
/** unused */
|
|
83
51
|
auth?: null;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
port
|
|
88
|
-
|
|
89
|
-
host?: string;
|
|
52
|
+
secure: boolean;
|
|
53
|
+
/** as required by createServer TODO: if createServer is typed, add type */
|
|
54
|
+
certificates: any;
|
|
55
|
+
port: number;
|
|
56
|
+
host: string;
|
|
90
57
|
/** logging namespace */
|
|
91
58
|
namespace?: string;
|
|
92
|
-
/** Host name used as a fallback for the logging namespace */
|
|
93
|
-
hostname?: string;
|
|
94
|
-
/** Default ACL applied to newly created objects */
|
|
95
|
-
defaultNewAcl?: {
|
|
96
|
-
object: number;
|
|
97
|
-
state: number;
|
|
98
|
-
file: number;
|
|
99
|
-
owner: ioBroker.ObjectIDs.User;
|
|
100
|
-
ownerGroup: ioBroker.ObjectIDs.Group;
|
|
101
|
-
};
|
|
102
|
-
/** Redis key prefix used by the in-memory server (defaults to "io") */
|
|
103
|
-
redisNamespace?: string;
|
|
104
|
-
/** Namespace used for the message box */
|
|
105
|
-
namespaceMsg?: string;
|
|
106
|
-
/** Namespace used for log messages */
|
|
107
|
-
namespaceLog?: string;
|
|
108
|
-
/** Namespace used for sessions */
|
|
109
|
-
namespaceSession?: string;
|
|
110
|
-
/** Namespace used for meta information */
|
|
111
|
-
metaNamespace?: string;
|
|
112
|
-
/** Redis key prefix used for object meta information (defaults to "meta") */
|
|
113
|
-
namespaceMeta?: string;
|
|
114
59
|
}
|
|
115
60
|
interface Subscription {
|
|
116
61
|
pattern: string;
|
|
117
62
|
regex: RegExp;
|
|
63
|
+
options: any;
|
|
118
64
|
}
|
|
119
65
|
interface SubscriptionClient {
|
|
120
66
|
_subscribe?: Record<string, Subscription[]>;
|
|
@@ -123,25 +69,19 @@ interface SubscriptionClient {
|
|
|
123
69
|
* The parent of the class structure, which provides basic JSON storage
|
|
124
70
|
* and general subscription and publish functionality
|
|
125
71
|
*/
|
|
126
|
-
export declare class InMemoryFileDB
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
protected dataset: Record<string,
|
|
130
|
-
|
|
72
|
+
export declare class InMemoryFileDB {
|
|
73
|
+
private settings;
|
|
74
|
+
private readonly change;
|
|
75
|
+
protected dataset: Record<string, any>;
|
|
76
|
+
private readonly namespace;
|
|
131
77
|
private lastSave;
|
|
132
|
-
|
|
78
|
+
private stateTimer;
|
|
133
79
|
private callbackSubscriptionClient;
|
|
134
|
-
|
|
80
|
+
private readonly dataDir;
|
|
135
81
|
private readonly datasetName;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
* @param settings Settings for the database, the connection and backups
|
|
140
|
-
*/
|
|
141
|
-
constructor(settings: FileDbSettings<TObject>);
|
|
142
|
-
/**
|
|
143
|
-
* Open the database by loading the dataset from disk
|
|
144
|
-
*/
|
|
82
|
+
private log;
|
|
83
|
+
private readonly backupDir;
|
|
84
|
+
constructor(settings: FileDbSettings);
|
|
145
85
|
open(): Promise<void>;
|
|
146
86
|
/**
|
|
147
87
|
* Loads a dataset file
|
|
@@ -149,55 +89,20 @@ export declare class InMemoryFileDB<TObject, THandler extends SubscriptionClient
|
|
|
149
89
|
* @param datasetName Filename of the file to load
|
|
150
90
|
* @returns obj read data, normally as object
|
|
151
91
|
*/
|
|
152
|
-
loadDatasetFile(datasetName: string): Promise<Record<string,
|
|
92
|
+
loadDatasetFile(datasetName: string): Promise<Record<string, any>>;
|
|
153
93
|
/**
|
|
154
94
|
* Loads the dataset including pot. Fallback handling
|
|
155
95
|
*
|
|
156
96
|
* @param datasetName Filename of the file to load
|
|
157
97
|
* @returns obj dataset read as object
|
|
158
98
|
*/
|
|
159
|
-
loadDataset(datasetName: string): Promise<Record<string,
|
|
160
|
-
/**
|
|
161
|
-
* Normalize the backup settings and create the backup directory
|
|
162
|
-
*/
|
|
99
|
+
loadDataset(datasetName: string): Promise<Record<string, any>>;
|
|
163
100
|
initBackupDir(): void;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
*
|
|
167
|
-
* @param client The client to register the subscription for
|
|
168
|
-
* @param type The subscription type (e.g. objects or states)
|
|
169
|
-
* @param pattern One or more patterns to subscribe to
|
|
170
|
-
*/
|
|
171
|
-
handleSubscribe(client: SubscriptionClient, type: string, pattern: string | string[]): void;
|
|
172
|
-
/**
|
|
173
|
-
* Remove a client's subscription for the given pattern
|
|
174
|
-
*
|
|
175
|
-
* @param client The client whose subscription should be removed
|
|
176
|
-
* @param type The subscription type (e.g. objects or states)
|
|
177
|
-
* @param pattern One or more patterns to unsubscribe from
|
|
178
|
-
* @param cb Called once the subscription has been removed
|
|
179
|
-
*/
|
|
101
|
+
handleSubscribe(client: SubscriptionClient, type: string, pattern: string | string[], cb?: () => void): void;
|
|
102
|
+
handleSubscribe(client: SubscriptionClient, type: string, pattern: string | string[], options: any, cb?: () => void): void;
|
|
180
103
|
handleUnsubscribe(client: SubscriptionClient, type: string, pattern: string | string[], cb?: () => void): void | Promise<void>;
|
|
181
|
-
|
|
182
|
-
* Publish a change to a single client. Must be implemented by a subclass that handles client communication.
|
|
183
|
-
*
|
|
184
|
-
* @param _client The client to publish to
|
|
185
|
-
* @param _type The change type (e.g. objects or states)
|
|
186
|
-
* @param _id The ID of the changed object or state
|
|
187
|
-
* @param _obj The new value of the object or state
|
|
188
|
-
*/
|
|
189
|
-
publishToClients(_client: SubscriptionClient, _type: string, _id: string, _obj: TObject | string | null | FileSize | MetaObject): number;
|
|
190
|
-
/**
|
|
191
|
-
* Delete outdated backup files according to the configured retention settings
|
|
192
|
-
*
|
|
193
|
-
* @param baseFilename Base file name of the backups that should be pruned
|
|
194
|
-
*/
|
|
104
|
+
publishToClients(_client: SubscriptionClient, _type: string, _id: string, _obj: any): number;
|
|
195
105
|
deleteOldBackupFiles(baseFilename: string): void;
|
|
196
|
-
/**
|
|
197
|
-
* Format a timestamp into a "YYYY-MM-DD_HH-MM-SS" string used for backup file names
|
|
198
|
-
*
|
|
199
|
-
* @param date Timestamp in milliseconds
|
|
200
|
-
*/
|
|
201
106
|
getTimeStr(date: number): string;
|
|
202
107
|
/**
|
|
203
108
|
* Handle saving the dataset incl. backups
|
|
@@ -215,25 +120,9 @@ export declare class InMemoryFileDB<TObject, THandler extends SubscriptionClient
|
|
|
215
120
|
* @param jsonString JSON string of the complete dataset to also be stored into a compressed backup file
|
|
216
121
|
*/
|
|
217
122
|
saveBackup(jsonString: string): void;
|
|
218
|
-
/**
|
|
219
|
-
* Get the current status of the database
|
|
220
|
-
*/
|
|
221
123
|
getStatus(): DbStatus;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
*/
|
|
225
|
-
getClients(): Record<string, THandler>;
|
|
226
|
-
/**
|
|
227
|
-
* Publish a change to all connected clients and local subscribers
|
|
228
|
-
*
|
|
229
|
-
* @param type The change type (e.g. objects or states)
|
|
230
|
-
* @param id The ID of the changed object or state
|
|
231
|
-
* @param obj The new value of the object or state
|
|
232
|
-
*/
|
|
233
|
-
publishAll(type: string, id: string, obj: TObject | string | null | FileSize | MetaObject): number;
|
|
234
|
-
/**
|
|
235
|
-
* Destructor of the class. Called when shutting down to persist state and clear timers.
|
|
236
|
-
*/
|
|
124
|
+
getClients(): Record<string, any>;
|
|
125
|
+
publishAll(type: string, id: string, obj: any): number;
|
|
237
126
|
destroy(): Promise<void>;
|
|
238
127
|
}
|
|
239
128
|
export {};
|
|
@@ -5,7 +5,6 @@ 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 });
|
|
9
8
|
var __export = (target, all) => {
|
|
10
9
|
for (var name in all)
|
|
11
10
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -37,27 +36,24 @@ var import_node_path = __toESM(require("node:path"), 1);
|
|
|
37
36
|
var import_js_controller_common_db = require("@iobroker/js-controller-common-db");
|
|
38
37
|
var import_node_zlib = require("node:zlib");
|
|
39
38
|
class InMemoryFileDB {
|
|
40
|
-
static {
|
|
41
|
-
__name(this, "InMemoryFileDB");
|
|
42
|
-
}
|
|
43
39
|
settings;
|
|
44
40
|
change;
|
|
45
|
-
dataset
|
|
41
|
+
dataset;
|
|
46
42
|
namespace;
|
|
47
|
-
lastSave
|
|
48
|
-
stateTimer
|
|
49
|
-
callbackSubscriptionClient
|
|
43
|
+
lastSave;
|
|
44
|
+
stateTimer;
|
|
45
|
+
callbackSubscriptionClient;
|
|
50
46
|
dataDir;
|
|
51
47
|
datasetName;
|
|
52
48
|
log;
|
|
53
49
|
backupDir;
|
|
54
|
-
/**
|
|
55
|
-
* @param settings Settings for the database, the connection and backups
|
|
56
|
-
*/
|
|
57
50
|
constructor(settings) {
|
|
58
|
-
this.settings = settings;
|
|
51
|
+
this.settings = settings || {};
|
|
59
52
|
this.change = this.settings.change;
|
|
53
|
+
this.dataset = {};
|
|
60
54
|
this.namespace = this.settings.namespace || "";
|
|
55
|
+
this.lastSave = null;
|
|
56
|
+
this.callbackSubscriptionClient = {};
|
|
61
57
|
this.settings.backup = this.settings.connection.backup || {
|
|
62
58
|
disabled: false,
|
|
63
59
|
// deactivates
|
|
@@ -70,36 +66,29 @@ class InMemoryFileDB {
|
|
|
70
66
|
path: ""
|
|
71
67
|
// use default path
|
|
72
68
|
};
|
|
73
|
-
const backup = this.settings.backup;
|
|
74
69
|
this.dataDir = this.settings.connection.dataDir || import_js_controller_common_db.tools.getDefaultDataDir();
|
|
75
70
|
if (!import_node_path.default.isAbsolute(this.dataDir)) {
|
|
76
71
|
this.dataDir = import_node_path.default.normalize(import_node_path.default.join(import_js_controller_common_db.tools.getControllerDir(), this.dataDir));
|
|
77
72
|
}
|
|
78
73
|
this.dataDir = this.dataDir.replace(/\\/g, "/");
|
|
79
|
-
const
|
|
80
|
-
if (!fileDbOptions) {
|
|
81
|
-
throw new Error(`${this.namespace} No fileDB storage options were provided`);
|
|
82
|
-
}
|
|
83
|
-
const fileName = this.settings.jsonlDB ? this.settings.jsonlDB.fileName : fileDbOptions.fileName;
|
|
74
|
+
const fileName = this.settings.jsonlDB ? this.settings.jsonlDB.fileName : this.settings.fileDB.fileName;
|
|
84
75
|
this.datasetName = import_node_path.default.join(this.dataDir, fileName);
|
|
85
76
|
const parts = import_node_path.default.dirname(this.datasetName);
|
|
86
77
|
import_fs_extra.default.ensureDirSync(parts);
|
|
87
|
-
this.
|
|
78
|
+
this.stateTimer = null;
|
|
79
|
+
this.backupDir = this.settings.backup.path || import_node_path.default.join(this.dataDir, this.settings.fileDB.backupDirName);
|
|
88
80
|
this.log = import_js_controller_common_db.tools.getLogger(this.settings.logger);
|
|
89
|
-
if (!backup.disabled) {
|
|
81
|
+
if (!this.settings.backup.disabled) {
|
|
90
82
|
try {
|
|
91
83
|
this.initBackupDir();
|
|
92
84
|
} catch (e) {
|
|
93
85
|
this.log.error(`Database backups are disabled, because backup directory could not be initialized: ${e.message}`);
|
|
94
86
|
this.log.error("This leads to an increased risk of data loss, please check that the configured backup directory is available and restart the controller");
|
|
95
|
-
backup.disabled = true;
|
|
87
|
+
this.settings.backup.disabled = true;
|
|
96
88
|
}
|
|
97
89
|
}
|
|
98
90
|
this.log.debug(`${this.namespace} Data File: ${this.datasetName}`);
|
|
99
91
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Open the database by loading the dataset from disk
|
|
102
|
-
*/
|
|
103
92
|
async open() {
|
|
104
93
|
this.dataset = await this.loadDataset(this.datasetName);
|
|
105
94
|
}
|
|
@@ -162,75 +151,58 @@ class InMemoryFileDB {
|
|
|
162
151
|
}
|
|
163
152
|
return ret;
|
|
164
153
|
}
|
|
165
|
-
/**
|
|
166
|
-
* Normalize the backup settings and create the backup directory
|
|
167
|
-
*/
|
|
168
154
|
initBackupDir() {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
backup.period = backup.period === void 0 ? 120 : parseInt(String(backup.period));
|
|
175
|
-
if (isNaN(backup.period)) {
|
|
176
|
-
backup.period = 120;
|
|
155
|
+
this.settings.backup.period = this.settings.backup.period === void 0 ? 120 : parseInt(String(this.settings.backup.period));
|
|
156
|
+
if (isNaN(this.settings.backup.period)) {
|
|
157
|
+
this.settings.backup.period = 120;
|
|
177
158
|
}
|
|
178
159
|
const maxTimeoutMinutes = Math.floor((2 ** 31 - 1) / 6e4);
|
|
179
|
-
if (backup.period > maxTimeoutMinutes) {
|
|
180
|
-
this.log.warn(`${this.namespace} Configured backup period ${backup.period} is larger than the supported maximum of ${maxTimeoutMinutes} minutes. Defaulting to 120 minutes.`);
|
|
181
|
-
backup.period = 120;
|
|
160
|
+
if (this.settings.backup.period > maxTimeoutMinutes) {
|
|
161
|
+
this.log.warn(`${this.namespace} Configured backup period ${this.settings.backup.period} is larger than the supported maximum of ${maxTimeoutMinutes} minutes. Defaulting to 120 minutes.`);
|
|
162
|
+
this.settings.backup.period = 120;
|
|
182
163
|
}
|
|
183
|
-
backup.period *= 6e4;
|
|
184
|
-
backup.files = backup.files === void 0 ? 24 : parseInt(String(backup.files));
|
|
185
|
-
if (isNaN(backup.files)) {
|
|
186
|
-
backup.files = 24;
|
|
164
|
+
this.settings.backup.period *= 6e4;
|
|
165
|
+
this.settings.backup.files = this.settings.backup.files === void 0 ? 24 : parseInt(String(this.settings.backup.files));
|
|
166
|
+
if (isNaN(this.settings.backup.files)) {
|
|
167
|
+
this.settings.backup.files = 24;
|
|
187
168
|
}
|
|
188
|
-
backup.hours = backup.hours === void 0 ? 48 : parseInt(String(backup.hours));
|
|
189
|
-
if (isNaN(backup.hours)) {
|
|
190
|
-
backup.hours = 48;
|
|
169
|
+
this.settings.backup.hours = this.settings.backup.hours === void 0 ? 48 : parseInt(String(this.settings.backup.hours));
|
|
170
|
+
if (isNaN(this.settings.backup.hours)) {
|
|
171
|
+
this.settings.backup.hours = 48;
|
|
191
172
|
}
|
|
173
|
+
import_fs_extra.default.ensureDirSync(this.backupDir);
|
|
192
174
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
handleSubscribe(client, type, pattern) {
|
|
201
|
-
client._subscribe ||= {};
|
|
202
|
-
client._subscribe[type] ||= [];
|
|
175
|
+
handleSubscribe(client, type, pattern, options, cb) {
|
|
176
|
+
if (typeof options === "function") {
|
|
177
|
+
cb = options;
|
|
178
|
+
options = void 0;
|
|
179
|
+
}
|
|
180
|
+
client._subscribe = client._subscribe || {};
|
|
181
|
+
client._subscribe[type] = client._subscribe[type] || [];
|
|
203
182
|
const s = client._subscribe[type];
|
|
204
183
|
if (pattern instanceof Array) {
|
|
205
184
|
pattern.forEach((pattern2) => {
|
|
206
185
|
if (s.find((sub) => sub.pattern === pattern2)) {
|
|
207
186
|
return;
|
|
208
187
|
}
|
|
209
|
-
s.push({ pattern: pattern2, regex: new RegExp(import_js_controller_common_db.tools.pattern2RegEx(pattern2)) });
|
|
188
|
+
s.push({ pattern: pattern2, regex: new RegExp(import_js_controller_common_db.tools.pattern2RegEx(pattern2)), options });
|
|
210
189
|
});
|
|
211
190
|
} else {
|
|
212
191
|
if (!s.find((sub) => sub.pattern === pattern)) {
|
|
213
|
-
s.push({ pattern, regex: new RegExp(import_js_controller_common_db.tools.pattern2RegEx(pattern)) });
|
|
192
|
+
s.push({ pattern, regex: new RegExp(import_js_controller_common_db.tools.pattern2RegEx(pattern)), options });
|
|
214
193
|
}
|
|
215
194
|
}
|
|
195
|
+
typeof cb === "function" && cb();
|
|
216
196
|
}
|
|
217
|
-
/**
|
|
218
|
-
* Remove a client's subscription for the given pattern
|
|
219
|
-
*
|
|
220
|
-
* @param client The client whose subscription should be removed
|
|
221
|
-
* @param type The subscription type (e.g. objects or states)
|
|
222
|
-
* @param pattern One or more patterns to unsubscribe from
|
|
223
|
-
* @param cb Called once the subscription has been removed
|
|
224
|
-
*/
|
|
225
197
|
handleUnsubscribe(client, type, pattern, cb) {
|
|
226
198
|
const s = client?._subscribe?.[type];
|
|
227
199
|
if (s) {
|
|
228
|
-
const removeEntry =
|
|
200
|
+
const removeEntry = (p) => {
|
|
229
201
|
const index = s.findIndex((sub) => sub.pattern === p);
|
|
230
202
|
if (index > -1) {
|
|
231
203
|
s.splice(index, 1);
|
|
232
204
|
}
|
|
233
|
-
}
|
|
205
|
+
};
|
|
234
206
|
if (pattern instanceof Array) {
|
|
235
207
|
pattern.forEach((p) => {
|
|
236
208
|
removeEntry(p);
|
|
@@ -241,28 +213,15 @@ class InMemoryFileDB {
|
|
|
241
213
|
}
|
|
242
214
|
return import_js_controller_common_db.tools.maybeCallback(cb);
|
|
243
215
|
}
|
|
244
|
-
/**
|
|
245
|
-
* Publish a change to a single client. Must be implemented by a subclass that handles client communication.
|
|
246
|
-
*
|
|
247
|
-
* @param _client The client to publish to
|
|
248
|
-
* @param _type The change type (e.g. objects or states)
|
|
249
|
-
* @param _id The ID of the changed object or state
|
|
250
|
-
* @param _obj The new value of the object or state
|
|
251
|
-
*/
|
|
252
216
|
publishToClients(_client, _type, _id, _obj) {
|
|
253
217
|
throw new Error("no communication handling implemented");
|
|
254
218
|
}
|
|
255
|
-
/**
|
|
256
|
-
* Delete outdated backup files according to the configured retention settings
|
|
257
|
-
*
|
|
258
|
-
* @param baseFilename Base file name of the backups that should be pruned
|
|
259
|
-
*/
|
|
260
219
|
deleteOldBackupFiles(baseFilename) {
|
|
261
220
|
let files = import_fs_extra.default.readdirSync(this.backupDir);
|
|
262
221
|
files.sort();
|
|
263
|
-
const limit = Date.now() -
|
|
222
|
+
const limit = Date.now() - this.settings.backup.hours * 36e5;
|
|
264
223
|
files = files.filter((f) => f.endsWith(`${baseFilename}.gz`));
|
|
265
|
-
while (files.length >
|
|
224
|
+
while (files.length > this.settings.backup.files) {
|
|
266
225
|
const file = files.shift();
|
|
267
226
|
if (!file) {
|
|
268
227
|
continue;
|
|
@@ -277,11 +236,6 @@ class InMemoryFileDB {
|
|
|
277
236
|
}
|
|
278
237
|
}
|
|
279
238
|
}
|
|
280
|
-
/**
|
|
281
|
-
* Format a timestamp into a "YYYY-MM-DD_HH-MM-SS" string used for backup file names
|
|
282
|
-
*
|
|
283
|
-
* @param date Timestamp in milliseconds
|
|
284
|
-
*/
|
|
285
239
|
getTimeStr(date) {
|
|
286
240
|
const dateObj = new Date(date);
|
|
287
241
|
let text = `${dateObj.getFullYear().toString()}-`;
|
|
@@ -313,7 +267,7 @@ class InMemoryFileDB {
|
|
|
313
267
|
async saveState() {
|
|
314
268
|
try {
|
|
315
269
|
const jsonString = await this.saveDataset();
|
|
316
|
-
if (!this.settings.backup
|
|
270
|
+
if (!this.settings.backup.disabled && jsonString) {
|
|
317
271
|
this.saveBackup(jsonString);
|
|
318
272
|
}
|
|
319
273
|
} finally {
|
|
@@ -378,10 +332,9 @@ class InMemoryFileDB {
|
|
|
378
332
|
*/
|
|
379
333
|
saveBackup(jsonString) {
|
|
380
334
|
const now = Date.now();
|
|
381
|
-
|
|
382
|
-
if (fileName && this.settings.backup?.period && (!this.lastSave || now - this.lastSave > this.settings.backup.period)) {
|
|
335
|
+
if (this.settings.backup.period && (!this.lastSave || now - this.lastSave > this.settings.backup.period)) {
|
|
383
336
|
this.lastSave = now;
|
|
384
|
-
const backFileName = import_node_path.default.join(this.backupDir, `${this.getTimeStr(now)}_${fileName}.gz`);
|
|
337
|
+
const backFileName = import_node_path.default.join(this.backupDir, `${this.getTimeStr(now)}_${this.settings.fileDB.fileName}.gz`);
|
|
385
338
|
try {
|
|
386
339
|
if (!import_fs_extra.default.existsSync(backFileName)) {
|
|
387
340
|
const output = import_fs_extra.default.createWriteStream(backFileName);
|
|
@@ -392,32 +345,19 @@ class InMemoryFileDB {
|
|
|
392
345
|
compress.pipe(output);
|
|
393
346
|
compress.write(jsonString);
|
|
394
347
|
compress.end();
|
|
395
|
-
this.deleteOldBackupFiles(fileName);
|
|
348
|
+
this.deleteOldBackupFiles(this.settings.fileDB.fileName);
|
|
396
349
|
}
|
|
397
350
|
} catch (e) {
|
|
398
351
|
this.log.error(`${this.namespace} Cannot save backup ${backFileName}: ${e.message}`);
|
|
399
352
|
}
|
|
400
353
|
}
|
|
401
354
|
}
|
|
402
|
-
/**
|
|
403
|
-
* Get the current status of the database
|
|
404
|
-
*/
|
|
405
355
|
getStatus() {
|
|
406
356
|
return { type: "file", server: true };
|
|
407
357
|
}
|
|
408
|
-
/**
|
|
409
|
-
* Get the currently connected clients. Subclasses override this to return the real clients.
|
|
410
|
-
*/
|
|
411
358
|
getClients() {
|
|
412
359
|
return {};
|
|
413
360
|
}
|
|
414
|
-
/**
|
|
415
|
-
* Publish a change to all connected clients and local subscribers
|
|
416
|
-
*
|
|
417
|
-
* @param type The change type (e.g. objects or states)
|
|
418
|
-
* @param id The ID of the changed object or state
|
|
419
|
-
* @param obj The new value of the object or state
|
|
420
|
-
*/
|
|
421
361
|
publishAll(type, id, obj) {
|
|
422
362
|
if (id === void 0) {
|
|
423
363
|
this.log.error(`${this.namespace} Can not publish empty ID`);
|
|
@@ -440,9 +380,7 @@ class InMemoryFileDB {
|
|
|
440
380
|
}
|
|
441
381
|
return publishCount;
|
|
442
382
|
}
|
|
443
|
-
|
|
444
|
-
* Destructor of the class. Called when shutting down to persist state and clear timers.
|
|
445
|
-
*/
|
|
383
|
+
// Destructor of the class. Called by shutting down.
|
|
446
384
|
async destroy() {
|
|
447
385
|
if (this.stateTimer) {
|
|
448
386
|
clearTimeout(this.stateTimer);
|