waengine 1.7.3 → 1.7.4
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/CHANGELOG.md +29 -0
- package/README.md +34 -3
- package/package.json +3 -2
- package/src/ab-testing.js +698 -0
- package/src/advanced-scheduler.js +577 -0
- package/src/ai-features.js +459 -0
- package/src/ai-integration.js +2 -1
- package/src/analytics-manager.js +458 -0
- package/src/business-manager.js +362 -0
- package/src/client.js +447 -39
- package/src/console-logger.js +256 -0
- package/src/core.js +28 -3
- package/src/cross-platform.js +538 -0
- package/src/database-manager.js +766 -0
- package/src/device-manager.js +1 -1
- package/src/easy-bot-fixed.js +341 -0
- package/src/easy-bot.js +503 -22
- package/src/error-handler.js +230 -0
- package/src/gaming-manager.js +842 -0
- package/src/http-client.js +1 -1
- package/src/index.js +15 -0
- package/src/message.js +197 -94
- package/src/multi-client.js +26 -12
- package/src/plugin-manager.js +59 -10
- package/src/prefix-manager.js +48 -1
- package/src/qr-terminal-fix.js +239 -0
- package/src/qr.js +170 -27
- package/src/quick-bot.js +63 -0
- package/src/reporting-manager.js +867 -0
- package/src/scheduler.js +14 -1
- package/src/security-manager.js +678 -0
- package/src/session-manager-old.js +314 -0
- package/src/session-manager.js +429 -24
- package/src/storage.js +254 -194
- package/src/ui-components.js +560 -0
package/src/storage.js
CHANGED
|
@@ -8,7 +8,7 @@ export class WAStorage {
|
|
|
8
8
|
this.cache = new Map();
|
|
9
9
|
this.ensureBaseDir();
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
// Schöne Console ist jetzt Standard - keine Logs mehr hier
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// ===== SETUP =====
|
|
@@ -21,11 +21,33 @@ export class WAStorage {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
getFilePath(fileName) {
|
|
24
|
+
// Sicherheitsvalidierung gegen Path Traversal
|
|
25
|
+
if (!fileName || typeof fileName !== 'string') {
|
|
26
|
+
throw new Error('❌ Ungültiger Dateiname');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Entferne gefährliche Zeichen und Pfad-Traversal-Versuche
|
|
30
|
+
let sanitizedFileName = fileName
|
|
31
|
+
.replace(/\.\./g, '') // Entferne ../
|
|
32
|
+
.replace(/[<>:"|?*]/g, '') // Entferne Windows-ungültige Zeichen
|
|
33
|
+
.replace(/^\/+/, '') // Entferne führende Slashes
|
|
34
|
+
.trim();
|
|
35
|
+
|
|
36
|
+
if (!sanitizedFileName) {
|
|
37
|
+
throw new Error('❌ Dateiname ist nach Bereinigung leer');
|
|
38
|
+
}
|
|
39
|
+
|
|
24
40
|
// Automatisch .json hinzufügen falls nicht vorhanden
|
|
25
|
-
if (!
|
|
26
|
-
|
|
41
|
+
if (!sanitizedFileName.endsWith('.json')) {
|
|
42
|
+
sanitizedFileName += '.json';
|
|
27
43
|
}
|
|
28
|
-
|
|
44
|
+
|
|
45
|
+
// Prüfe ob Dateiname zu lang ist (Windows: 255 Zeichen)
|
|
46
|
+
if (sanitizedFileName.length > 200) {
|
|
47
|
+
throw new Error('❌ Dateiname zu lang');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return path.join(this.baseDir, sanitizedFileName);
|
|
29
51
|
}
|
|
30
52
|
|
|
31
53
|
// ===== WRITE SYSTEM =====
|
|
@@ -49,14 +71,9 @@ export class WAStorage {
|
|
|
49
71
|
return this.setKey(fileName, key, value);
|
|
50
72
|
},
|
|
51
73
|
|
|
52
|
-
// write.in("datei").push(
|
|
53
|
-
push: (
|
|
54
|
-
return this.
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
// write.in("datei").increment(key, amount)
|
|
58
|
-
increment: (key, amount = 1) => {
|
|
59
|
-
return this.incrementKey(fileName, key, amount);
|
|
74
|
+
// write.in("datei").push(item)
|
|
75
|
+
push: (item) => {
|
|
76
|
+
return this.pushItem(fileName, item);
|
|
60
77
|
}
|
|
61
78
|
};
|
|
62
79
|
}
|
|
@@ -65,7 +82,7 @@ export class WAStorage {
|
|
|
65
82
|
// ===== READ SYSTEM =====
|
|
66
83
|
|
|
67
84
|
read = {
|
|
68
|
-
// read.from("datei")
|
|
85
|
+
// read.from("datei") - Liest Daten aus Datei
|
|
69
86
|
from: (fileName) => {
|
|
70
87
|
return {
|
|
71
88
|
// read.from("datei").all()
|
|
@@ -78,33 +95,24 @@ export class WAStorage {
|
|
|
78
95
|
return this.getKey(fileName, key);
|
|
79
96
|
},
|
|
80
97
|
|
|
81
|
-
// read.from("datei").
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return data ? Object.keys(data) : [];
|
|
98
|
+
// read.from("datei").find(condition)
|
|
99
|
+
find: (condition) => {
|
|
100
|
+
return this.findItem(fileName, condition);
|
|
85
101
|
},
|
|
86
102
|
|
|
87
|
-
// read.from("datei").
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return data ? Object.values(data) : [];
|
|
103
|
+
// read.from("datei").filter(condition)
|
|
104
|
+
filter: (condition) => {
|
|
105
|
+
return this.filterItems(fileName, condition);
|
|
91
106
|
},
|
|
92
107
|
|
|
93
|
-
// read.from("datei").
|
|
94
|
-
|
|
108
|
+
// read.from("datei").count()
|
|
109
|
+
count: () => {
|
|
95
110
|
const data = this.readData(fileName);
|
|
96
|
-
return Array.isArray(data) ? data.length : 0;
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
// read.from("datei").exists()
|
|
100
|
-
exists: () => {
|
|
101
|
-
return this.fileExists(fileName);
|
|
111
|
+
return Array.isArray(data) ? data.length : (data ? Object.keys(data).length : 0);
|
|
102
112
|
}
|
|
103
113
|
};
|
|
104
114
|
}
|
|
105
115
|
};
|
|
106
|
-
|
|
107
|
-
// ===== DELETE SYSTEM =====
|
|
108
116
|
|
|
109
117
|
delete = {
|
|
110
118
|
// delete.from("datei")
|
|
@@ -133,12 +141,39 @@ export class WAStorage {
|
|
|
133
141
|
writeData(fileName, data) {
|
|
134
142
|
try {
|
|
135
143
|
const filePath = this.getFilePath(fileName);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
144
|
+
|
|
145
|
+
// Validiere Daten
|
|
146
|
+
if (data === undefined) {
|
|
147
|
+
throw new Error('Daten sind undefined');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Atomare Schreibung: Erst in temporäre Datei, dann umbenennen
|
|
151
|
+
const tempFilePath = `${filePath}.tmp`;
|
|
152
|
+
const jsonData = JSON.stringify(data, null, 2);
|
|
153
|
+
|
|
154
|
+
// Schreibe in temporäre Datei
|
|
155
|
+
fs.writeFileSync(tempFilePath, jsonData);
|
|
156
|
+
|
|
157
|
+
// Atomare Umbenennung (verhindert korrupte Dateien)
|
|
158
|
+
fs.renameSync(tempFilePath, filePath);
|
|
159
|
+
|
|
160
|
+
// Cache mit Größenlimit aktualisieren
|
|
161
|
+
this.updateCache(fileName, data);
|
|
162
|
+
|
|
139
163
|
return true;
|
|
140
164
|
} catch (error) {
|
|
141
165
|
console.error(`❌ Fehler beim Schreiben in ${fileName}:`, error);
|
|
166
|
+
|
|
167
|
+
// Cleanup temporäre Datei
|
|
168
|
+
try {
|
|
169
|
+
const tempFilePath = `${this.getFilePath(fileName)}.tmp`;
|
|
170
|
+
if (fs.existsSync(tempFilePath)) {
|
|
171
|
+
fs.unlinkSync(tempFilePath);
|
|
172
|
+
}
|
|
173
|
+
} catch (cleanupError) {
|
|
174
|
+
// Stille Behandlung
|
|
175
|
+
}
|
|
176
|
+
|
|
142
177
|
return false;
|
|
143
178
|
}
|
|
144
179
|
}
|
|
@@ -156,11 +191,72 @@ export class WAStorage {
|
|
|
156
191
|
return null;
|
|
157
192
|
}
|
|
158
193
|
|
|
159
|
-
|
|
160
|
-
|
|
194
|
+
// Robuste JSON-Lesung mit Validierung
|
|
195
|
+
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
196
|
+
|
|
197
|
+
// Prüfe auf leere oder zu kurze Dateien
|
|
198
|
+
if (!fileContent || fileContent.trim().length < 2) {
|
|
199
|
+
console.warn(`⚠️ Datei ${fileName} ist leer oder zu kurz`);
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Prüfe auf unvollständige JSON
|
|
204
|
+
const trimmed = fileContent.trim();
|
|
205
|
+
if (!((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
|
|
206
|
+
(trimmed.startsWith('[') && trimmed.endsWith(']')))) {
|
|
207
|
+
console.warn(`⚠️ Datei ${fileName} hat ungültiges JSON-Format`);
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const data = JSON.parse(fileContent);
|
|
212
|
+
|
|
213
|
+
// Cache mit Größenlimit aktualisieren
|
|
214
|
+
this.updateCache(fileName, data);
|
|
215
|
+
|
|
161
216
|
return data;
|
|
162
217
|
} catch (error) {
|
|
163
|
-
console.error(`❌ Fehler beim Lesen von ${fileName}:`, error);
|
|
218
|
+
console.error(`❌ Fehler beim Lesen von ${fileName}:`, error.message);
|
|
219
|
+
|
|
220
|
+
// Versuche Backup-Recovery
|
|
221
|
+
const backupData = this.tryRecoverFromBackup(fileName);
|
|
222
|
+
if (backupData) {
|
|
223
|
+
console.log(`✅ ${fileName} aus Backup wiederhergestellt`);
|
|
224
|
+
return backupData;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Cache-Management mit Größenlimit
|
|
232
|
+
updateCache(fileName, data) {
|
|
233
|
+
// Begrenze Cache-Größe auf 100 Einträge
|
|
234
|
+
if (this.cache.size >= 100) {
|
|
235
|
+
// Entferne älteste Einträge (FIFO)
|
|
236
|
+
const firstKey = this.cache.keys().next().value;
|
|
237
|
+
this.cache.delete(firstKey);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this.cache.set(fileName, data);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Backup-Recovery für korrupte Dateien
|
|
244
|
+
tryRecoverFromBackup(fileName) {
|
|
245
|
+
try {
|
|
246
|
+
const filePath = this.getFilePath(fileName);
|
|
247
|
+
const backupPath = `${filePath}.backup`;
|
|
248
|
+
|
|
249
|
+
if (fs.existsSync(backupPath)) {
|
|
250
|
+
const backupContent = fs.readFileSync(backupPath, 'utf8');
|
|
251
|
+
const backupData = JSON.parse(backupContent);
|
|
252
|
+
|
|
253
|
+
// Backup ist gültig - stelle wieder her
|
|
254
|
+
fs.copyFileSync(backupPath, filePath);
|
|
255
|
+
return backupData;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return null;
|
|
259
|
+
} catch (error) {
|
|
164
260
|
return null;
|
|
165
261
|
}
|
|
166
262
|
}
|
|
@@ -170,34 +266,29 @@ export class WAStorage {
|
|
|
170
266
|
|
|
171
267
|
if (Array.isArray(existingData)) {
|
|
172
268
|
existingData.push(newData);
|
|
269
|
+
return this.writeData(fileName, existingData);
|
|
173
270
|
} else {
|
|
174
|
-
//
|
|
175
|
-
|
|
271
|
+
// Für Objekte: Merge
|
|
272
|
+
const merged = { ...existingData, ...newData };
|
|
273
|
+
return this.writeData(fileName, merged);
|
|
176
274
|
}
|
|
177
|
-
|
|
178
|
-
return this.writeData(fileName, existingData);
|
|
179
275
|
}
|
|
180
276
|
|
|
181
277
|
setKey(fileName, key, value) {
|
|
182
|
-
|
|
278
|
+
const data = this.readData(fileName) || {};
|
|
183
279
|
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
current[keys[i]] = {};
|
|
192
|
-
}
|
|
193
|
-
current = current[keys[i]];
|
|
280
|
+
// Unterstütze nested keys mit Punkt-Notation (z.B. "user.name")
|
|
281
|
+
const keys = key.split('.');
|
|
282
|
+
let current = data;
|
|
283
|
+
|
|
284
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
285
|
+
if (!current[keys[i]] || typeof current[keys[i]] !== 'object') {
|
|
286
|
+
current[keys[i]] = {};
|
|
194
287
|
}
|
|
195
|
-
|
|
196
|
-
current[keys[keys.length - 1]] = value;
|
|
197
|
-
} else {
|
|
198
|
-
data[key] = value;
|
|
288
|
+
current = current[keys[i]];
|
|
199
289
|
}
|
|
200
290
|
|
|
291
|
+
current[keys[keys.length - 1]] = value;
|
|
201
292
|
return this.writeData(fileName, data);
|
|
202
293
|
}
|
|
203
294
|
|
|
@@ -205,42 +296,44 @@ export class WAStorage {
|
|
|
205
296
|
const data = this.readData(fileName);
|
|
206
297
|
if (!data) return null;
|
|
207
298
|
|
|
208
|
-
//
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
current = current[k];
|
|
299
|
+
// Unterstütze nested keys mit Punkt-Notation
|
|
300
|
+
const keys = key.split('.');
|
|
301
|
+
let current = data;
|
|
302
|
+
|
|
303
|
+
for (const k of keys) {
|
|
304
|
+
if (current === null || current === undefined || typeof current !== 'object') {
|
|
305
|
+
return null;
|
|
218
306
|
}
|
|
219
|
-
|
|
220
|
-
return current;
|
|
307
|
+
current = current[k];
|
|
221
308
|
}
|
|
222
309
|
|
|
223
|
-
return
|
|
310
|
+
return current;
|
|
224
311
|
}
|
|
225
312
|
|
|
226
|
-
|
|
227
|
-
|
|
313
|
+
pushItem(fileName, item) {
|
|
314
|
+
const data = this.readData(fileName) || [];
|
|
228
315
|
|
|
229
|
-
if (!data) {
|
|
230
|
-
|
|
231
|
-
} else if (!Array.isArray(data)) {
|
|
232
|
-
console.error(`❌ ${fileName} ist kein Array!`);
|
|
316
|
+
if (!Array.isArray(data)) {
|
|
317
|
+
console.error(`❌ ${fileName} ist kein Array - kann nicht pushen`);
|
|
233
318
|
return false;
|
|
234
319
|
}
|
|
235
320
|
|
|
236
|
-
data.push(
|
|
321
|
+
data.push(item);
|
|
237
322
|
return this.writeData(fileName, data);
|
|
238
323
|
}
|
|
239
324
|
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
325
|
+
findItem(fileName, condition) {
|
|
326
|
+
const data = this.readData(fileName);
|
|
327
|
+
if (!Array.isArray(data)) return null;
|
|
328
|
+
|
|
329
|
+
return data.find(condition);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
filterItems(fileName, condition) {
|
|
333
|
+
const data = this.readData(fileName);
|
|
334
|
+
if (!Array.isArray(data)) return [];
|
|
335
|
+
|
|
336
|
+
return data.filter(condition);
|
|
244
337
|
}
|
|
245
338
|
|
|
246
339
|
deleteFile(fileName) {
|
|
@@ -249,12 +342,10 @@ export class WAStorage {
|
|
|
249
342
|
|
|
250
343
|
if (fs.existsSync(filePath)) {
|
|
251
344
|
fs.unlinkSync(filePath);
|
|
252
|
-
this.cache.delete(fileName);
|
|
253
|
-
// Stille Löschung
|
|
254
|
-
return true;
|
|
255
345
|
}
|
|
256
346
|
|
|
257
|
-
|
|
347
|
+
this.cache.delete(fileName);
|
|
348
|
+
return true;
|
|
258
349
|
} catch (error) {
|
|
259
350
|
console.error(`❌ Fehler beim Löschen von ${fileName}:`, error);
|
|
260
351
|
return false;
|
|
@@ -262,141 +353,102 @@ export class WAStorage {
|
|
|
262
353
|
}
|
|
263
354
|
|
|
264
355
|
deleteKey(fileName, key) {
|
|
265
|
-
|
|
356
|
+
const data = this.readData(fileName);
|
|
266
357
|
if (!data) return false;
|
|
267
358
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
current = current[keys[i]];
|
|
359
|
+
// Unterstütze nested keys
|
|
360
|
+
const keys = key.split('.');
|
|
361
|
+
let current = data;
|
|
362
|
+
|
|
363
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
364
|
+
if (!current[keys[i]] || typeof current[keys[i]] !== 'object') {
|
|
365
|
+
return false; // Key existiert nicht
|
|
278
366
|
}
|
|
279
|
-
|
|
280
|
-
delete current[keys[keys.length - 1]];
|
|
281
|
-
} else {
|
|
282
|
-
delete data[key];
|
|
367
|
+
current = current[keys[i]];
|
|
283
368
|
}
|
|
284
369
|
|
|
370
|
+
delete current[keys[keys.length - 1]];
|
|
285
371
|
return this.writeData(fileName, data);
|
|
286
372
|
}
|
|
287
373
|
|
|
288
374
|
deleteWhere(fileName, condition) {
|
|
289
|
-
|
|
290
|
-
if (!data) return false;
|
|
291
|
-
|
|
292
|
-
if (Array.isArray(data)) {
|
|
293
|
-
// Array filtern
|
|
294
|
-
const originalLength = data.length;
|
|
295
|
-
data = data.filter(item => !condition(item));
|
|
296
|
-
|
|
297
|
-
if (data.length !== originalLength) {
|
|
298
|
-
return this.writeData(fileName, data);
|
|
299
|
-
}
|
|
300
|
-
} else {
|
|
301
|
-
// Object filtern
|
|
302
|
-
let changed = false;
|
|
303
|
-
|
|
304
|
-
for (const [key, value] of Object.entries(data)) {
|
|
305
|
-
if (condition(value, key)) {
|
|
306
|
-
delete data[key];
|
|
307
|
-
changed = true;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (changed) {
|
|
312
|
-
return this.writeData(fileName, data);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
375
|
+
const data = this.readData(fileName);
|
|
376
|
+
if (!Array.isArray(data)) return false;
|
|
315
377
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
fileExists(fileName) {
|
|
320
|
-
const filePath = this.getFilePath(fileName);
|
|
321
|
-
return fs.existsSync(filePath);
|
|
378
|
+
const filteredData = data.filter(item => !condition(item));
|
|
379
|
+
return this.writeData(fileName, filteredData);
|
|
322
380
|
}
|
|
323
381
|
|
|
324
382
|
// ===== UTILITY METHODS =====
|
|
325
383
|
|
|
326
|
-
|
|
327
|
-
listFiles() {
|
|
384
|
+
exists(fileName) {
|
|
328
385
|
try {
|
|
329
|
-
const
|
|
330
|
-
return
|
|
386
|
+
const filePath = this.getFilePath(fileName);
|
|
387
|
+
return fs.existsSync(filePath);
|
|
331
388
|
} catch (error) {
|
|
332
|
-
|
|
333
|
-
return [];
|
|
389
|
+
return false;
|
|
334
390
|
}
|
|
335
391
|
}
|
|
336
392
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
393
|
+
size(fileName) {
|
|
394
|
+
try {
|
|
395
|
+
const filePath = this.getFilePath(fileName);
|
|
396
|
+
if (fs.existsSync(filePath)) {
|
|
397
|
+
return fs.statSync(filePath).size;
|
|
398
|
+
}
|
|
399
|
+
return 0;
|
|
400
|
+
} catch (error) {
|
|
401
|
+
return 0;
|
|
402
|
+
}
|
|
341
403
|
}
|
|
342
404
|
|
|
343
|
-
|
|
344
|
-
backup(backupDir = './waengine-backup') {
|
|
405
|
+
backup(fileName) {
|
|
345
406
|
try {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const files = fs.readdirSync(this.baseDir);
|
|
351
|
-
let backedUp = 0;
|
|
407
|
+
const filePath = this.getFilePath(fileName);
|
|
408
|
+
const backupPath = `${filePath}.backup`;
|
|
352
409
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
fs.copyFileSync(srcPath, destPath);
|
|
357
|
-
backedUp++;
|
|
410
|
+
if (fs.existsSync(filePath)) {
|
|
411
|
+
fs.copyFileSync(filePath, backupPath);
|
|
412
|
+
return true;
|
|
358
413
|
}
|
|
359
|
-
|
|
360
|
-
// Nur bei explizitem Backup eine Meldung
|
|
361
|
-
console.log(`💾 Backup erstellt: ${backedUp} Dateien in ${backupDir}`);
|
|
362
|
-
return backupDir;
|
|
414
|
+
return false;
|
|
363
415
|
} catch (error) {
|
|
364
|
-
console.error(
|
|
416
|
+
console.error(`❌ Backup-Fehler für ${fileName}:`, error);
|
|
365
417
|
return false;
|
|
366
418
|
}
|
|
367
419
|
}
|
|
368
420
|
|
|
369
|
-
//
|
|
421
|
+
// Bereinige Cache
|
|
422
|
+
clearCache() {
|
|
423
|
+
this.cache.clear();
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Storage-Statistiken
|
|
370
427
|
getStats() {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
totalSize += stats.size;
|
|
379
|
-
} catch (error) {
|
|
380
|
-
// Ignore
|
|
428
|
+
try {
|
|
429
|
+
const files = fs.readdirSync(this.baseDir);
|
|
430
|
+
const jsonFiles = files.filter(f => f.endsWith('.json'));
|
|
431
|
+
|
|
432
|
+
let totalSize = 0;
|
|
433
|
+
for (const file of jsonFiles) {
|
|
434
|
+
totalSize += this.size(file.replace('.json', ''));
|
|
381
435
|
}
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
totalFiles: jsonFiles.length,
|
|
439
|
+
totalSize: totalSize,
|
|
440
|
+
cacheSize: this.cache.size,
|
|
441
|
+
baseDir: this.baseDir
|
|
442
|
+
};
|
|
443
|
+
} catch (error) {
|
|
444
|
+
return {
|
|
445
|
+
totalFiles: 0,
|
|
446
|
+
totalSize: 0,
|
|
447
|
+
cacheSize: this.cache.size,
|
|
448
|
+
baseDir: this.baseDir,
|
|
449
|
+
error: error.message
|
|
450
|
+
};
|
|
382
451
|
}
|
|
383
|
-
|
|
384
|
-
return {
|
|
385
|
-
totalFiles: files.length,
|
|
386
|
-
totalSize: totalSize,
|
|
387
|
-
totalSizeFormatted: this.formatBytes(totalSize),
|
|
388
|
-
cacheSize: this.cache.size,
|
|
389
|
-
baseDir: this.baseDir,
|
|
390
|
-
files: files
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
formatBytes(bytes) {
|
|
395
|
-
if (bytes === 0) return '0 Bytes';
|
|
396
|
-
const k = 1024;
|
|
397
|
-
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
398
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
399
|
-
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
400
452
|
}
|
|
401
453
|
}
|
|
402
454
|
|
|
@@ -404,19 +456,27 @@ export class WAStorage {
|
|
|
404
456
|
|
|
405
457
|
let globalStorage = null;
|
|
406
458
|
|
|
407
|
-
export function createStorage(baseDir) {
|
|
459
|
+
export function createStorage(baseDir = './waengine-data') {
|
|
408
460
|
return new WAStorage(baseDir);
|
|
409
461
|
}
|
|
410
462
|
|
|
411
|
-
export function getStorage() {
|
|
463
|
+
export function getStorage(baseDir = './waengine-data') {
|
|
412
464
|
if (!globalStorage) {
|
|
413
|
-
globalStorage = new WAStorage();
|
|
465
|
+
globalStorage = new WAStorage(baseDir);
|
|
414
466
|
}
|
|
415
467
|
return globalStorage;
|
|
416
468
|
}
|
|
417
469
|
|
|
418
|
-
// =====
|
|
470
|
+
// ===== CONVENIENCE EXPORTS =====
|
|
471
|
+
|
|
472
|
+
export const write = {
|
|
473
|
+
in: (fileName) => getStorage().write.in(fileName)
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
export const read = {
|
|
477
|
+
from: (fileName) => getStorage().read.from(fileName)
|
|
478
|
+
};
|
|
419
479
|
|
|
420
|
-
export const
|
|
421
|
-
|
|
422
|
-
|
|
480
|
+
export const del = {
|
|
481
|
+
from: (fileName) => getStorage().delete.from(fileName)
|
|
482
|
+
};
|