aicodeswitch 2.1.6 → 3.0.2

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.
@@ -0,0 +1,1752 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ var __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.FileSystemDatabaseManager = void 0;
27
+ const path_1 = __importDefault(require("path"));
28
+ const promises_1 = __importDefault(require("fs/promises"));
29
+ const crypto_1 = __importDefault(require("crypto"));
30
+ const crypto_js_1 = __importDefault(require("crypto-js"));
31
+ /**
32
+ * 基于文件系统的数据库管理器
33
+ * 使用 JSON 文件存储数据,无需编译依赖
34
+ */
35
+ class FileSystemDatabaseManager {
36
+ // 文件路径
37
+ get vendorsFile() { return path_1.default.join(this.dataPath, 'vendors.json'); }
38
+ get servicesFile() { return path_1.default.join(this.dataPath, 'services.json'); }
39
+ get routesFile() { return path_1.default.join(this.dataPath, 'routes.json'); }
40
+ get rulesFile() { return path_1.default.join(this.dataPath, 'rules.json'); } // legacy
41
+ get configFile() { return path_1.default.join(this.dataPath, 'config.json'); }
42
+ get sessionsFile() { return path_1.default.join(this.dataPath, 'sessions.json'); }
43
+ get logsDir() { return path_1.default.join(this.dataPath, 'logs'); }
44
+ get logsIndexFile() { return path_1.default.join(this.dataPath, 'logs-index.json'); }
45
+ get errorLogsFile() { return path_1.default.join(this.dataPath, 'error-logs.json'); }
46
+ get blacklistFile() { return path_1.default.join(this.dataPath, 'blacklist.json'); }
47
+ get statisticsFile() { return path_1.default.join(this.dataPath, 'statistics.json'); }
48
+ // 创建空的统计数据结构
49
+ createEmptyStatistics() {
50
+ return {
51
+ overview: {
52
+ totalRequests: 0,
53
+ totalTokens: 0,
54
+ totalInputTokens: 0,
55
+ totalOutputTokens: 0,
56
+ totalCacheReadTokens: 0,
57
+ totalVendors: 0,
58
+ totalServices: 0,
59
+ totalRoutes: 0,
60
+ totalRules: 0,
61
+ avgResponseTime: 0,
62
+ successRate: 100,
63
+ totalCodingTime: 0,
64
+ },
65
+ byTargetType: [],
66
+ byVendor: [],
67
+ byService: [],
68
+ byModel: [],
69
+ timeline: [],
70
+ contentTypeDistribution: [],
71
+ errors: {
72
+ totalErrors: 0,
73
+ recentErrors: 0,
74
+ },
75
+ };
76
+ }
77
+ constructor(dataPath) {
78
+ Object.defineProperty(this, "dataPath", {
79
+ enumerable: true,
80
+ configurable: true,
81
+ writable: true,
82
+ value: void 0
83
+ });
84
+ Object.defineProperty(this, "vendors", {
85
+ enumerable: true,
86
+ configurable: true,
87
+ writable: true,
88
+ value: []
89
+ });
90
+ // 移除独立的 apiServices 存储,现在作为 vendor 的属性
91
+ Object.defineProperty(this, "routes", {
92
+ enumerable: true,
93
+ configurable: true,
94
+ writable: true,
95
+ value: []
96
+ });
97
+ Object.defineProperty(this, "rules", {
98
+ enumerable: true,
99
+ configurable: true,
100
+ writable: true,
101
+ value: []
102
+ });
103
+ Object.defineProperty(this, "config", {
104
+ enumerable: true,
105
+ configurable: true,
106
+ writable: true,
107
+ value: null
108
+ });
109
+ Object.defineProperty(this, "sessions", {
110
+ enumerable: true,
111
+ configurable: true,
112
+ writable: true,
113
+ value: []
114
+ });
115
+ Object.defineProperty(this, "logShardsIndex", {
116
+ enumerable: true,
117
+ configurable: true,
118
+ writable: true,
119
+ value: []
120
+ });
121
+ Object.defineProperty(this, "errorLogs", {
122
+ enumerable: true,
123
+ configurable: true,
124
+ writable: true,
125
+ value: []
126
+ });
127
+ Object.defineProperty(this, "blacklist", {
128
+ enumerable: true,
129
+ configurable: true,
130
+ writable: true,
131
+ value: new Map()
132
+ });
133
+ // 持久化统计数据
134
+ Object.defineProperty(this, "statistics", {
135
+ enumerable: true,
136
+ configurable: true,
137
+ writable: true,
138
+ value: this.createEmptyStatistics()
139
+ });
140
+ // 缓存机制
141
+ Object.defineProperty(this, "logsCountCache", {
142
+ enumerable: true,
143
+ configurable: true,
144
+ writable: true,
145
+ value: null
146
+ });
147
+ Object.defineProperty(this, "errorLogsCountCache", {
148
+ enumerable: true,
149
+ configurable: true,
150
+ writable: true,
151
+ value: null
152
+ });
153
+ Object.defineProperty(this, "CACHE_TTL", {
154
+ enumerable: true,
155
+ configurable: true,
156
+ writable: true,
157
+ value: 1000
158
+ });
159
+ // 日志分片配置
160
+ Object.defineProperty(this, "MAX_SHARD_SIZE", {
161
+ enumerable: true,
162
+ configurable: true,
163
+ writable: true,
164
+ value: 10 * 1024 * 1024
165
+ }); // 10MB
166
+ Object.defineProperty(this, "LOG_RETENTION_DAYS", {
167
+ enumerable: true,
168
+ configurable: true,
169
+ writable: true,
170
+ value: 30
171
+ });
172
+ this.dataPath = dataPath;
173
+ }
174
+ initialize() {
175
+ return __awaiter(this, void 0, void 0, function* () {
176
+ // 确保数据目录存在
177
+ yield promises_1.default.mkdir(this.dataPath, { recursive: true });
178
+ // 加载所有数据
179
+ yield this.loadAllData();
180
+ // 确保默认配置
181
+ yield this.ensureDefaultConfig();
182
+ });
183
+ }
184
+ loadAllData() {
185
+ return __awaiter(this, void 0, void 0, function* () {
186
+ yield Promise.all([
187
+ this.loadVendors(), // loadVendors 内部会处理旧 services.json 的迁移
188
+ // 删除: this.loadServices(),
189
+ this.loadRoutes(),
190
+ this.loadConfig(),
191
+ this.loadSessions(),
192
+ this.loadLogsIndex(),
193
+ this.loadErrorLogs(),
194
+ this.loadBlacklist(),
195
+ this.loadStatistics(),
196
+ ]);
197
+ });
198
+ }
199
+ loadVendors() {
200
+ return __awaiter(this, void 0, void 0, function* () {
201
+ try {
202
+ const data = yield promises_1.default.readFile(this.vendorsFile, 'utf-8');
203
+ this.vendors = JSON.parse(data);
204
+ }
205
+ catch (_a) {
206
+ this.vendors = [];
207
+ }
208
+ // 兼容性检查:如果存在旧的 services.json,自动迁移
209
+ yield this.migrateServicesIfNeeded();
210
+ });
211
+ }
212
+ /**
213
+ * 检测并迁移旧的 services.json 到新结构
214
+ * 旧格式:vendors.json 和 services.json 分离
215
+ * 新格式:vendors.json 包含嵌套的 services 数组
216
+ */
217
+ migrateServicesIfNeeded() {
218
+ return __awaiter(this, void 0, void 0, function* () {
219
+ const oldServicesFile = this.servicesFile;
220
+ try {
221
+ yield promises_1.default.access(oldServicesFile);
222
+ console.log('[Database] 发现旧的 services.json 文件,开始迁移到新结构...');
223
+ // 读取旧服务数据
224
+ const servicesData = yield promises_1.default.readFile(oldServicesFile, 'utf-8');
225
+ const oldServices = JSON.parse(servicesData);
226
+ console.log(`[Database] 准备迁移 ${oldServices.length} 个服务...`);
227
+ // 按 vendorId 分组
228
+ const servicesByVendor = new Map();
229
+ for (const service of oldServices) {
230
+ if (!service.vendorId) {
231
+ console.warn(`[Database] 跳过没有 vendorId 的服务: ${service.id}`);
232
+ continue;
233
+ }
234
+ if (!servicesByVendor.has(service.vendorId)) {
235
+ servicesByVendor.set(service.vendorId, []);
236
+ }
237
+ // 移除 vendorId 字段,因为现在通过父级关系隐式关联
238
+ const { vendorId } = service, serviceWithoutVendorId = __rest(service, ["vendorId"]);
239
+ servicesByVendor.get(service.vendorId).push(serviceWithoutVendorId);
240
+ }
241
+ // 合并到 vendors 数组
242
+ let migratedCount = 0;
243
+ for (const vendor of this.vendors) {
244
+ const services = servicesByVendor.get(vendor.id);
245
+ if (services) {
246
+ vendor.services = services;
247
+ migratedCount += services.length;
248
+ }
249
+ else {
250
+ vendor.services = [];
251
+ }
252
+ }
253
+ // 保存新的 vendors.json
254
+ yield this.saveVendors();
255
+ // 备份旧文件
256
+ const timestamp = Date.now();
257
+ const backupFile = path_1.default.join(this.dataPath, `services.json.backup.${timestamp}`);
258
+ yield promises_1.default.rename(oldServicesFile, backupFile);
259
+ console.log(`[Database] 迁移完成:${migratedCount} 个服务已迁移`);
260
+ console.log(`[Database] 旧的 services.json 已备份到 ${backupFile}`);
261
+ }
262
+ catch (err) {
263
+ if (err.code === 'ENOENT') {
264
+ // 旧文件不存在,这是正常的(新安装或已迁移)
265
+ return;
266
+ }
267
+ console.error('[Database] 迁移 services 时出错:', err);
268
+ }
269
+ });
270
+ }
271
+ saveVendors() {
272
+ return __awaiter(this, void 0, void 0, function* () {
273
+ // 确保每个供应商都有 services 数组
274
+ const normalizedVendors = this.vendors.map(v => (Object.assign(Object.assign({}, v), { services: v.services || [] })));
275
+ yield promises_1.default.writeFile(this.vendorsFile, JSON.stringify(normalizedVendors, null, 2));
276
+ });
277
+ }
278
+ // loadServices 和 saveServices 已移除
279
+ // 服务现在作为供应商的属性存储在 vendors.json 中
280
+ // 迁移逻辑见 migrateServicesIfNeeded() 方法
281
+ loadRoutes() {
282
+ return __awaiter(this, void 0, void 0, function* () {
283
+ let routesFileFormat = 'missing';
284
+ let routesFromFile = [];
285
+ let rulesFromFile = [];
286
+ let hasRulesInRoutesFile = false;
287
+ try {
288
+ const data = yield promises_1.default.readFile(this.routesFile, 'utf-8');
289
+ const parsed = JSON.parse(data);
290
+ if (Array.isArray(parsed)) {
291
+ routesFileFormat = 'array';
292
+ routesFromFile = parsed;
293
+ }
294
+ else if (parsed && typeof parsed === 'object') {
295
+ routesFileFormat = 'combined';
296
+ routesFromFile = Array.isArray(parsed.routes) ? parsed.routes : [];
297
+ if (Array.isArray(parsed.rules)) {
298
+ rulesFromFile = parsed.rules;
299
+ hasRulesInRoutesFile = true;
300
+ }
301
+ }
302
+ else {
303
+ routesFileFormat = 'unknown';
304
+ }
305
+ }
306
+ catch (_a) {
307
+ routesFileFormat = 'missing';
308
+ }
309
+ this.routes = routesFromFile;
310
+ this.rules = rulesFromFile;
311
+ // 兼容旧的 rules.json 文件(迁移到 routes.json 的 rules 属性)
312
+ yield this.migrateRulesIfNeeded(routesFileFormat, hasRulesInRoutesFile);
313
+ });
314
+ }
315
+ saveRoutesData() {
316
+ return __awaiter(this, void 0, void 0, function* () {
317
+ const payload = {
318
+ routes: this.routes,
319
+ rules: this.rules,
320
+ };
321
+ yield promises_1.default.writeFile(this.routesFile, JSON.stringify(payload, null, 2));
322
+ });
323
+ }
324
+ saveRoutes() {
325
+ return __awaiter(this, void 0, void 0, function* () {
326
+ yield this.saveRoutesData();
327
+ });
328
+ }
329
+ saveRules() {
330
+ return __awaiter(this, void 0, void 0, function* () {
331
+ yield this.saveRoutesData();
332
+ });
333
+ }
334
+ /**
335
+ * 检测并迁移旧的 rules.json 到 routes.json 的 rules 属性
336
+ * 旧格式:routes.json + rules.json 分离
337
+ * 新格式:routes.json 内包含 { routes, rules }
338
+ */
339
+ migrateRulesIfNeeded(routesFileFormat, hasRulesInRoutesFile) {
340
+ return __awaiter(this, void 0, void 0, function* () {
341
+ const oldRulesFile = this.rulesFile;
342
+ const oldRulesExists = yield promises_1.default.access(oldRulesFile)
343
+ .then(() => true)
344
+ .catch(() => false);
345
+ let merged = false;
346
+ if (oldRulesExists) {
347
+ try {
348
+ const data = yield promises_1.default.readFile(oldRulesFile, 'utf-8');
349
+ const oldRules = JSON.parse(data);
350
+ if (Array.isArray(oldRules)) {
351
+ if (this.rules.length > 0) {
352
+ const mergedMap = new Map();
353
+ oldRules.forEach((rule, index) => {
354
+ const key = (rule === null || rule === void 0 ? void 0 : rule.id) || `legacy-${index}`;
355
+ if (!mergedMap.has(key)) {
356
+ mergedMap.set(key, rule);
357
+ }
358
+ });
359
+ this.rules.forEach((rule, index) => {
360
+ const key = (rule === null || rule === void 0 ? void 0 : rule.id) || `current-${index}`;
361
+ mergedMap.set(key, rule);
362
+ });
363
+ this.rules = Array.from(mergedMap.values());
364
+ }
365
+ else {
366
+ this.rules = oldRules;
367
+ }
368
+ merged = true;
369
+ }
370
+ }
371
+ catch (error) {
372
+ console.error('[Database] 迁移 rules.json 时出错:', error);
373
+ }
374
+ }
375
+ // 如果 routes.json 还是旧格式/缺失,或从旧 rules.json 合并过数据,或缺少 rules 字段,则写入新格式
376
+ if (routesFileFormat !== 'combined' || merged || (routesFileFormat === 'combined' && !hasRulesInRoutesFile)) {
377
+ yield this.saveRoutesData();
378
+ }
379
+ // 备份旧的 rules.json 文件
380
+ if (oldRulesExists) {
381
+ try {
382
+ const timestamp = Date.now();
383
+ const backupFile = path_1.default.join(this.dataPath, `rules.json.backup.${timestamp}`);
384
+ yield promises_1.default.rename(oldRulesFile, backupFile);
385
+ console.log(`[Database] 旧的 rules.json 已备份到 ${backupFile}`);
386
+ }
387
+ catch (error) {
388
+ console.error('[Database] 备份 rules.json 失败:', error);
389
+ }
390
+ }
391
+ });
392
+ }
393
+ loadConfig() {
394
+ return __awaiter(this, void 0, void 0, function* () {
395
+ try {
396
+ const data = yield promises_1.default.readFile(this.configFile, 'utf-8');
397
+ this.config = JSON.parse(data);
398
+ }
399
+ catch (_a) {
400
+ this.config = null;
401
+ }
402
+ });
403
+ }
404
+ saveConfig() {
405
+ return __awaiter(this, void 0, void 0, function* () {
406
+ yield promises_1.default.writeFile(this.configFile, JSON.stringify(this.config, null, 2));
407
+ });
408
+ }
409
+ loadSessions() {
410
+ return __awaiter(this, void 0, void 0, function* () {
411
+ try {
412
+ const data = yield promises_1.default.readFile(this.sessionsFile, 'utf-8');
413
+ this.sessions = JSON.parse(data);
414
+ }
415
+ catch (_a) {
416
+ this.sessions = [];
417
+ // 创建空文件
418
+ yield this.saveSessions();
419
+ }
420
+ });
421
+ }
422
+ saveSessions() {
423
+ return __awaiter(this, void 0, void 0, function* () {
424
+ yield promises_1.default.writeFile(this.sessionsFile, JSON.stringify(this.sessions, null, 2));
425
+ });
426
+ }
427
+ loadLogsIndex() {
428
+ return __awaiter(this, void 0, void 0, function* () {
429
+ try {
430
+ const data = yield promises_1.default.readFile(this.logsIndexFile, 'utf-8');
431
+ this.logShardsIndex = JSON.parse(data);
432
+ }
433
+ catch (_a) {
434
+ this.logShardsIndex = [];
435
+ yield this.saveLogsIndex();
436
+ }
437
+ // 检查并迁移旧的 logs.json 文件
438
+ yield this.migrateOldLogsIfNeeded();
439
+ // 清理旧日志分片
440
+ yield this.cleanupOldLogShards();
441
+ });
442
+ }
443
+ saveLogsIndex() {
444
+ return __awaiter(this, void 0, void 0, function* () {
445
+ yield promises_1.default.writeFile(this.logsIndexFile, JSON.stringify(this.logShardsIndex, null, 2));
446
+ });
447
+ }
448
+ /**
449
+ * 迁移旧的 logs.json 文件到新的分片格式
450
+ */
451
+ migrateOldLogsIfNeeded() {
452
+ return __awaiter(this, void 0, void 0, function* () {
453
+ const oldLogsFile = path_1.default.join(this.dataPath, 'logs.json');
454
+ try {
455
+ // 检查旧日志文件是否存在
456
+ yield promises_1.default.access(oldLogsFile);
457
+ console.log('[Database] Found old logs.json file, migrating to shard format...');
458
+ // 读取旧日志
459
+ const data = yield promises_1.default.readFile(oldLogsFile, 'utf-8');
460
+ const oldLogs = JSON.parse(data);
461
+ if (oldLogs.length === 0) {
462
+ console.log('[Database] Old logs.json is empty, skipping migration');
463
+ yield promises_1.default.unlink(oldLogsFile); // 删除空文件
464
+ return;
465
+ }
466
+ console.log(`[Database] Migrating ${oldLogs.length} log entries...`);
467
+ // 按日期分组日志
468
+ const logsByDate = new Map();
469
+ for (const log of oldLogs) {
470
+ const date = new Date(log.timestamp).toISOString().split('T')[0];
471
+ if (!logsByDate.has(date)) {
472
+ logsByDate.set(date, []);
473
+ }
474
+ logsByDate.get(date).push(log);
475
+ }
476
+ // 为每个日期创建分片
477
+ let migratedCount = 0;
478
+ for (const [date, logs] of logsByDate.entries()) {
479
+ // 如果单日日志超过大小限制,需要进一步分片
480
+ let currentShardLogs = [];
481
+ let currentShardSize = 0;
482
+ let shardIndex = 0;
483
+ for (const log of logs) {
484
+ const logSize = JSON.stringify(log).length;
485
+ // 检查是否需要创建新分片
486
+ if (currentShardSize + logSize > this.MAX_SHARD_SIZE && currentShardLogs.length > 0) {
487
+ // 保存当前分片
488
+ const filename = shardIndex === 0 ? `logs-${date}.json` : `logs-${date}-${shardIndex}.json`;
489
+ yield this.saveLogShard(filename, currentShardLogs);
490
+ // 更新索引
491
+ const timestamps = currentShardLogs.map(l => l.timestamp);
492
+ this.logShardsIndex.push({
493
+ filename,
494
+ date,
495
+ startTime: Math.min(...timestamps),
496
+ endTime: Math.max(...timestamps),
497
+ count: currentShardLogs.length
498
+ });
499
+ migratedCount += currentShardLogs.length;
500
+ currentShardLogs = [];
501
+ currentShardSize = 0;
502
+ shardIndex++;
503
+ }
504
+ currentShardLogs.push(log);
505
+ currentShardSize += logSize;
506
+ }
507
+ // 保存最后一个分片
508
+ if (currentShardLogs.length > 0) {
509
+ const filename = shardIndex === 0 ? `logs-${date}.json` : `logs-${date}-${shardIndex}.json`;
510
+ yield this.saveLogShard(filename, currentShardLogs);
511
+ const timestamps = currentShardLogs.map(l => l.timestamp);
512
+ this.logShardsIndex.push({
513
+ filename,
514
+ date,
515
+ startTime: Math.min(...timestamps),
516
+ endTime: Math.max(...timestamps),
517
+ count: currentShardLogs.length
518
+ });
519
+ migratedCount += currentShardLogs.length;
520
+ }
521
+ }
522
+ // 保存索引
523
+ yield this.saveLogsIndex();
524
+ console.log(`[Database] Successfully migrated ${migratedCount} log entries to ${this.logShardsIndex.length} shard(s)`);
525
+ // 备份旧文件
526
+ const backupFile = path_1.default.join(this.dataPath, 'logs.json.backup');
527
+ yield promises_1.default.rename(oldLogsFile, backupFile);
528
+ console.log(`[Database] Old logs.json backed up to ${backupFile}`);
529
+ }
530
+ catch (err) {
531
+ if (err.code === 'ENOENT') {
532
+ // 旧文件不存在,这是正常的
533
+ return;
534
+ }
535
+ console.error('[Database] Error migrating old logs:', err);
536
+ }
537
+ });
538
+ }
539
+ cleanupOldLogShards() {
540
+ return __awaiter(this, void 0, void 0, function* () {
541
+ const now = Date.now();
542
+ const cutoffTime = now - this.LOG_RETENTION_DAYS * 24 * 60 * 60 * 1000;
543
+ // 找出需要删除的分片
544
+ const toDelete = [];
545
+ for (const shard of this.logShardsIndex) {
546
+ if (shard.endTime < cutoffTime) {
547
+ toDelete.push(shard.filename);
548
+ }
549
+ }
550
+ // 删除旧分片文件
551
+ for (const filename of toDelete) {
552
+ try {
553
+ const filepath = path_1.default.join(this.logsDir, filename);
554
+ yield promises_1.default.unlink(filepath);
555
+ }
556
+ catch (err) {
557
+ console.error(`Failed to delete old log shard ${filename}:`, err);
558
+ }
559
+ }
560
+ // 更新索引
561
+ this.logShardsIndex = this.logShardsIndex.filter(s => !toDelete.includes(s.filename));
562
+ if (toDelete.length > 0) {
563
+ yield this.saveLogsIndex();
564
+ }
565
+ });
566
+ }
567
+ getLogShardFilename(timestamp) {
568
+ return __awaiter(this, void 0, void 0, function* () {
569
+ const date = new Date(timestamp);
570
+ const dateStr = date.toISOString().split('T')[0]; // YYYY-MM-DD
571
+ // 查找当天的现有分片
572
+ const existingShards = this.logShardsIndex.filter(s => s.date === dateStr);
573
+ // 检查最后一个分片的大小
574
+ for (const shard of existingShards.reverse()) {
575
+ const filepath = path_1.default.join(this.logsDir, shard.filename);
576
+ try {
577
+ const stats = yield promises_1.default.stat(filepath);
578
+ if (stats.size < this.MAX_SHARD_SIZE) {
579
+ return shard.filename;
580
+ }
581
+ }
582
+ catch (_a) {
583
+ // 文件不存在,继续查找
584
+ continue;
585
+ }
586
+ }
587
+ // 创建新分片
588
+ const shardIndex = existingShards.length;
589
+ const filename = shardIndex === 0 ? `logs-${dateStr}.json` : `logs-${dateStr}-${shardIndex}.json`;
590
+ return filename;
591
+ });
592
+ }
593
+ loadLogShard(filename) {
594
+ return __awaiter(this, void 0, void 0, function* () {
595
+ const filepath = path_1.default.join(this.logsDir, filename);
596
+ try {
597
+ const data = yield promises_1.default.readFile(filepath, 'utf-8');
598
+ return JSON.parse(data);
599
+ }
600
+ catch (_a) {
601
+ return [];
602
+ }
603
+ });
604
+ }
605
+ saveLogShard(filename, logs) {
606
+ return __awaiter(this, void 0, void 0, function* () {
607
+ const filepath = path_1.default.join(this.logsDir, filename);
608
+ yield promises_1.default.mkdir(this.logsDir, { recursive: true });
609
+ yield promises_1.default.writeFile(filepath, JSON.stringify(logs, null, 2));
610
+ });
611
+ }
612
+ loadErrorLogs() {
613
+ return __awaiter(this, void 0, void 0, function* () {
614
+ try {
615
+ const data = yield promises_1.default.readFile(this.errorLogsFile, 'utf-8');
616
+ this.errorLogs = JSON.parse(data);
617
+ // 兼容旧的 response 字段名,迁移到 responseBody
618
+ let needsSave = false;
619
+ for (const log of this.errorLogs) {
620
+ if (log.response !== undefined && !log.responseBody) {
621
+ log.responseBody = log.response;
622
+ delete log.response;
623
+ needsSave = true;
624
+ }
625
+ }
626
+ if (needsSave) {
627
+ yield this.saveErrorLogs();
628
+ }
629
+ }
630
+ catch (_a) {
631
+ this.errorLogs = [];
632
+ // 创建空文件
633
+ yield this.saveErrorLogs();
634
+ }
635
+ });
636
+ }
637
+ saveErrorLogs() {
638
+ return __awaiter(this, void 0, void 0, function* () {
639
+ yield promises_1.default.writeFile(this.errorLogsFile, JSON.stringify(this.errorLogs, null, 2));
640
+ this.errorLogsCountCache = null;
641
+ });
642
+ }
643
+ loadBlacklist() {
644
+ return __awaiter(this, void 0, void 0, function* () {
645
+ try {
646
+ const data = yield promises_1.default.readFile(this.blacklistFile, 'utf-8');
647
+ const entries = JSON.parse(data);
648
+ this.blacklist = new Map(entries.map(e => [
649
+ `${e.routeId}:${e.contentType}:${e.serviceId}`,
650
+ e
651
+ ]));
652
+ }
653
+ catch (_a) {
654
+ this.blacklist = new Map();
655
+ // 创建空文件
656
+ yield this.saveBlacklist();
657
+ }
658
+ });
659
+ }
660
+ saveBlacklist() {
661
+ return __awaiter(this, void 0, void 0, function* () {
662
+ const entries = Array.from(this.blacklist.values());
663
+ yield promises_1.default.writeFile(this.blacklistFile, JSON.stringify(entries, null, 2));
664
+ });
665
+ }
666
+ loadStatistics() {
667
+ return __awaiter(this, void 0, void 0, function* () {
668
+ try {
669
+ const data = yield promises_1.default.readFile(this.statisticsFile, 'utf-8');
670
+ this.statistics = JSON.parse(data);
671
+ }
672
+ catch (_a) {
673
+ this.statistics = this.createEmptyStatistics();
674
+ // 创建空文件
675
+ yield this.saveStatistics();
676
+ }
677
+ });
678
+ }
679
+ saveStatistics() {
680
+ return __awaiter(this, void 0, void 0, function* () {
681
+ yield promises_1.default.writeFile(this.statisticsFile, JSON.stringify(this.statistics, null, 2));
682
+ });
683
+ }
684
+ ensureDefaultConfig() {
685
+ return __awaiter(this, void 0, void 0, function* () {
686
+ if (!this.config) {
687
+ this.config = {
688
+ enableLogging: true,
689
+ logRetentionDays: 30,
690
+ maxLogSize: 100000,
691
+ apiKey: '',
692
+ enableFailover: true,
693
+ proxyEnabled: false,
694
+ proxyUrl: '',
695
+ proxyUsername: '',
696
+ proxyPassword: '',
697
+ };
698
+ yield this.saveConfig();
699
+ }
700
+ });
701
+ }
702
+ // Vendor operations
703
+ getVendors() {
704
+ return [...this.vendors].sort((a, b) => {
705
+ if (b.sortOrder !== a.sortOrder) {
706
+ return (b.sortOrder || 0) - (a.sortOrder || 0);
707
+ }
708
+ return b.createdAt - a.createdAt;
709
+ });
710
+ }
711
+ // 新增:获取单个供应商(带服务)
712
+ getVendor(id) {
713
+ return this.vendors.find(v => v.id === id);
714
+ }
715
+ createVendor(vendor) {
716
+ return __awaiter(this, void 0, void 0, function* () {
717
+ console.log('[数据库] 创建供应商,输入数据:', JSON.stringify(vendor, null, 2));
718
+ const id = crypto_1.default.randomUUID();
719
+ const now = Date.now();
720
+ const newVendor = Object.assign(Object.assign({}, vendor), { id, services: vendor.services || [], createdAt: now, updatedAt: now });
721
+ console.log('[数据库] 创建供应商,返回数据:', JSON.stringify(newVendor, null, 2));
722
+ this.vendors.push(newVendor);
723
+ yield this.saveVendors();
724
+ return newVendor;
725
+ });
726
+ }
727
+ updateVendor(id, vendor) {
728
+ return __awaiter(this, void 0, void 0, function* () {
729
+ const index = this.vendors.findIndex(v => v.id === id);
730
+ if (index === -1)
731
+ return false;
732
+ const now = Date.now();
733
+ this.vendors[index] = Object.assign(Object.assign(Object.assign({}, this.vendors[index]), vendor), { id, services: vendor.services !== undefined ? vendor.services : this.vendors[index].services, updatedAt: now });
734
+ yield this.saveVendors();
735
+ return true;
736
+ });
737
+ }
738
+ deleteVendor(id) {
739
+ return __awaiter(this, void 0, void 0, function* () {
740
+ const index = this.vendors.findIndex(v => v.id === id);
741
+ if (index === -1)
742
+ return false;
743
+ // 检查是否有服务被规则使用
744
+ const vendor = this.vendors[index];
745
+ const serviceIds = (vendor.services || []).map(s => s.id);
746
+ const rulesUsingServices = this.rules.filter(r => serviceIds.includes(r.targetServiceId));
747
+ if (rulesUsingServices.length > 0) {
748
+ throw new Error(`无法删除供应商:有 ${rulesUsingServices.length} 个规则正在使用该供应商的服务`);
749
+ }
750
+ this.vendors.splice(index, 1);
751
+ yield this.saveVendors();
752
+ return true;
753
+ });
754
+ }
755
+ // API Service operations
756
+ getAPIServices(vendorId) {
757
+ if (vendorId) {
758
+ const vendor = this.vendors.find(v => v.id === vendorId);
759
+ if (!vendor)
760
+ return [];
761
+ // 返回指定供应商的服务,并添加 vendorId
762
+ return (vendor.services || []).map(service => (Object.assign(Object.assign({}, service), { vendorId: vendor.id // 添加 vendorId 以便前端使用
763
+ })));
764
+ }
765
+ // 返回所有供应商的所有服务(扁平化),并添加 vendorId
766
+ const allServices = [];
767
+ for (const vendor of this.vendors) {
768
+ if (vendor.services) {
769
+ const servicesWithVendorId = vendor.services.map(service => (Object.assign(Object.assign({}, service), { vendorId: vendor.id // 添加 vendorId 以便前端使用
770
+ })));
771
+ allServices.push(...servicesWithVendorId);
772
+ }
773
+ }
774
+ return allServices.sort((a, b) => b.createdAt - a.createdAt);
775
+ }
776
+ // 新增:通过 ID 获取服务
777
+ getAPIService(id) {
778
+ var _a;
779
+ for (const vendor of this.vendors) {
780
+ const service = (_a = vendor.services) === null || _a === void 0 ? void 0 : _a.find(s => s.id === id);
781
+ if (service) {
782
+ return service;
783
+ }
784
+ }
785
+ return undefined;
786
+ }
787
+ // 新增:获取服务所属的供应商
788
+ getVendorByServiceId(serviceId) {
789
+ var _a;
790
+ for (const vendor of this.vendors) {
791
+ if ((_a = vendor.services) === null || _a === void 0 ? void 0 : _a.some(s => s.id === serviceId)) {
792
+ return vendor;
793
+ }
794
+ }
795
+ return undefined;
796
+ }
797
+ createAPIService(service) {
798
+ return __awaiter(this, void 0, void 0, function* () {
799
+ console.log('[数据库] 创建服务,输入数据:', JSON.stringify(service, null, 2));
800
+ // 从 vendorId 找到供应商
801
+ const vendorId = service.vendorId;
802
+ if (!vendorId) {
803
+ throw new Error('创建服务时必须提供 vendorId');
804
+ }
805
+ const vendor = this.vendors.find(v => v.id === vendorId);
806
+ if (!vendor) {
807
+ throw new Error(`供应商不存在: ${vendorId}`);
808
+ }
809
+ // 移除 vendorId 字段(数据存储时不需要)
810
+ const _a = service, { vendorId: _ } = _a, serviceData = __rest(_a, ["vendorId"]);
811
+ const id = crypto_1.default.randomUUID();
812
+ const now = Date.now();
813
+ const newService = Object.assign(Object.assign({}, serviceData), { id, createdAt: now, updatedAt: now });
814
+ console.log('[数据库] 创建服务,最终数据:', JSON.stringify(newService, null, 2));
815
+ if (!vendor.services) {
816
+ vendor.services = [];
817
+ }
818
+ vendor.services.push(newService);
819
+ // 更新供应商的 updatedAt 时间
820
+ vendor.updatedAt = now;
821
+ yield this.saveVendors();
822
+ console.log('[数据库] 服务已保存,当前总数:', vendor.services.length);
823
+ return Object.assign(Object.assign({}, newService), { vendorId });
824
+ });
825
+ }
826
+ updateAPIService(id, service) {
827
+ return __awaiter(this, void 0, void 0, function* () {
828
+ // 查找服务所属的供应商
829
+ const vendor = this.getVendorByServiceId(id);
830
+ if (!vendor)
831
+ return false;
832
+ const index = vendor.services.findIndex(s => s.id === id);
833
+ if (index === -1)
834
+ return false;
835
+ const now = Date.now();
836
+ vendor.services[index] = Object.assign(Object.assign(Object.assign({}, vendor.services[index]), service), { id, updatedAt: now });
837
+ // 更新供应商的 updatedAt 时间
838
+ vendor.updatedAt = now;
839
+ yield this.saveVendors();
840
+ // 同步规则的超量限制
841
+ yield this.syncRulesWithServiceLimits(id, service);
842
+ return true;
843
+ });
844
+ }
845
+ deleteAPIService(id) {
846
+ return __awaiter(this, void 0, void 0, function* () {
847
+ // 查找服务所属的供应商
848
+ const vendor = this.getVendorByServiceId(id);
849
+ if (!vendor)
850
+ return false;
851
+ const index = vendor.services.findIndex(s => s.id === id);
852
+ if (index === -1)
853
+ return false;
854
+ // 检查是否有规则正在使用此服务
855
+ const rulesUsingService = this.rules.filter(r => r.targetServiceId === id);
856
+ if (rulesUsingService.length > 0) {
857
+ throw new Error(`无法删除服务:有 ${rulesUsingService.length} 个规则正在使用此服务`);
858
+ }
859
+ vendor.services.splice(index, 1);
860
+ // 更新供应商的 updatedAt 时间
861
+ vendor.updatedAt = Date.now();
862
+ yield this.saveVendors();
863
+ return true;
864
+ });
865
+ }
866
+ syncRulesWithServiceLimits(serviceId, _service) {
867
+ return __awaiter(this, void 0, void 0, function* () {
868
+ const relatedRules = this.rules.filter(r => r.targetServiceId === serviceId);
869
+ if (relatedRules.length === 0)
870
+ return;
871
+ const now = Date.now();
872
+ const currentService = this.getAPIService(serviceId);
873
+ if (!currentService)
874
+ return;
875
+ let updated = false;
876
+ // Token超量限制同步
877
+ if (currentService.enableTokenLimit) {
878
+ for (const rule of relatedRules) {
879
+ rule.tokenLimit = currentService.tokenLimit;
880
+ rule.resetInterval = currentService.tokenResetInterval;
881
+ rule.tokenResetBaseTime = currentService.tokenResetBaseTime;
882
+ rule.updatedAt = now;
883
+ updated = true;
884
+ }
885
+ }
886
+ // 请求次数超量限制同步
887
+ if (currentService.enableRequestLimit) {
888
+ for (const rule of relatedRules) {
889
+ rule.requestCountLimit = currentService.requestCountLimit;
890
+ rule.requestResetInterval = currentService.requestResetInterval;
891
+ rule.requestResetBaseTime = currentService.requestResetBaseTime;
892
+ rule.updatedAt = now;
893
+ updated = true;
894
+ }
895
+ }
896
+ if (updated) {
897
+ yield this.saveRules();
898
+ }
899
+ });
900
+ }
901
+ // Route operations
902
+ getRoutes() {
903
+ return this.routes.sort((a, b) => b.createdAt - a.createdAt);
904
+ }
905
+ createRoute(route) {
906
+ return __awaiter(this, void 0, void 0, function* () {
907
+ const id = crypto_1.default.randomUUID();
908
+ const now = Date.now();
909
+ const newRoute = Object.assign(Object.assign({}, route), { id, createdAt: now, updatedAt: now });
910
+ this.routes.push(newRoute);
911
+ yield this.saveRoutes();
912
+ return newRoute;
913
+ });
914
+ }
915
+ updateRoute(id, route) {
916
+ return __awaiter(this, void 0, void 0, function* () {
917
+ const index = this.routes.findIndex(r => r.id === id);
918
+ if (index === -1)
919
+ return false;
920
+ const now = Date.now();
921
+ this.routes[index] = Object.assign(Object.assign(Object.assign({}, this.routes[index]), route), { id, updatedAt: now });
922
+ yield this.saveRoutes();
923
+ return true;
924
+ });
925
+ }
926
+ deleteRoute(id) {
927
+ return __awaiter(this, void 0, void 0, function* () {
928
+ const index = this.routes.findIndex(r => r.id === id);
929
+ if (index === -1)
930
+ return false;
931
+ // 删除关联的规则
932
+ this.rules = this.rules.filter(r => r.routeId !== id);
933
+ yield this.saveRules();
934
+ this.routes.splice(index, 1);
935
+ yield this.saveRoutes();
936
+ return true;
937
+ });
938
+ }
939
+ activateRoute(id) {
940
+ return __awaiter(this, void 0, void 0, function* () {
941
+ const route = this.routes.find(r => r.id === id);
942
+ if (!route)
943
+ return false;
944
+ // 停用同类型的其他路由
945
+ for (const r of this.routes) {
946
+ if (r.targetType === route.targetType) {
947
+ r.isActive = r.id === id;
948
+ }
949
+ }
950
+ yield this.saveRoutes();
951
+ return true;
952
+ });
953
+ }
954
+ deactivateRoute(id) {
955
+ return __awaiter(this, void 0, void 0, function* () {
956
+ const route = this.routes.find(r => r.id === id);
957
+ if (!route)
958
+ return false;
959
+ route.isActive = false;
960
+ yield this.saveRoutes();
961
+ return true;
962
+ });
963
+ }
964
+ deactivateAllRoutes() {
965
+ return __awaiter(this, void 0, void 0, function* () {
966
+ let count = 0;
967
+ for (const route of this.routes) {
968
+ if (route.isActive) {
969
+ route.isActive = false;
970
+ count++;
971
+ }
972
+ }
973
+ if (count > 0) {
974
+ yield this.saveRoutes();
975
+ }
976
+ return count;
977
+ });
978
+ }
979
+ // Rule operations
980
+ getRules(routeId) {
981
+ const rules = routeId
982
+ ? this.rules.filter(r => r.routeId === routeId)
983
+ : this.rules;
984
+ return rules.sort((a, b) => {
985
+ if (b.sortOrder !== a.sortOrder) {
986
+ return (b.sortOrder || 0) - (a.sortOrder || 0);
987
+ }
988
+ return b.createdAt - a.createdAt;
989
+ });
990
+ }
991
+ getRule(id) {
992
+ return this.rules.find(r => r.id === id);
993
+ }
994
+ createRule(rule) {
995
+ return __awaiter(this, void 0, void 0, function* () {
996
+ const id = crypto_1.default.randomUUID();
997
+ const now = Date.now();
998
+ const newRule = Object.assign(Object.assign({}, rule), { id, totalTokensUsed: rule.totalTokensUsed || 0, totalRequestsUsed: rule.totalRequestsUsed || 0, isDisabled: rule.isDisabled || false, createdAt: now, updatedAt: now });
999
+ this.rules.push(newRule);
1000
+ yield this.saveRules();
1001
+ return newRule;
1002
+ });
1003
+ }
1004
+ updateRule(id, rule) {
1005
+ return __awaiter(this, void 0, void 0, function* () {
1006
+ const index = this.rules.findIndex(r => r.id === id);
1007
+ if (index === -1)
1008
+ return false;
1009
+ const now = Date.now();
1010
+ this.rules[index] = Object.assign(Object.assign(Object.assign({}, this.rules[index]), rule), { id, updatedAt: now });
1011
+ yield this.saveRules();
1012
+ return true;
1013
+ });
1014
+ }
1015
+ deleteRule(id) {
1016
+ return __awaiter(this, void 0, void 0, function* () {
1017
+ const index = this.rules.findIndex(r => r.id === id);
1018
+ if (index === -1)
1019
+ return false;
1020
+ this.rules.splice(index, 1);
1021
+ yield this.saveRules();
1022
+ return true;
1023
+ });
1024
+ }
1025
+ toggleRuleDisabled(ruleId) {
1026
+ return __awaiter(this, void 0, void 0, function* () {
1027
+ const rule = this.rules.find(r => r.id === ruleId);
1028
+ if (!rule) {
1029
+ return { success: false, isDisabled: false };
1030
+ }
1031
+ rule.isDisabled = !rule.isDisabled;
1032
+ rule.updatedAt = Date.now();
1033
+ yield this.saveRules();
1034
+ return {
1035
+ success: true,
1036
+ isDisabled: rule.isDisabled
1037
+ };
1038
+ });
1039
+ }
1040
+ incrementRuleTokenUsage(ruleId, tokensUsed) {
1041
+ return __awaiter(this, void 0, void 0, function* () {
1042
+ const rule = this.rules.find(r => r.id === ruleId);
1043
+ if (!rule)
1044
+ return false;
1045
+ rule.totalTokensUsed = (rule.totalTokensUsed || 0) + tokensUsed;
1046
+ yield this.saveRules();
1047
+ return true;
1048
+ });
1049
+ }
1050
+ resetRuleTokenUsage(ruleId) {
1051
+ return __awaiter(this, void 0, void 0, function* () {
1052
+ const rule = this.rules.find(r => r.id === ruleId);
1053
+ if (!rule)
1054
+ return false;
1055
+ rule.totalTokensUsed = 0;
1056
+ rule.lastResetAt = Date.now();
1057
+ yield this.saveRules();
1058
+ return true;
1059
+ });
1060
+ }
1061
+ checkAndResetRuleIfNeeded(ruleId) {
1062
+ return __awaiter(this, void 0, void 0, function* () {
1063
+ const rule = this.rules.find(r => r.id === ruleId);
1064
+ if (!rule || !rule.resetInterval)
1065
+ return false;
1066
+ const now = Date.now();
1067
+ const resetIntervalMs = rule.resetInterval * 60 * 60 * 1000;
1068
+ const baseTime = rule.tokenResetBaseTime;
1069
+ const lastResetAt = rule.lastResetAt || 0;
1070
+ if (baseTime) {
1071
+ if (now >= baseTime) {
1072
+ yield this.resetRuleTokenUsageWithBaseTime(ruleId, baseTime);
1073
+ return true;
1074
+ }
1075
+ return false;
1076
+ }
1077
+ if (now - lastResetAt >= resetIntervalMs) {
1078
+ yield this.resetRuleTokenUsage(ruleId);
1079
+ return true;
1080
+ }
1081
+ return false;
1082
+ });
1083
+ }
1084
+ resetRuleTokenUsageWithBaseTime(ruleId, currentBaseTime) {
1085
+ return __awaiter(this, void 0, void 0, function* () {
1086
+ const rule = this.rules.find(r => r.id === ruleId);
1087
+ if (!rule || !rule.resetInterval)
1088
+ return false;
1089
+ const now = Date.now();
1090
+ const resetIntervalMs = rule.resetInterval * 60 * 60 * 1000;
1091
+ let nextBaseTime = currentBaseTime;
1092
+ while (nextBaseTime <= now) {
1093
+ nextBaseTime += resetIntervalMs;
1094
+ }
1095
+ rule.totalTokensUsed = 0;
1096
+ rule.lastResetAt = now;
1097
+ rule.tokenResetBaseTime = nextBaseTime;
1098
+ yield this.saveRules();
1099
+ return true;
1100
+ });
1101
+ }
1102
+ incrementRuleRequestCount(ruleId, count) {
1103
+ return __awaiter(this, void 0, void 0, function* () {
1104
+ const rule = this.rules.find(r => r.id === ruleId);
1105
+ if (!rule)
1106
+ return false;
1107
+ rule.totalRequestsUsed = (rule.totalRequestsUsed || 0) + count;
1108
+ yield this.saveRules();
1109
+ return true;
1110
+ });
1111
+ }
1112
+ resetRuleRequestCount(ruleId) {
1113
+ return __awaiter(this, void 0, void 0, function* () {
1114
+ const rule = this.rules.find(r => r.id === ruleId);
1115
+ if (!rule)
1116
+ return false;
1117
+ rule.totalRequestsUsed = 0;
1118
+ rule.requestLastResetAt = Date.now();
1119
+ yield this.saveRules();
1120
+ return true;
1121
+ });
1122
+ }
1123
+ checkAndResetRequestCountIfNeeded(ruleId) {
1124
+ return __awaiter(this, void 0, void 0, function* () {
1125
+ const rule = this.rules.find(r => r.id === ruleId);
1126
+ if (!rule || !rule.requestResetInterval)
1127
+ return false;
1128
+ const now = Date.now();
1129
+ const resetIntervalMs = rule.requestResetInterval * 60 * 60 * 1000;
1130
+ const baseTime = rule.requestResetBaseTime;
1131
+ const lastResetAt = rule.requestLastResetAt || 0;
1132
+ if (baseTime) {
1133
+ if (now >= baseTime) {
1134
+ yield this.resetRuleRequestCountWithBaseTime(ruleId, baseTime);
1135
+ return true;
1136
+ }
1137
+ return false;
1138
+ }
1139
+ if (now - lastResetAt >= resetIntervalMs) {
1140
+ yield this.resetRuleRequestCount(ruleId);
1141
+ return true;
1142
+ }
1143
+ return false;
1144
+ });
1145
+ }
1146
+ resetRuleRequestCountWithBaseTime(ruleId, currentBaseTime) {
1147
+ return __awaiter(this, void 0, void 0, function* () {
1148
+ const rule = this.rules.find(r => r.id === ruleId);
1149
+ if (!rule || !rule.requestResetInterval)
1150
+ return false;
1151
+ const now = Date.now();
1152
+ const resetIntervalMs = rule.requestResetInterval * 60 * 60 * 1000;
1153
+ let nextBaseTime = currentBaseTime;
1154
+ while (nextBaseTime <= now) {
1155
+ nextBaseTime += resetIntervalMs;
1156
+ }
1157
+ rule.totalRequestsUsed = 0;
1158
+ rule.requestLastResetAt = now;
1159
+ rule.requestResetBaseTime = nextBaseTime;
1160
+ yield this.saveRules();
1161
+ return true;
1162
+ });
1163
+ }
1164
+ // Log operations
1165
+ addLog(log) {
1166
+ return __awaiter(this, void 0, void 0, function* () {
1167
+ const id = crypto_1.default.randomUUID();
1168
+ const logWithId = Object.assign(Object.assign({}, log), { id });
1169
+ // 获取目标分片文件名
1170
+ const filename = yield this.getLogShardFilename(logWithId.timestamp);
1171
+ // 加载现有分片数据
1172
+ let shardLogs = yield this.loadLogShard(filename);
1173
+ // 添加新日志
1174
+ shardLogs.push(logWithId);
1175
+ // 保存分片
1176
+ yield this.saveLogShard(filename, shardLogs);
1177
+ // 更新索引
1178
+ const date = new Date(logWithId.timestamp).toISOString().split('T')[0];
1179
+ let shardIndex = this.logShardsIndex.find(s => s.filename === filename);
1180
+ if (shardIndex) {
1181
+ shardIndex.count = shardLogs.length;
1182
+ shardIndex.endTime = Math.max(shardIndex.endTime, logWithId.timestamp);
1183
+ }
1184
+ else {
1185
+ this.logShardsIndex.push({
1186
+ filename,
1187
+ date,
1188
+ startTime: logWithId.timestamp,
1189
+ endTime: logWithId.timestamp,
1190
+ count: 1
1191
+ });
1192
+ }
1193
+ yield this.saveLogsIndex();
1194
+ // 同时更新统计数据
1195
+ yield this.updateStatistics(logWithId);
1196
+ // 清除计数缓存
1197
+ this.logsCountCache = null;
1198
+ });
1199
+ }
1200
+ getLogs() {
1201
+ return __awaiter(this, arguments, void 0, function* (limit = 100, offset = 0) {
1202
+ // 按分片索引倒序排列(最新的在前)
1203
+ const sortedShards = [...this.logShardsIndex].sort((a, b) => b.endTime - a.endTime);
1204
+ const allLogs = [];
1205
+ let currentOffset = 0;
1206
+ // 遍历分片直到收集足够的日志
1207
+ for (const shard of sortedShards) {
1208
+ if (currentOffset + shard.count <= offset) {
1209
+ // 跳过整个分片
1210
+ currentOffset += shard.count;
1211
+ continue;
1212
+ }
1213
+ const shardLogs = yield this.loadLogShard(shard.filename);
1214
+ // 计算需要从该分片取出的日志范围
1215
+ let startIndex = 0;
1216
+ if (currentOffset < offset) {
1217
+ startIndex = offset - currentOffset;
1218
+ }
1219
+ const remainingCount = limit - allLogs.length;
1220
+ const endIndex = Math.min(startIndex + remainingCount, shardLogs.length);
1221
+ // 添加日志到结果
1222
+ allLogs.push(...shardLogs.slice(startIndex, endIndex));
1223
+ currentOffset += shard.count;
1224
+ if (allLogs.length >= limit) {
1225
+ break;
1226
+ }
1227
+ }
1228
+ // 按时间戳倒序排序
1229
+ return allLogs.sort((a, b) => b.timestamp - a.timestamp);
1230
+ });
1231
+ }
1232
+ clearLogs() {
1233
+ return __awaiter(this, void 0, void 0, function* () {
1234
+ // 删除所有日志分片文件
1235
+ for (const shard of this.logShardsIndex) {
1236
+ try {
1237
+ const filepath = path_1.default.join(this.logsDir, shard.filename);
1238
+ yield promises_1.default.unlink(filepath);
1239
+ }
1240
+ catch (err) {
1241
+ console.error(`Failed to delete log shard ${shard.filename}:`, err);
1242
+ }
1243
+ }
1244
+ // 清空索引
1245
+ this.logShardsIndex = [];
1246
+ yield this.saveLogsIndex();
1247
+ // 清除计数缓存
1248
+ this.logsCountCache = null;
1249
+ });
1250
+ }
1251
+ getLogsCount() {
1252
+ return __awaiter(this, void 0, void 0, function* () {
1253
+ const now = Date.now();
1254
+ if (this.logsCountCache && now - this.logsCountCache.timestamp < this.CACHE_TTL) {
1255
+ return this.logsCountCache.count;
1256
+ }
1257
+ const count = this.logShardsIndex.reduce((sum, shard) => sum + shard.count, 0);
1258
+ this.logsCountCache = { count, timestamp: now };
1259
+ return count;
1260
+ });
1261
+ }
1262
+ // Error log operations
1263
+ addErrorLog(log) {
1264
+ return __awaiter(this, void 0, void 0, function* () {
1265
+ const id = crypto_1.default.randomUUID();
1266
+ this.errorLogs.push(Object.assign(Object.assign({}, log), { id }));
1267
+ yield this.saveErrorLogs();
1268
+ });
1269
+ }
1270
+ getErrorLogs() {
1271
+ return __awaiter(this, arguments, void 0, function* (limit = 100, offset = 0) {
1272
+ const sorted = [...this.errorLogs].sort((a, b) => b.timestamp - a.timestamp);
1273
+ return sorted.slice(offset, offset + limit);
1274
+ });
1275
+ }
1276
+ clearErrorLogs() {
1277
+ return __awaiter(this, void 0, void 0, function* () {
1278
+ this.errorLogs = [];
1279
+ yield this.saveErrorLogs();
1280
+ });
1281
+ }
1282
+ getErrorLogsCount() {
1283
+ return __awaiter(this, void 0, void 0, function* () {
1284
+ const now = Date.now();
1285
+ if (this.errorLogsCountCache && now - this.errorLogsCountCache.timestamp < this.CACHE_TTL) {
1286
+ return this.errorLogsCountCache.count;
1287
+ }
1288
+ const count = this.errorLogs.length;
1289
+ this.errorLogsCountCache = { count, timestamp: now };
1290
+ return count;
1291
+ });
1292
+ }
1293
+ // Service blacklist operations
1294
+ isServiceBlacklisted(serviceId, routeId, contentType) {
1295
+ return __awaiter(this, void 0, void 0, function* () {
1296
+ const key = `${routeId}:${contentType}:${serviceId}`;
1297
+ const entry = this.blacklist.get(key);
1298
+ if (!entry)
1299
+ return false;
1300
+ if (Date.now() > entry.expiresAt) {
1301
+ this.blacklist.delete(key);
1302
+ yield this.saveBlacklist();
1303
+ return false;
1304
+ }
1305
+ return true;
1306
+ });
1307
+ }
1308
+ addToBlacklist(serviceId, routeId, contentType, errorMessage, statusCode, errorType) {
1309
+ return __awaiter(this, void 0, void 0, function* () {
1310
+ const key = `${routeId}:${contentType}:${serviceId}`;
1311
+ const now = Date.now();
1312
+ const existing = this.blacklist.get(key);
1313
+ if (existing) {
1314
+ existing.blacklistedAt = now;
1315
+ existing.expiresAt = now + 10 * 60 * 1000;
1316
+ existing.errorCount++;
1317
+ existing.lastError = errorMessage;
1318
+ existing.lastStatusCode = statusCode;
1319
+ existing.errorType = errorType;
1320
+ }
1321
+ else {
1322
+ this.blacklist.set(key, {
1323
+ serviceId,
1324
+ routeId,
1325
+ contentType,
1326
+ blacklistedAt: now,
1327
+ expiresAt: now + 10 * 60 * 1000,
1328
+ errorCount: 1,
1329
+ lastError: errorMessage,
1330
+ lastStatusCode: statusCode,
1331
+ errorType,
1332
+ });
1333
+ }
1334
+ yield this.saveBlacklist();
1335
+ });
1336
+ }
1337
+ removeFromBlacklist(serviceId, routeId, contentType) {
1338
+ return __awaiter(this, void 0, void 0, function* () {
1339
+ const key = `${routeId}:${contentType}:${serviceId}`;
1340
+ this.blacklist.delete(key);
1341
+ yield this.saveBlacklist();
1342
+ });
1343
+ }
1344
+ cleanupExpiredBlacklist() {
1345
+ return __awaiter(this, void 0, void 0, function* () {
1346
+ const now = Date.now();
1347
+ let count = 0;
1348
+ for (const [key, entry] of this.blacklist.entries()) {
1349
+ if (now > entry.expiresAt) {
1350
+ this.blacklist.delete(key);
1351
+ count++;
1352
+ }
1353
+ }
1354
+ if (count > 0) {
1355
+ yield this.saveBlacklist();
1356
+ }
1357
+ return count;
1358
+ });
1359
+ }
1360
+ // Config operations
1361
+ getConfig() {
1362
+ return this.config;
1363
+ }
1364
+ updateConfig(config) {
1365
+ return __awaiter(this, void 0, void 0, function* () {
1366
+ this.config = config;
1367
+ yield this.saveConfig();
1368
+ return true;
1369
+ });
1370
+ }
1371
+ // Export/Import operations
1372
+ exportData(password) {
1373
+ return __awaiter(this, void 0, void 0, function* () {
1374
+ // 扁平化所有服务(兼容旧格式)
1375
+ const allServices = [];
1376
+ for (const vendor of this.vendors) {
1377
+ if (vendor.services) {
1378
+ // 为每个服务添加 vendorId(兼容旧格式)
1379
+ const servicesWithVendorId = vendor.services.map(s => (Object.assign(Object.assign({}, s), { vendorId: vendor.id })));
1380
+ allServices.push(...servicesWithVendorId);
1381
+ }
1382
+ }
1383
+ const exportData = {
1384
+ version: '2.0.0', // 更新版本号
1385
+ exportDate: Date.now(),
1386
+ vendors: this.vendors,
1387
+ apiServices: allServices, // 兼容旧格式
1388
+ routes: this.routes,
1389
+ rules: this.rules,
1390
+ config: this.config,
1391
+ };
1392
+ const jsonData = JSON.stringify(exportData);
1393
+ const encrypted = crypto_js_1.default.AES.encrypt(jsonData, password).toString();
1394
+ return encrypted;
1395
+ });
1396
+ }
1397
+ importData(encryptedData, password) {
1398
+ return __awaiter(this, void 0, void 0, function* () {
1399
+ try {
1400
+ const decrypted = crypto_js_1.default.AES.decrypt(encryptedData, password);
1401
+ const jsonData = decrypted.toString(crypto_js_1.default.enc.Utf8);
1402
+ const importData = JSON.parse(jsonData);
1403
+ // 检测数据版本
1404
+ const isNewFormat = importData.vendors.some((v) => v.services);
1405
+ if (isNewFormat || importData.version >= '2.0.0') {
1406
+ // 新格式:直接使用 vendors(已包含 services)
1407
+ this.vendors = importData.vendors;
1408
+ }
1409
+ else {
1410
+ // 旧格式:需要重建 services 关系
1411
+ const { vendors, apiServices } = importData;
1412
+ // 构建 vendorId -> services 映射
1413
+ const servicesByVendor = new Map();
1414
+ for (const service of apiServices) {
1415
+ if (!service.vendorId)
1416
+ continue;
1417
+ if (!servicesByVendor.has(service.vendorId)) {
1418
+ servicesByVendor.set(service.vendorId, []);
1419
+ }
1420
+ const { vendorId } = service, serviceWithoutVendorId = __rest(service, ["vendorId"]);
1421
+ servicesByVendor.get(service.vendorId).push(serviceWithoutVendorId);
1422
+ }
1423
+ // 合并到 vendors
1424
+ this.vendors = vendors.map((vendor) => (Object.assign(Object.assign({}, vendor), { services: servicesByVendor.get(vendor.id) || [] })));
1425
+ }
1426
+ this.routes = importData.routes;
1427
+ this.rules = importData.rules;
1428
+ this.config = importData.config;
1429
+ yield Promise.all([
1430
+ this.saveVendors(),
1431
+ // 删除: this.saveServices(),
1432
+ this.saveRoutes(),
1433
+ this.saveConfig(),
1434
+ ]);
1435
+ return true;
1436
+ }
1437
+ catch (error) {
1438
+ console.error('Import error:', error);
1439
+ return false;
1440
+ }
1441
+ });
1442
+ }
1443
+ // Statistics operations
1444
+ /**
1445
+ * 更新统计数据 - 在每次添加日志时调用
1446
+ */
1447
+ updateStatistics(log) {
1448
+ return __awaiter(this, void 0, void 0, function* () {
1449
+ var _a, _b, _c, _d;
1450
+ const vendors = this.getVendors();
1451
+ const services = this.getAPIServices();
1452
+ // 更新 overview 数据
1453
+ this.statistics.overview.totalRequests++;
1454
+ this.statistics.overview.totalVendors = vendors.length;
1455
+ this.statistics.overview.totalServices = services.length;
1456
+ this.statistics.overview.totalRoutes = this.getRoutes().length;
1457
+ this.statistics.overview.totalRules = this.getRules().length;
1458
+ // 更新 tokens 统计
1459
+ const inputTokens = ((_a = log.usage) === null || _a === void 0 ? void 0 : _a.inputTokens) || 0;
1460
+ const outputTokens = ((_b = log.usage) === null || _b === void 0 ? void 0 : _b.outputTokens) || 0;
1461
+ const cacheTokens = ((_c = log.usage) === null || _c === void 0 ? void 0 : _c.cacheReadInputTokens) || 0;
1462
+ const totalTokens = ((_d = log.usage) === null || _d === void 0 ? void 0 : _d.totalTokens) || (inputTokens + outputTokens);
1463
+ this.statistics.overview.totalInputTokens += inputTokens;
1464
+ this.statistics.overview.totalOutputTokens += outputTokens;
1465
+ this.statistics.overview.totalCacheReadTokens += cacheTokens;
1466
+ this.statistics.overview.totalTokens += totalTokens;
1467
+ // 更新平均响应时间
1468
+ const currentAvg = this.statistics.overview.avgResponseTime;
1469
+ const responseTime = log.responseTime || 0;
1470
+ this.statistics.overview.avgResponseTime =
1471
+ (currentAvg * (this.statistics.overview.totalRequests - 1) + responseTime) / this.statistics.overview.totalRequests;
1472
+ // 更新成功率
1473
+ if (log.statusCode && log.statusCode >= 400) {
1474
+ const successCount = Math.round(this.statistics.overview.totalRequests * this.statistics.overview.successRate / 100);
1475
+ this.statistics.overview.successRate = ((successCount) / this.statistics.overview.totalRequests) * 100;
1476
+ }
1477
+ // 更新编程时长
1478
+ this.statistics.overview.totalCodingTime = Math.round(this.statistics.overview.totalInputTokens / 250 +
1479
+ this.statistics.overview.totalOutputTokens / 100);
1480
+ // 更新 byTargetType
1481
+ if (log.targetType) {
1482
+ let targetTypeStats = this.statistics.byTargetType.find(s => s.targetType === log.targetType);
1483
+ if (!targetTypeStats) {
1484
+ targetTypeStats = { targetType: log.targetType, totalRequests: 0, totalTokens: 0, avgResponseTime: 0 };
1485
+ this.statistics.byTargetType.push(targetTypeStats);
1486
+ }
1487
+ targetTypeStats.totalRequests++;
1488
+ targetTypeStats.totalTokens += totalTokens;
1489
+ targetTypeStats.avgResponseTime =
1490
+ (targetTypeStats.avgResponseTime * (targetTypeStats.totalRequests - 1) + responseTime) / targetTypeStats.totalRequests;
1491
+ }
1492
+ // 更新 byVendor
1493
+ if (log.vendorId) {
1494
+ let vendorStats = this.statistics.byVendor.find(s => s.vendorId === log.vendorId);
1495
+ if (!vendorStats) {
1496
+ vendorStats = {
1497
+ vendorId: log.vendorId,
1498
+ vendorName: log.vendorName || 'Unknown',
1499
+ totalRequests: 0,
1500
+ totalTokens: 0,
1501
+ avgResponseTime: 0
1502
+ };
1503
+ this.statistics.byVendor.push(vendorStats);
1504
+ }
1505
+ vendorStats.totalRequests++;
1506
+ vendorStats.totalTokens += totalTokens;
1507
+ vendorStats.avgResponseTime =
1508
+ (vendorStats.avgResponseTime * (vendorStats.totalRequests - 1) + responseTime) / vendorStats.totalRequests;
1509
+ }
1510
+ // 更新 byService
1511
+ if (log.targetServiceId) {
1512
+ let serviceStats = this.statistics.byService.find(s => s.serviceId === log.targetServiceId);
1513
+ if (!serviceStats) {
1514
+ serviceStats = {
1515
+ serviceId: log.targetServiceId,
1516
+ serviceName: log.targetServiceName || 'Unknown',
1517
+ vendorName: log.vendorName || 'Unknown',
1518
+ totalRequests: 0,
1519
+ totalTokens: 0,
1520
+ avgResponseTime: 0
1521
+ };
1522
+ this.statistics.byService.push(serviceStats);
1523
+ }
1524
+ serviceStats.totalRequests++;
1525
+ serviceStats.totalTokens += totalTokens;
1526
+ serviceStats.avgResponseTime =
1527
+ (serviceStats.avgResponseTime * (serviceStats.totalRequests - 1) + responseTime) / serviceStats.totalRequests;
1528
+ }
1529
+ // 更新 byModel
1530
+ if (log.requestModel || log.targetModel) {
1531
+ const modelName = log.requestModel || log.targetModel || 'Unknown';
1532
+ let modelStats = this.statistics.byModel.find(s => s.modelName === modelName);
1533
+ if (!modelStats) {
1534
+ modelStats = { modelName, totalRequests: 0, totalTokens: 0, avgResponseTime: 0 };
1535
+ this.statistics.byModel.push(modelStats);
1536
+ }
1537
+ modelStats.totalRequests++;
1538
+ modelStats.totalTokens += totalTokens;
1539
+ modelStats.avgResponseTime =
1540
+ (modelStats.avgResponseTime * (modelStats.totalRequests - 1) + responseTime) / modelStats.totalRequests;
1541
+ }
1542
+ // 更新 timeline
1543
+ const date = new Date(log.timestamp).toISOString().split('T')[0];
1544
+ let timelineStats = this.statistics.timeline.find(t => t.date === date);
1545
+ if (!timelineStats) {
1546
+ timelineStats = {
1547
+ date,
1548
+ totalRequests: 0,
1549
+ totalTokens: 0,
1550
+ totalInputTokens: 0,
1551
+ totalOutputTokens: 0
1552
+ };
1553
+ this.statistics.timeline.push(timelineStats);
1554
+ }
1555
+ timelineStats.totalRequests++;
1556
+ timelineStats.totalTokens += totalTokens;
1557
+ timelineStats.totalInputTokens += inputTokens;
1558
+ timelineStats.totalOutputTokens += outputTokens;
1559
+ // 保存统计数据
1560
+ yield this.saveStatistics();
1561
+ });
1562
+ }
1563
+ /**
1564
+ * 获取统计数据 - 从持久化的统计数据中读取
1565
+ * @param days - 用于过滤 timeline 数据的天数
1566
+ */
1567
+ getStatistics() {
1568
+ return __awaiter(this, arguments, void 0, function* (days = 30) {
1569
+ const now = Date.now();
1570
+ const startTime = now - days * 24 * 60 * 60 * 1000;
1571
+ // 过滤 timeline 数据
1572
+ const filteredTimeline = this.statistics.timeline.filter(t => {
1573
+ const timelineDate = new Date(t.date).getTime();
1574
+ return timelineDate >= startTime;
1575
+ });
1576
+ // 计算最近24小时的错误数
1577
+ const recentErrors = this.errorLogs.filter(log => log.timestamp >= now - 24 * 60 * 60 * 1000).length;
1578
+ return Object.assign(Object.assign({}, this.statistics), { timeline: filteredTimeline, errors: {
1579
+ totalErrors: this.errorLogs.length,
1580
+ recentErrors,
1581
+ } });
1582
+ });
1583
+ }
1584
+ /**
1585
+ * 清空统计数据 - 重置所有统计数据为初始状态
1586
+ */
1587
+ resetStatistics() {
1588
+ return __awaiter(this, void 0, void 0, function* () {
1589
+ this.statistics = this.createEmptyStatistics();
1590
+ yield this.saveStatistics();
1591
+ });
1592
+ }
1593
+ // Session operations
1594
+ getOrCreateSession(sessionId, targetType, title) {
1595
+ return __awaiter(this, void 0, void 0, function* () {
1596
+ let session = this.sessions.find(s => s.id === sessionId);
1597
+ if (!session) {
1598
+ const now = Date.now();
1599
+ session = {
1600
+ id: sessionId,
1601
+ targetType,
1602
+ title,
1603
+ firstRequestAt: now,
1604
+ lastRequestAt: now,
1605
+ requestCount: 1,
1606
+ totalTokens: 0,
1607
+ };
1608
+ this.sessions.push(session);
1609
+ yield this.saveSessions();
1610
+ }
1611
+ return session;
1612
+ });
1613
+ }
1614
+ updateSession(sessionId, updates) {
1615
+ return __awaiter(this, void 0, void 0, function* () {
1616
+ const session = this.sessions.find(s => s.id === sessionId);
1617
+ if (!session)
1618
+ return false;
1619
+ Object.assign(session, updates);
1620
+ yield this.saveSessions();
1621
+ return true;
1622
+ });
1623
+ }
1624
+ getSessions(targetType_1) {
1625
+ return __awaiter(this, arguments, void 0, function* (targetType, limit = 100, offset = 0) {
1626
+ let filtered = targetType
1627
+ ? this.sessions.filter(s => s.targetType === targetType)
1628
+ : this.sessions;
1629
+ filtered = filtered.sort((a, b) => b.lastRequestAt - a.lastRequestAt);
1630
+ return filtered.slice(offset, offset + limit);
1631
+ });
1632
+ }
1633
+ getSessionsCount(targetType) {
1634
+ return __awaiter(this, void 0, void 0, function* () {
1635
+ if (targetType) {
1636
+ return this.sessions.filter(s => s.targetType === targetType).length;
1637
+ }
1638
+ return this.sessions.length;
1639
+ });
1640
+ }
1641
+ getLogsBySessionId(sessionId_1) {
1642
+ return __awaiter(this, arguments, void 0, function* (sessionId, limit = 100) {
1643
+ const allLogs = [];
1644
+ // 遍历所有分片
1645
+ for (const shard of this.logShardsIndex) {
1646
+ const shardLogs = yield this.loadLogShard(shard.filename);
1647
+ const filtered = shardLogs.filter(log => this.isLogBelongsToSession(log, sessionId));
1648
+ allLogs.push(...filtered);
1649
+ }
1650
+ return allLogs.sort((a, b) => b.timestamp - a.timestamp).slice(0, limit);
1651
+ });
1652
+ }
1653
+ /**
1654
+ * 检查日志是否属于指定 session
1655
+ */
1656
+ isLogBelongsToSession(log, sessionId) {
1657
+ var _a, _b;
1658
+ // 检查 headers 中的 session_id(Codex)
1659
+ if (((_a = log.headers) === null || _a === void 0 ? void 0 : _a['session_id']) === sessionId) {
1660
+ return true;
1661
+ }
1662
+ // 检查 body 中的 metadata.user_id(Claude Code)
1663
+ if (log.body) {
1664
+ try {
1665
+ const body = JSON.parse(log.body);
1666
+ if (((_b = body.metadata) === null || _b === void 0 ? void 0 : _b.user_id) === sessionId) {
1667
+ return true;
1668
+ }
1669
+ }
1670
+ catch (_c) {
1671
+ // 忽略解析错误
1672
+ }
1673
+ }
1674
+ return false;
1675
+ }
1676
+ deleteSession(sessionId) {
1677
+ return __awaiter(this, void 0, void 0, function* () {
1678
+ const index = this.sessions.findIndex(s => s.id === sessionId);
1679
+ if (index === -1)
1680
+ return false;
1681
+ this.sessions.splice(index, 1);
1682
+ yield this.saveSessions();
1683
+ return true;
1684
+ });
1685
+ }
1686
+ clearSessions() {
1687
+ return __awaiter(this, void 0, void 0, function* () {
1688
+ this.sessions = [];
1689
+ yield this.saveSessions();
1690
+ });
1691
+ }
1692
+ // 新增方法:获取单个 session
1693
+ getSession(id) {
1694
+ return this.sessions.find(s => s.id === id) || null;
1695
+ }
1696
+ // 新增方法:创建或更新 session
1697
+ upsertSession(session) {
1698
+ const now = Date.now();
1699
+ const existing = this.sessions.find(s => s.id === session.id);
1700
+ if (existing) {
1701
+ // 更新现有 session
1702
+ existing.lastRequestAt = now;
1703
+ existing.requestCount++;
1704
+ existing.totalTokens += session.totalTokens || 0;
1705
+ existing.vendorId = session.vendorId;
1706
+ existing.vendorName = session.vendorName;
1707
+ existing.serviceId = session.serviceId;
1708
+ existing.serviceName = session.serviceName;
1709
+ existing.model = session.model;
1710
+ }
1711
+ else {
1712
+ // 创建新 session
1713
+ this.sessions.push({
1714
+ id: session.id,
1715
+ targetType: session.targetType,
1716
+ title: session.title,
1717
+ firstRequestAt: session.firstRequestAt,
1718
+ lastRequestAt: now,
1719
+ requestCount: 1,
1720
+ totalTokens: session.totalTokens || 0,
1721
+ vendorId: session.vendorId,
1722
+ vendorName: session.vendorName,
1723
+ serviceId: session.serviceId,
1724
+ serviceName: session.serviceName,
1725
+ model: session.model,
1726
+ });
1727
+ }
1728
+ // 异步保存(不阻塞)
1729
+ this.saveSessions().catch(console.error);
1730
+ }
1731
+ // 新增方法:获取规则黑名单状态
1732
+ getRuleBlacklistStatus(serviceId, routeId, contentType) {
1733
+ return __awaiter(this, void 0, void 0, function* () {
1734
+ const key = `${routeId}:${contentType}:${serviceId}`;
1735
+ const entry = this.blacklist.get(key);
1736
+ if (!entry)
1737
+ return null;
1738
+ if (Date.now() > entry.expiresAt) {
1739
+ this.blacklist.delete(key);
1740
+ yield this.saveBlacklist();
1741
+ return null;
1742
+ }
1743
+ return entry;
1744
+ });
1745
+ }
1746
+ // Close method for compatibility (no-op for filesystem database)
1747
+ close() {
1748
+ // 文件系统数据库不需要关闭连接
1749
+ // 所有数据已经持久化到文件
1750
+ }
1751
+ }
1752
+ exports.FileSystemDatabaseManager = FileSystemDatabaseManager;