@iobroker/db-objects-jsonl 4.0.0-alpha.45-20220114-88aaebdb → 4.0.0-alpha.49-20220121-e7aa4308
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.
|
@@ -54,7 +54,9 @@ class ObjectsInMemoryJsonlDB extends ObjectsInMemoryFileDB {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
async open() {
|
|
57
|
-
await this.
|
|
57
|
+
if (!(await this._maybeMigrateFileDB())) {
|
|
58
|
+
await this._db.open();
|
|
59
|
+
}
|
|
58
60
|
|
|
59
61
|
// Create an object-like wrapper around the internal Map
|
|
60
62
|
this.dataset = new Proxy(this._db, {
|
|
@@ -99,6 +101,82 @@ class ObjectsInMemoryJsonlDB extends ObjectsInMemoryFileDB {
|
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Checks if an existing file DB should be migrated to JSONL
|
|
106
|
+
* @returns {Promise<boolean>} true if the file DB was migrated. false if not.
|
|
107
|
+
* If this returns true, the jsonl DB was opened and doesn't need to be opened again.
|
|
108
|
+
*/
|
|
109
|
+
async _maybeMigrateFileDB() {
|
|
110
|
+
const jsonlFileName = path.join(this.dataDir, this.settings.jsonlDB.fileName);
|
|
111
|
+
const jsonFileName = path.join(this.dataDir, this.settings.fileDB.fileName);
|
|
112
|
+
const bakFileName = path.join(this.dataDir, this.settings.fileDB.fileName + '.bak');
|
|
113
|
+
|
|
114
|
+
// Check the timestamps of each file, defaulting to 0 if they don't exist
|
|
115
|
+
let jsonlTimeStamp = 0;
|
|
116
|
+
let jsonTimeStamp = 0;
|
|
117
|
+
let bakTimeStamp = 0;
|
|
118
|
+
try {
|
|
119
|
+
const stat = fs.statSync(jsonlFileName);
|
|
120
|
+
if (stat.isFile()) {
|
|
121
|
+
jsonlTimeStamp = stat.mtime;
|
|
122
|
+
}
|
|
123
|
+
} catch {
|
|
124
|
+
// ignore
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const stat = fs.statSync(jsonFileName);
|
|
128
|
+
if (stat.isFile()) {
|
|
129
|
+
jsonTimeStamp = stat.mtime;
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
// ignore
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const stat = fs.statSync(bakFileName);
|
|
136
|
+
if (stat.isFile()) {
|
|
137
|
+
bakTimeStamp = stat.mtime;
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
// ignore
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Figure out which file needs to be imported
|
|
144
|
+
/** @type {string} */
|
|
145
|
+
let importFilename;
|
|
146
|
+
if (jsonTimeStamp > 0 && jsonTimeStamp >= bakTimeStamp && jsonTimeStamp >= jsonlTimeStamp) {
|
|
147
|
+
importFilename = jsonFileName;
|
|
148
|
+
} else if (bakTimeStamp > 0 && bakTimeStamp >= jsonTimeStamp && bakTimeStamp >= jsonlTimeStamp) {
|
|
149
|
+
importFilename = bakFileName;
|
|
150
|
+
} else {
|
|
151
|
+
// None of the File DB files are newer than the JSONL file
|
|
152
|
+
// There is nothing to restore, we're done
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
await this._db.open();
|
|
157
|
+
this._db.clear();
|
|
158
|
+
await this._db.importJson(importFilename);
|
|
159
|
+
|
|
160
|
+
// And rename the existing files to avoid redoing the work next time
|
|
161
|
+
if (fs.existsSync(jsonFileName)) {
|
|
162
|
+
try {
|
|
163
|
+
fs.renameSync(jsonFileName, `${jsonFileName}.migrated`);
|
|
164
|
+
} catch {
|
|
165
|
+
// ignore
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (fs.existsSync(bakFileName)) {
|
|
169
|
+
try {
|
|
170
|
+
fs.renameSync(bakFileName, `${bakFileName}.migrated`);
|
|
171
|
+
} catch {
|
|
172
|
+
// ignore
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Signal to the caller that the DB is already open
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
102
180
|
async saveState() {
|
|
103
181
|
// Nothing to do, the DB saves behind the scenes
|
|
104
182
|
}
|
|
@@ -106,10 +184,10 @@ class ObjectsInMemoryJsonlDB extends ObjectsInMemoryFileDB {
|
|
|
106
184
|
// Is regularly called and stores a compressed backup of the DB
|
|
107
185
|
async saveBackup() {
|
|
108
186
|
const now = Date.now();
|
|
109
|
-
const tmpBackupFileName = path.join(os.tmpdir(), this.getTimeStr(now)
|
|
187
|
+
const tmpBackupFileName = path.join(os.tmpdir(), `${this.getTimeStr(now)}_${this.settings.jsonlDB.fileName}`);
|
|
110
188
|
const backupFileName = path.join(
|
|
111
189
|
this.backupDir,
|
|
112
|
-
this.getTimeStr(now)
|
|
190
|
+
`${this.getTimeStr(now)}_${this.settings.jsonlDB.fileName}.gz`
|
|
113
191
|
);
|
|
114
192
|
try {
|
|
115
193
|
if (fs.existsSync(backupFileName)) {
|
|
@@ -294,11 +294,22 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
294
294
|
);
|
|
295
295
|
}
|
|
296
296
|
handler.sendBulk(responseId, scriptChecksum);
|
|
297
|
+
} else if (data[1].includes('-- REDLOCK SCRIPT')) {
|
|
298
|
+
// redlock scripts are currently not needed for Simulator
|
|
299
|
+
this.knownScripts[scriptChecksum] = { redlock: true };
|
|
300
|
+
if (this.settings.connection.enhancedLogging) {
|
|
301
|
+
this.log.silly(
|
|
302
|
+
`${namespaceLog} Register Func LUA Script: ${scriptChecksum} = ${JSON.stringify(
|
|
303
|
+
this.knownScripts[scriptChecksum]
|
|
304
|
+
)}`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
handler.sendBulk(responseId, scriptChecksum);
|
|
297
308
|
} else {
|
|
298
|
-
handler.sendError(responseId, new Error(
|
|
309
|
+
handler.sendError(responseId, new Error(`Unknown LUA script ${data[1]}`));
|
|
299
310
|
}
|
|
300
311
|
} else {
|
|
301
|
-
handler.sendError(responseId, new Error(
|
|
312
|
+
handler.sendError(responseId, new Error(`Unsupported Script command ${data[0]}`));
|
|
302
313
|
}
|
|
303
314
|
});
|
|
304
315
|
|
|
@@ -353,8 +364,11 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
353
364
|
const res = objs.rows.map(obj => JSON.stringify(this.dataset[obj.value._id || obj.id]));
|
|
354
365
|
|
|
355
366
|
return void handler.sendArray(responseId, res);
|
|
367
|
+
} else if (this.knownScripts[data[0]].redlock) {
|
|
368
|
+
// just return a dummy
|
|
369
|
+
return void handler.sendArray(responseId, [0]);
|
|
356
370
|
} else {
|
|
357
|
-
handler.sendError(responseId, new Error(
|
|
371
|
+
handler.sendError(responseId, new Error(`Unknown LUA script eval call ${JSON.stringify(data)}`));
|
|
358
372
|
}
|
|
359
373
|
});
|
|
360
374
|
|
|
@@ -521,11 +535,17 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
521
535
|
handler.sendBufBulk(responseId, Buffer.from(fileData));
|
|
522
536
|
}
|
|
523
537
|
} else if (namespace === this.metaNamespace) {
|
|
524
|
-
|
|
525
|
-
if (
|
|
526
|
-
|
|
538
|
+
// special handling for the primaryHost
|
|
539
|
+
if (id === 'objects.primaryHost') {
|
|
540
|
+
// we are the server -> we are primary
|
|
541
|
+
handler.sendString(this.settings.hostname);
|
|
527
542
|
} else {
|
|
528
|
-
|
|
543
|
+
const result = this.getMeta(id);
|
|
544
|
+
if (result === undefined || result === null) {
|
|
545
|
+
handler.sendNull(responseId);
|
|
546
|
+
} else {
|
|
547
|
+
handler.sendBulk(responseId, result);
|
|
548
|
+
}
|
|
529
549
|
}
|
|
530
550
|
} else {
|
|
531
551
|
handler.sendError(
|
|
@@ -710,15 +730,6 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
710
730
|
return this._handleScanOrKeys(handler, data[0], responseId);
|
|
711
731
|
});
|
|
712
732
|
|
|
713
|
-
// MULTI/EXEC is never used with return values, thus we just answer with syntactic correct responses
|
|
714
|
-
handler.on('multi', (data, responseId) => {
|
|
715
|
-
return void handler.sendString(responseId, 'OK');
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
handler.on('exec', (data, reponseId) => {
|
|
719
|
-
return void handler.sendArray(reponseId, []);
|
|
720
|
-
});
|
|
721
|
-
|
|
722
733
|
// commands for redis SETS, just dummies
|
|
723
734
|
handler.on('sadd', (data, responseId) => {
|
|
724
735
|
return void handler.sendInteger(responseId, 1);
|
|
@@ -770,9 +781,22 @@ class ObjectsInMemoryServer extends ObjectsInMemoryJsonlDB {
|
|
|
770
781
|
}
|
|
771
782
|
});
|
|
772
783
|
|
|
784
|
+
// Handle Redis "SUBSCRIBE" ... currently mainly ignored
|
|
785
|
+
handler.on('subscribe', (data, responseId) => {
|
|
786
|
+
if (data[0].startsWith('__keyevent@')) {
|
|
787
|
+
// we ignore these type of events because we publish expires anyway directly
|
|
788
|
+
handler.sendArray(responseId, ['subscribe', data[0], 1]);
|
|
789
|
+
} else {
|
|
790
|
+
handler.sendError(responseId, new Error(`SUBSCRIBE-UNSUPPORTED for ${data[0]}`));
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
|
|
773
794
|
// Handle Redis "CONFIG" ... currently mainly ignored
|
|
774
795
|
handler.on('config', (data, responseId) => {
|
|
775
|
-
if (data[0] === 'set' && data[1] === '
|
|
796
|
+
if (data[0] === 'set' && data[1] === 'notify-keyspace-events') {
|
|
797
|
+
// we ignore these type of commands for now, should only be to subscribe to keyspace events
|
|
798
|
+
handler.sendString(responseId, 'OK');
|
|
799
|
+
} else if (data[0] === 'set' && data[1] === 'lua-time-limit') {
|
|
776
800
|
// we ignore these type of commands for now, irrelevant
|
|
777
801
|
handler.sendString(responseId, 'OK');
|
|
778
802
|
} else {
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iobroker/db-objects-jsonl",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.49-20220121-e7aa4308",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=12.0.0"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@alcalzone/jsonl-db": "~2.4.1",
|
|
9
|
-
"@iobroker/db-base": "4.0.0-alpha.
|
|
10
|
-
"@iobroker/db-objects-file": "4.0.0-alpha.
|
|
11
|
-
"@iobroker/db-objects-redis": "4.0.0-alpha.
|
|
9
|
+
"@iobroker/db-base": "4.0.0-alpha.49-20220121-e7aa4308",
|
|
10
|
+
"@iobroker/db-objects-file": "4.0.0-alpha.49-20220121-e7aa4308",
|
|
11
|
+
"@iobroker/db-objects-redis": "4.0.0-alpha.49-20220121-e7aa4308",
|
|
12
12
|
"deep-clone": "^3.0.3",
|
|
13
13
|
"fs-extra": "^10.0.0"
|
|
14
14
|
},
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"lib/",
|
|
38
38
|
"index.js"
|
|
39
39
|
],
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "f42f117b74d3c4bfac0bc872c087d382ca897b7c"
|
|
41
41
|
}
|