aicodeswitch 1.9.0 → 1.10.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.
@@ -57,6 +57,31 @@ class DatabaseManager {
57
57
  writable: true,
58
58
  value: void 0
59
59
  });
60
+ // 缓存机制:总数查询缓存
61
+ Object.defineProperty(this, "logsCountCache", {
62
+ enumerable: true,
63
+ configurable: true,
64
+ writable: true,
65
+ value: null
66
+ });
67
+ Object.defineProperty(this, "accessLogsCountCache", {
68
+ enumerable: true,
69
+ configurable: true,
70
+ writable: true,
71
+ value: null
72
+ });
73
+ Object.defineProperty(this, "errorLogsCountCache", {
74
+ enumerable: true,
75
+ configurable: true,
76
+ writable: true,
77
+ value: null
78
+ });
79
+ Object.defineProperty(this, "CACHE_TTL", {
80
+ enumerable: true,
81
+ configurable: true,
82
+ writable: true,
83
+ value: 1000
84
+ }); // 1秒缓存TTL
60
85
  this.db = new better_sqlite3_1.default(path_1.default.join(dataPath, 'app.db'));
61
86
  // 启用外键约束(SQLite 默认禁用,必须手动启用才能使 ON DELETE CASCADE 生效)
62
87
  this.db.pragma('foreign_keys = ON');
@@ -100,6 +125,14 @@ class DatabaseManager {
100
125
  console.log('[DB] Migration completed: model_limits column added');
101
126
  }
102
127
  }
128
+ // 检查vendors表是否有sort_order字段
129
+ const vendorsColumns = this.db.pragma('table_info(vendors)');
130
+ const hasSortOrder = vendorsColumns.some((col) => col.name === 'sort_order');
131
+ if (!hasSortOrder) {
132
+ console.log('[DB] Running migration: Adding sort_order column to vendors table');
133
+ this.db.exec('ALTER TABLE vendors ADD COLUMN sort_order INTEGER DEFAULT 0;');
134
+ console.log('[DB] Migration completed: sort_order column added to vendors');
135
+ }
103
136
  // 检查rules表是否有token相关字段
104
137
  const rulesColumns = this.db.pragma('table_info(rules)');
105
138
  const hasTokenLimit = rulesColumns.some((col) => col.name === 'token_limit');
@@ -140,6 +173,103 @@ class DatabaseManager {
140
173
  yield this.migrateRemoveServiceTimeout();
141
174
  console.log('[DB] Migration completed: timeout column removed from api_services');
142
175
  }
176
+ // 检查api_services表是否有enable_proxy字段
177
+ const hasEnableProxy = columns.some((col) => col.name === 'enable_proxy');
178
+ if (!hasEnableProxy) {
179
+ console.log('[DB] Running migration: Adding enable_proxy column to api_services table');
180
+ this.db.exec('ALTER TABLE api_services ADD COLUMN enable_proxy INTEGER DEFAULT 0;');
181
+ console.log('[DB] Migration completed: enable_proxy column added');
182
+ }
183
+ // 检查rules表是否有请求次数相关字段
184
+ const hasRequestCountLimit = rulesColumns.some((col) => col.name === 'request_count_limit');
185
+ const hasTotalRequestsUsed = rulesColumns.some((col) => col.name === 'total_requests_used');
186
+ const hasRequestResetInterval = rulesColumns.some((col) => col.name === 'request_reset_interval');
187
+ const hasRequestLastResetAt = rulesColumns.some((col) => col.name === 'request_last_reset_at');
188
+ if (!hasRequestCountLimit) {
189
+ console.log('[DB] Running migration: Adding request_count_limit column to rules table');
190
+ this.db.exec('ALTER TABLE rules ADD COLUMN request_count_limit INTEGER;');
191
+ console.log('[DB] Migration completed: request_count_limit column added');
192
+ }
193
+ if (!hasTotalRequestsUsed) {
194
+ console.log('[DB] Running migration: Adding total_requests_used column to rules table');
195
+ this.db.exec('ALTER TABLE rules ADD COLUMN total_requests_used INTEGER DEFAULT 0;');
196
+ console.log('[DB] Migration completed: total_requests_used column added');
197
+ }
198
+ if (!hasRequestResetInterval) {
199
+ console.log('[DB] Running migration: Adding request_reset_interval column to rules table');
200
+ this.db.exec('ALTER TABLE rules ADD COLUMN request_reset_interval INTEGER;');
201
+ console.log('[DB] Migration completed: request_reset_interval column added');
202
+ }
203
+ if (!hasRequestLastResetAt) {
204
+ console.log('[DB] Running migration: Adding request_last_reset_at column to rules table');
205
+ this.db.exec('ALTER TABLE rules ADD COLUMN request_last_reset_at INTEGER;');
206
+ console.log('[DB] Migration completed: request_last_reset_at column added');
207
+ }
208
+ // 检查rules表是否有request_reset_base_time字段
209
+ const hasRequestResetBaseTime = rulesColumns.some((col) => col.name === 'request_reset_base_time');
210
+ if (!hasRequestResetBaseTime) {
211
+ console.log('[DB] Running migration: Adding request_reset_base_time column to rules table');
212
+ this.db.exec('ALTER TABLE rules ADD COLUMN request_reset_base_time INTEGER;');
213
+ console.log('[DB] Migration completed: request_reset_base_time column added');
214
+ }
215
+ // 检查rules表是否有token_reset_base_time字段
216
+ const hasTokenResetBaseTime = rulesColumns.some((col) => col.name === 'token_reset_base_time');
217
+ if (!hasTokenResetBaseTime) {
218
+ console.log('[DB] Running migration: Adding token_reset_base_time column to rules table');
219
+ this.db.exec('ALTER TABLE rules ADD COLUMN token_reset_base_time INTEGER;');
220
+ console.log('[DB] Migration completed: token_reset_base_time column added');
221
+ }
222
+ // 检查api_services表是否有超量配置相关字段
223
+ // Token超量配置
224
+ const hasEnableTokenLimit = columns.some((col) => col.name === 'enable_token_limit');
225
+ if (!hasEnableTokenLimit) {
226
+ console.log('[DB] Running migration: Adding enable_token_limit column to api_services table');
227
+ this.db.exec('ALTER TABLE api_services ADD COLUMN enable_token_limit INTEGER DEFAULT 0;');
228
+ console.log('[DB] Migration completed: enable_token_limit column added');
229
+ }
230
+ const hasServiceTokenLimit = columns.some((col) => col.name === 'token_limit');
231
+ if (!hasServiceTokenLimit) {
232
+ console.log('[DB] Running migration: Adding token_limit column to api_services table');
233
+ this.db.exec('ALTER TABLE api_services ADD COLUMN token_limit INTEGER;');
234
+ console.log('[DB] Migration completed: token_limit column added');
235
+ }
236
+ const hasTokenResetInterval = columns.some((col) => col.name === 'token_reset_interval');
237
+ if (!hasTokenResetInterval) {
238
+ console.log('[DB] Running migration: Adding token_reset_interval column to api_services table');
239
+ this.db.exec('ALTER TABLE api_services ADD COLUMN token_reset_interval INTEGER;');
240
+ console.log('[DB] Migration completed: token_reset_interval column added');
241
+ }
242
+ const hasServiceTokenResetBaseTime = columns.some((col) => col.name === 'token_reset_base_time');
243
+ if (!hasServiceTokenResetBaseTime) {
244
+ console.log('[DB] Running migration: Adding token_reset_base_time column to api_services table');
245
+ this.db.exec('ALTER TABLE api_services ADD COLUMN token_reset_base_time INTEGER;');
246
+ console.log('[DB] Migration completed: token_reset_base_time column added');
247
+ }
248
+ // 请求次数超量配置
249
+ const hasEnableRequestLimit = columns.some((col) => col.name === 'enable_request_limit');
250
+ if (!hasEnableRequestLimit) {
251
+ console.log('[DB] Running migration: Adding enable_request_limit column to api_services table');
252
+ this.db.exec('ALTER TABLE api_services ADD COLUMN enable_request_limit INTEGER DEFAULT 0;');
253
+ console.log('[DB] Migration completed: enable_request_limit column added');
254
+ }
255
+ const hasServiceRequestCountLimit = columns.some((col) => col.name === 'request_count_limit');
256
+ if (!hasServiceRequestCountLimit) {
257
+ console.log('[DB] Running migration: Adding request_count_limit column to api_services table');
258
+ this.db.exec('ALTER TABLE api_services ADD COLUMN request_count_limit INTEGER;');
259
+ console.log('[DB] Migration completed: request_count_limit column added');
260
+ }
261
+ const hasServiceRequestResetInterval = columns.some((col) => col.name === 'request_reset_interval');
262
+ if (!hasServiceRequestResetInterval) {
263
+ console.log('[DB] Running migration: Adding request_reset_interval column to api_services table');
264
+ this.db.exec('ALTER TABLE api_services ADD COLUMN request_reset_interval INTEGER;');
265
+ console.log('[DB] Migration completed: request_reset_interval column added');
266
+ }
267
+ const hasServiceRequestResetBaseTime = columns.some((col) => col.name === 'request_reset_base_time');
268
+ if (!hasServiceRequestResetBaseTime) {
269
+ console.log('[DB] Running migration: Adding request_reset_base_time column to api_services table');
270
+ this.db.exec('ALTER TABLE api_services ADD COLUMN request_reset_base_time INTEGER;');
271
+ console.log('[DB] Migration completed: request_reset_base_time column added');
272
+ }
143
273
  });
144
274
  }
145
275
  migrateMaxOutputTokensToModelLimits() {
@@ -213,6 +343,7 @@ class DatabaseManager {
213
343
  id TEXT PRIMARY KEY,
214
344
  name TEXT NOT NULL,
215
345
  description TEXT,
346
+ sort_order INTEGER DEFAULT 0,
216
347
  created_at INTEGER NOT NULL,
217
348
  updated_at INTEGER NOT NULL
218
349
  );
@@ -253,6 +384,10 @@ class DatabaseManager {
253
384
  total_tokens_used INTEGER DEFAULT 0,
254
385
  reset_interval INTEGER,
255
386
  last_reset_at INTEGER,
387
+ request_count_limit INTEGER,
388
+ total_requests_used INTEGER DEFAULT 0,
389
+ request_reset_interval INTEGER,
390
+ request_last_reset_at INTEGER,
256
391
  created_at INTEGER NOT NULL,
257
392
  updated_at INTEGER NOT NULL,
258
393
  FOREIGN KEY (route_id) REFERENCES routes(id) ON DELETE CASCADE,
@@ -272,9 +407,13 @@ class DatabaseManager {
272
407
  const defaultConfig = {
273
408
  enableLogging: true,
274
409
  logRetentionDays: 30,
275
- maxLogSize: 1000,
410
+ maxLogSize: 100000,
276
411
  apiKey: '',
277
412
  enableFailover: true, // 默认启用智能故障切换
413
+ proxyEnabled: false, // 默认不启用代理
414
+ proxyUrl: '',
415
+ proxyUsername: '',
416
+ proxyPassword: '',
278
417
  };
279
418
  this.db.prepare('INSERT INTO config (key, value) VALUES (?, ?)').run('app_config', JSON.stringify(defaultConfig));
280
419
  }
@@ -282,11 +421,12 @@ class DatabaseManager {
282
421
  }
283
422
  // Vendor operations
284
423
  getVendors() {
285
- const rows = this.db.prepare('SELECT * FROM vendors ORDER BY created_at DESC').all();
424
+ const rows = this.db.prepare('SELECT * FROM vendors ORDER BY sort_order DESC, created_at DESC').all();
286
425
  return rows.map((row) => ({
287
426
  id: row.id,
288
427
  name: row.name,
289
428
  description: row.description,
429
+ sortOrder: row.sort_order,
290
430
  createdAt: row.created_at,
291
431
  updatedAt: row.updated_at,
292
432
  }));
@@ -295,15 +435,15 @@ class DatabaseManager {
295
435
  const id = crypto_1.default.randomUUID();
296
436
  const now = Date.now();
297
437
  this.db
298
- .prepare('INSERT INTO vendors (id, name, description, created_at, updated_at) VALUES (?, ?, ?, ?, ?)')
299
- .run(id, vendor.name, vendor.description || null, now, now);
438
+ .prepare('INSERT INTO vendors (id, name, description, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)')
439
+ .run(id, vendor.name, vendor.description || null, vendor.sortOrder || 0, now, now);
300
440
  return Object.assign(Object.assign({}, vendor), { id, createdAt: now, updatedAt: now });
301
441
  }
302
442
  updateVendor(id, vendor) {
303
443
  const now = Date.now();
304
444
  const result = this.db
305
- .prepare('UPDATE vendors SET name = ?, description = ?, updated_at = ? WHERE id = ?')
306
- .run(vendor.name, vendor.description || null, now, id);
445
+ .prepare('UPDATE vendors SET name = ?, description = ?, sort_order = ?, updated_at = ? WHERE id = ?')
446
+ .run(vendor.name, vendor.description || null, vendor.sortOrder !== undefined ? vendor.sortOrder : 0, now, id);
307
447
  return result.changes > 0;
308
448
  }
309
449
  deleteVendor(id) {
@@ -328,6 +468,17 @@ class DatabaseManager {
328
468
  sourceType: row.source_type,
329
469
  supportedModels: row.supported_models ? row.supported_models.split(',').map((model) => model.trim()).filter((model) => model.length > 0) : undefined,
330
470
  modelLimits: row.model_limits ? JSON.parse(row.model_limits) : undefined,
471
+ enableProxy: row.enable_proxy === 1,
472
+ // Token超量配置
473
+ enableTokenLimit: row.enable_token_limit === 1,
474
+ tokenLimit: row.token_limit,
475
+ tokenResetInterval: row.token_reset_interval,
476
+ tokenResetBaseTime: row.token_reset_base_time,
477
+ // 请求次数超量配置
478
+ enableRequestLimit: row.enable_request_limit === 1,
479
+ requestCountLimit: row.request_count_limit,
480
+ requestResetInterval: row.request_reset_interval,
481
+ requestResetBaseTime: row.request_reset_base_time,
331
482
  createdAt: row.created_at,
332
483
  updatedAt: row.updated_at,
333
484
  }));
@@ -341,15 +492,15 @@ class DatabaseManager {
341
492
  const id = crypto_1.default.randomUUID();
342
493
  const now = Date.now();
343
494
  this.db
344
- .prepare('INSERT INTO api_services (id, vendor_id, name, api_url, api_key, source_type, supported_models, model_limits, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
345
- .run(id, service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || null, service.supportedModels ? service.supportedModels.join(',') : null, service.modelLimits ? JSON.stringify(service.modelLimits) : null, now, now);
495
+ .prepare('INSERT INTO api_services (id, vendor_id, name, api_url, api_key, source_type, supported_models, model_limits, enable_proxy, enable_token_limit, token_limit, token_reset_interval, token_reset_base_time, enable_request_limit, request_count_limit, request_reset_interval, request_reset_base_time, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
496
+ .run(id, service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || null, service.supportedModels ? service.supportedModels.join(',') : null, service.modelLimits ? JSON.stringify(service.modelLimits) : null, service.enableProxy ? 1 : 0, service.enableTokenLimit ? 1 : 0, service.tokenLimit || null, service.tokenResetInterval || null, service.tokenResetBaseTime || null, service.enableRequestLimit ? 1 : 0, service.requestCountLimit || null, service.requestResetInterval || null, service.requestResetBaseTime || null, now, now);
346
497
  return Object.assign(Object.assign({}, service), { id, createdAt: now, updatedAt: now });
347
498
  }
348
499
  updateAPIService(id, service) {
349
500
  const now = Date.now();
350
501
  const result = this.db
351
- .prepare('UPDATE api_services SET name = ?, api_url = ?, api_key = ?, source_type = ?, supported_models = ?, model_limits = ?, updated_at = ? WHERE id = ?')
352
- .run(service.name, service.apiUrl, service.apiKey, service.sourceType || null, service.supportedModels ? service.supportedModels.join(',') : null, service.modelLimits ? JSON.stringify(service.modelLimits) : null, now, id);
502
+ .prepare('UPDATE api_services SET vendor_id = ?, name = ?, api_url = ?, api_key = ?, source_type = ?, supported_models = ?, model_limits = ?, enable_proxy = ?, enable_token_limit = ?, token_limit = ?, token_reset_interval = ?, token_reset_base_time = ?, enable_request_limit = ?, request_count_limit = ?, request_reset_interval = ?, request_reset_base_time = ?, updated_at = ? WHERE id = ?')
503
+ .run(service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || null, service.supportedModels ? service.supportedModels.join(',') : null, service.modelLimits ? JSON.stringify(service.modelLimits) : null, service.enableProxy !== undefined ? (service.enableProxy ? 1 : 0) : null, service.enableTokenLimit !== undefined ? (service.enableTokenLimit ? 1 : 0) : null, service.tokenLimit !== undefined ? service.tokenLimit : null, service.tokenResetInterval !== undefined ? service.tokenResetInterval : null, service.tokenResetBaseTime !== undefined ? service.tokenResetBaseTime : null, service.enableRequestLimit !== undefined ? (service.enableRequestLimit ? 1 : 0) : null, service.requestCountLimit !== undefined ? service.requestCountLimit : null, service.requestResetInterval !== undefined ? service.requestResetInterval : null, service.requestResetBaseTime !== undefined ? service.requestResetBaseTime : null, now, id);
353
504
  // 调试日志: 记录更新操作
354
505
  if (result.changes > 0 && process.env.NODE_ENV === 'development') {
355
506
  console.log(`[DB] Updated service ${id}: ${service.name} -> ${service.apiUrl}`);
@@ -425,23 +576,56 @@ class DatabaseManager {
425
576
  totalTokensUsed: row.total_tokens_used,
426
577
  resetInterval: row.reset_interval,
427
578
  lastResetAt: row.last_reset_at,
579
+ tokenResetBaseTime: row.token_reset_base_time,
580
+ requestCountLimit: row.request_count_limit,
581
+ totalRequestsUsed: row.total_requests_used,
582
+ requestResetInterval: row.request_reset_interval,
583
+ requestLastResetAt: row.request_last_reset_at,
584
+ requestResetBaseTime: row.request_reset_base_time,
428
585
  createdAt: row.created_at,
429
586
  updatedAt: row.updated_at,
430
587
  }));
431
588
  }
589
+ getRule(id) {
590
+ const row = this.db.prepare('SELECT * FROM rules WHERE id = ?').get(id);
591
+ if (!row)
592
+ return undefined;
593
+ return {
594
+ id: row.id,
595
+ routeId: row.route_id,
596
+ contentType: row.content_type,
597
+ targetServiceId: row.target_service_id,
598
+ targetModel: row.target_model,
599
+ replacedModel: row.replaced_model,
600
+ sortOrder: row.sort_order,
601
+ timeout: row.timeout,
602
+ tokenLimit: row.token_limit,
603
+ totalTokensUsed: row.total_tokens_used,
604
+ resetInterval: row.reset_interval,
605
+ lastResetAt: row.last_reset_at,
606
+ tokenResetBaseTime: row.token_reset_base_time,
607
+ requestCountLimit: row.request_count_limit,
608
+ totalRequestsUsed: row.total_requests_used,
609
+ requestResetInterval: row.request_reset_interval,
610
+ requestLastResetAt: row.request_last_reset_at,
611
+ requestResetBaseTime: row.request_reset_base_time,
612
+ createdAt: row.created_at,
613
+ updatedAt: row.updated_at,
614
+ };
615
+ }
432
616
  createRule(route) {
433
617
  const id = crypto_1.default.randomUUID();
434
618
  const now = Date.now();
435
619
  this.db
436
- .prepare('INSERT INTO rules (id, route_id, content_type, target_service_id, target_model, replaced_model, sort_order, timeout, token_limit, total_tokens_used, reset_interval, last_reset_at, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
437
- .run(id, route.routeId, route.contentType, route.targetServiceId, route.targetModel || null, route.replacedModel || null, route.sortOrder || 0, route.timeout || null, route.tokenLimit || null, route.totalTokensUsed || 0, route.resetInterval || null, route.lastResetAt || null, now, now);
620
+ .prepare('INSERT INTO rules (id, route_id, content_type, target_service_id, target_model, replaced_model, sort_order, timeout, token_limit, total_tokens_used, reset_interval, last_reset_at, token_reset_base_time, request_count_limit, total_requests_used, request_reset_interval, request_last_reset_at, request_reset_base_time, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
621
+ .run(id, route.routeId, route.contentType, route.targetServiceId, route.targetModel || null, route.replacedModel || null, route.sortOrder || 0, route.timeout || null, route.tokenLimit || null, route.totalTokensUsed || 0, route.resetInterval || null, route.lastResetAt || null, route.tokenResetBaseTime || null, route.requestCountLimit || null, route.totalRequestsUsed || 0, route.requestResetInterval || null, route.requestLastResetAt || null, route.requestResetBaseTime || null, now, now);
438
622
  return Object.assign(Object.assign({}, route), { id, createdAt: now, updatedAt: now });
439
623
  }
440
624
  updateRule(id, route) {
441
625
  const now = Date.now();
442
626
  const result = this.db
443
- .prepare('UPDATE rules SET content_type = ?, target_service_id = ?, target_model = ?, replaced_model = ?, sort_order = ?, timeout = ?, token_limit = ?, reset_interval = ?, updated_at = ? WHERE id = ?')
444
- .run(route.contentType, route.targetServiceId, route.targetModel || null, route.replacedModel || null, route.sortOrder || 0, route.timeout !== undefined ? route.timeout : null, route.tokenLimit !== undefined ? route.tokenLimit : null, route.resetInterval !== undefined ? route.resetInterval : null, now, id);
627
+ .prepare('UPDATE rules SET content_type = ?, target_service_id = ?, target_model = ?, replaced_model = ?, sort_order = ?, timeout = ?, token_limit = ?, reset_interval = ?, token_reset_base_time = ?, request_count_limit = ?, request_reset_interval = ?, request_reset_base_time = ?, updated_at = ? WHERE id = ?')
628
+ .run(route.contentType, route.targetServiceId, route.targetModel || null, route.replacedModel || null, route.sortOrder || 0, route.timeout !== undefined ? route.timeout : null, route.tokenLimit !== undefined ? route.tokenLimit : null, route.resetInterval !== undefined ? route.resetInterval : null, route.tokenResetBaseTime !== undefined ? route.tokenResetBaseTime : null, route.requestCountLimit !== undefined ? route.requestCountLimit : null, route.requestResetInterval !== undefined ? route.requestResetInterval : null, route.requestResetBaseTime !== undefined ? route.requestResetBaseTime : null, now, id);
445
629
  return result.changes > 0;
446
630
  }
447
631
  deleteRule(id) {
@@ -480,26 +664,137 @@ class DatabaseManager {
480
664
  */
481
665
  checkAndResetRuleIfNeeded(ruleId) {
482
666
  const rule = this.db
483
- .prepare('SELECT reset_interval, last_reset_at FROM rules WHERE id = ?')
667
+ .prepare('SELECT reset_interval, last_reset_at, token_reset_base_time FROM rules WHERE id = ?')
484
668
  .get(ruleId);
485
669
  if (!rule || !rule.reset_interval) {
486
670
  return false; // 没有设置重置间隔
487
671
  }
488
672
  const now = Date.now();
489
673
  const resetIntervalMs = rule.reset_interval * 60 * 60 * 1000; // 小时转毫秒
674
+ const baseTime = rule.token_reset_base_time;
490
675
  const lastResetAt = rule.last_reset_at || 0;
491
- // 检查是否已经到了重置时间
676
+ // 场景1: 设置了时间基点
677
+ if (baseTime) {
678
+ if (now >= baseTime) {
679
+ this.resetRuleTokenUsageWithBaseTime(ruleId, baseTime);
680
+ return true;
681
+ }
682
+ return false;
683
+ }
684
+ // 场景2: 未设置时间基点,使用原始逻辑(向后兼容)
492
685
  if (now - lastResetAt >= resetIntervalMs) {
493
686
  this.resetRuleTokenUsage(ruleId);
494
687
  return true;
495
688
  }
496
689
  return false;
497
690
  }
691
+ /**
692
+ * 重置规则的Token使用量(带时间基点更新)
693
+ */
694
+ resetRuleTokenUsageWithBaseTime(ruleId, currentBaseTime) {
695
+ const now = Date.now();
696
+ const rule = this.db
697
+ .prepare('SELECT reset_interval FROM rules WHERE id = ?')
698
+ .get(ruleId);
699
+ if (!rule || !rule.reset_interval) {
700
+ return false;
701
+ }
702
+ const resetIntervalMs = rule.reset_interval * 60 * 60 * 1000;
703
+ // 计算下一个时间基点
704
+ let nextBaseTime = currentBaseTime;
705
+ while (nextBaseTime <= now) {
706
+ nextBaseTime += resetIntervalMs;
707
+ }
708
+ const result = this.db
709
+ .prepare('UPDATE rules SET total_tokens_used = 0, last_reset_at = ?, token_reset_base_time = ? WHERE id = ?')
710
+ .run(now, nextBaseTime, ruleId);
711
+ return result.changes > 0;
712
+ }
713
+ /**
714
+ * 增加规则的请求次数
715
+ * @param ruleId 规则ID
716
+ * @param count 增加的次数
717
+ * @returns 是否成功
718
+ */
719
+ incrementRuleRequestCount(ruleId, count) {
720
+ const result = this.db
721
+ .prepare('UPDATE rules SET total_requests_used = total_requests_used + ? WHERE id = ?')
722
+ .run(count, ruleId);
723
+ return result.changes > 0;
724
+ }
725
+ /**
726
+ * 重置规则的请求次数
727
+ * @param ruleId 规则ID
728
+ * @returns 是否成功
729
+ */
730
+ resetRuleRequestCount(ruleId) {
731
+ const now = Date.now();
732
+ const result = this.db
733
+ .prepare('UPDATE rules SET total_requests_used = 0, request_last_reset_at = ? WHERE id = ?')
734
+ .run(now, ruleId);
735
+ return result.changes > 0;
736
+ }
737
+ /**
738
+ * 检查并重置到期的规则(请求次数)
739
+ * 如果规则设置了request_reset_interval且已经到了重置时间,则自动重置请求次数
740
+ * @param ruleId 规则ID
741
+ * @returns 是否进行了重置
742
+ */
743
+ checkAndResetRequestCountIfNeeded(ruleId) {
744
+ const rule = this.db
745
+ .prepare('SELECT request_reset_interval, request_last_reset_at, request_reset_base_time FROM rules WHERE id = ?')
746
+ .get(ruleId);
747
+ if (!rule || !rule.request_reset_interval) {
748
+ return false; // 没有设置重置间隔
749
+ }
750
+ const now = Date.now();
751
+ const resetIntervalMs = rule.request_reset_interval * 60 * 60 * 1000; // 小时转毫秒
752
+ const baseTime = rule.request_reset_base_time;
753
+ const lastResetAt = rule.request_last_reset_at || 0;
754
+ // 场景1: 设置了时间基点
755
+ if (baseTime) {
756
+ if (now >= baseTime) {
757
+ this.resetRuleRequestCountWithBaseTime(ruleId, baseTime);
758
+ return true;
759
+ }
760
+ return false;
761
+ }
762
+ // 场景2: 未设置时间基点,使用原始逻辑(向后兼容)
763
+ if (now - lastResetAt >= resetIntervalMs) {
764
+ this.resetRuleRequestCount(ruleId);
765
+ return true;
766
+ }
767
+ return false;
768
+ }
769
+ /**
770
+ * 重置规则的请求次数(带时间基点更新)
771
+ */
772
+ resetRuleRequestCountWithBaseTime(ruleId, currentBaseTime) {
773
+ const now = Date.now();
774
+ const rule = this.db
775
+ .prepare('SELECT request_reset_interval FROM rules WHERE id = ?')
776
+ .get(ruleId);
777
+ if (!rule || !rule.request_reset_interval) {
778
+ return false;
779
+ }
780
+ const resetIntervalMs = rule.request_reset_interval * 60 * 60 * 1000;
781
+ // 计算下一个时间基点
782
+ let nextBaseTime = currentBaseTime;
783
+ while (nextBaseTime <= now) {
784
+ nextBaseTime += resetIntervalMs;
785
+ }
786
+ const result = this.db
787
+ .prepare('UPDATE rules SET total_requests_used = 0, request_last_reset_at = ?, request_reset_base_time = ? WHERE id = ?')
788
+ .run(now, nextBaseTime, ruleId);
789
+ return result.changes > 0;
790
+ }
498
791
  // Log operations
499
792
  addLog(log) {
500
793
  return __awaiter(this, void 0, void 0, function* () {
501
794
  const id = crypto_1.default.randomUUID();
502
795
  yield this.logDb.put(id, JSON.stringify(Object.assign(Object.assign({}, log), { id })));
796
+ // 清除缓存
797
+ this.logsCountCache = null;
503
798
  });
504
799
  }
505
800
  getLogs() {
@@ -530,6 +825,8 @@ class DatabaseManager {
530
825
  clearLogs() {
531
826
  return __awaiter(this, void 0, void 0, function* () {
532
827
  yield this.logDb.clear();
828
+ // 清除缓存
829
+ this.logsCountCache = null;
533
830
  });
534
831
  }
535
832
  // Access log operations
@@ -537,6 +834,8 @@ class DatabaseManager {
537
834
  return __awaiter(this, void 0, void 0, function* () {
538
835
  const id = crypto_1.default.randomUUID();
539
836
  yield this.accessLogDb.put(id, JSON.stringify(Object.assign(Object.assign({}, log), { id })));
837
+ // 清除缓存
838
+ this.accessLogsCountCache = null;
540
839
  return id;
541
840
  });
542
841
  }
@@ -575,6 +874,8 @@ class DatabaseManager {
575
874
  clearAccessLogs() {
576
875
  return __awaiter(this, void 0, void 0, function* () {
577
876
  yield this.accessLogDb.clear();
877
+ // 清除缓存
878
+ this.accessLogsCountCache = null;
578
879
  });
579
880
  }
580
881
  // Error log operations
@@ -582,6 +883,8 @@ class DatabaseManager {
582
883
  return __awaiter(this, void 0, void 0, function* () {
583
884
  const id = crypto_1.default.randomUUID();
584
885
  yield this.errorLogDb.put(id, JSON.stringify(Object.assign(Object.assign({}, log), { id })));
886
+ // 清除缓存
887
+ this.errorLogsCountCache = null;
585
888
  });
586
889
  }
587
890
  getErrorLogs() {
@@ -612,6 +915,98 @@ class DatabaseManager {
612
915
  clearErrorLogs() {
613
916
  return __awaiter(this, void 0, void 0, function* () {
614
917
  yield this.errorLogDb.clear();
918
+ // 清除缓存
919
+ this.errorLogsCountCache = null;
920
+ });
921
+ }
922
+ /**
923
+ * 获取请求日志总数(带缓存)
924
+ */
925
+ getLogsCount() {
926
+ return __awaiter(this, void 0, void 0, function* () {
927
+ var _a, e_4, _b, _c;
928
+ const now = Date.now();
929
+ if (this.logsCountCache && now - this.logsCountCache.timestamp < this.CACHE_TTL) {
930
+ return this.logsCountCache.count;
931
+ }
932
+ let count = 0;
933
+ try {
934
+ for (var _d = true, _e = __asyncValues(this.logDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
935
+ _c = _f.value;
936
+ _d = false;
937
+ const _ = _c;
938
+ count++;
939
+ }
940
+ }
941
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
942
+ finally {
943
+ try {
944
+ if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
945
+ }
946
+ finally { if (e_4) throw e_4.error; }
947
+ }
948
+ this.logsCountCache = { count, timestamp: now };
949
+ return count;
950
+ });
951
+ }
952
+ /**
953
+ * 获取访问日志总数(带缓存)
954
+ */
955
+ getAccessLogsCount() {
956
+ return __awaiter(this, void 0, void 0, function* () {
957
+ var _a, e_5, _b, _c;
958
+ const now = Date.now();
959
+ if (this.accessLogsCountCache && now - this.accessLogsCountCache.timestamp < this.CACHE_TTL) {
960
+ return this.accessLogsCountCache.count;
961
+ }
962
+ let count = 0;
963
+ try {
964
+ for (var _d = true, _e = __asyncValues(this.accessLogDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
965
+ _c = _f.value;
966
+ _d = false;
967
+ const _ = _c;
968
+ count++;
969
+ }
970
+ }
971
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
972
+ finally {
973
+ try {
974
+ if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
975
+ }
976
+ finally { if (e_5) throw e_5.error; }
977
+ }
978
+ this.accessLogsCountCache = { count, timestamp: now };
979
+ return count;
980
+ });
981
+ }
982
+ /**
983
+ * 获取错误日志总数(带缓存)
984
+ */
985
+ getErrorLogsCount() {
986
+ return __awaiter(this, void 0, void 0, function* () {
987
+ var _a, e_6, _b, _c;
988
+ const now = Date.now();
989
+ if (this.errorLogsCountCache && now - this.errorLogsCountCache.timestamp < this.CACHE_TTL) {
990
+ return this.errorLogsCountCache.count;
991
+ }
992
+ let count = 0;
993
+ try {
994
+ for (var _d = true, _e = __asyncValues(this.errorLogDb.iterator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
995
+ _c = _f.value;
996
+ _d = false;
997
+ const _ = _c;
998
+ count++;
999
+ }
1000
+ }
1001
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
1002
+ finally {
1003
+ try {
1004
+ if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
1005
+ }
1006
+ finally { if (e_6) throw e_6.error; }
1007
+ }
1008
+ this.errorLogsCountCache = { count, timestamp: now };
1009
+ return count;
615
1010
  });
616
1011
  }
617
1012
  // Service blacklist operations
@@ -637,7 +1032,7 @@ class DatabaseManager {
637
1032
  }
638
1033
  });
639
1034
  }
640
- addToBlacklist(serviceId, routeId, contentType, errorMessage, statusCode) {
1035
+ addToBlacklist(serviceId, routeId, contentType, errorMessage, statusCode, errorType) {
641
1036
  return __awaiter(this, void 0, void 0, function* () {
642
1037
  const key = `${routeId}:${contentType}:${serviceId}`;
643
1038
  const now = Date.now();
@@ -651,6 +1046,7 @@ class DatabaseManager {
651
1046
  entry.errorCount++;
652
1047
  entry.lastError = errorMessage;
653
1048
  entry.lastStatusCode = statusCode;
1049
+ entry.errorType = errorType;
654
1050
  yield this.blacklistDb.put(key, JSON.stringify(entry));
655
1051
  }
656
1052
  catch (error) {
@@ -665,6 +1061,7 @@ class DatabaseManager {
665
1061
  errorCount: 1,
666
1062
  lastError: errorMessage,
667
1063
  lastStatusCode: statusCode,
1064
+ errorType,
668
1065
  };
669
1066
  yield this.blacklistDb.put(key, JSON.stringify(entry));
670
1067
  }
@@ -674,9 +1071,15 @@ class DatabaseManager {
674
1071
  }
675
1072
  });
676
1073
  }
1074
+ removeFromBlacklist(serviceId, routeId, contentType) {
1075
+ return __awaiter(this, void 0, void 0, function* () {
1076
+ const key = `${routeId}:${contentType}:${serviceId}`;
1077
+ yield this.blacklistDb.del(key);
1078
+ });
1079
+ }
677
1080
  cleanupExpiredBlacklist() {
678
1081
  return __awaiter(this, void 0, void 0, function* () {
679
- var _a, e_4, _b, _c;
1082
+ var _a, e_7, _b, _c;
680
1083
  const now = Date.now();
681
1084
  let count = 0;
682
1085
  try {
@@ -691,12 +1094,12 @@ class DatabaseManager {
691
1094
  }
692
1095
  }
693
1096
  }
694
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
1097
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
695
1098
  finally {
696
1099
  try {
697
1100
  if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
698
1101
  }
699
- finally { if (e_4) throw e_4.error; }
1102
+ finally { if (e_7) throw e_7.error; }
700
1103
  }
701
1104
  return count;
702
1105
  });
@@ -743,14 +1146,14 @@ class DatabaseManager {
743
1146
  // Import vendors
744
1147
  for (const vendor of importData.vendors) {
745
1148
  this.db
746
- .prepare('INSERT INTO vendors (id, name, description, created_at, updated_at) VALUES (?, ?, ?, ?, ?)')
747
- .run(vendor.id, vendor.name, vendor.description || null, vendor.createdAt, vendor.updatedAt);
1149
+ .prepare('INSERT INTO vendors (id, name, description, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)')
1150
+ .run(vendor.id, vendor.name, vendor.description || null, vendor.sortOrder || 0, vendor.createdAt, vendor.updatedAt);
748
1151
  }
749
1152
  // Import API services
750
1153
  for (const service of importData.apiServices) {
751
1154
  this.db
752
- .prepare('INSERT INTO api_services (id, vendor_id, name, api_url, api_key, source_type, supported_models, model_limits, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
753
- .run(service.id, service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || null, service.supportedModels ? service.supportedModels.join(',') : null, service.modelLimits ? JSON.stringify(service.modelLimits) : null, service.createdAt, service.updatedAt);
1155
+ .prepare('INSERT INTO api_services (id, vendor_id, name, api_url, api_key, source_type, supported_models, model_limits, enable_proxy, enable_token_limit, token_limit, token_reset_interval, token_reset_base_time, enable_request_limit, request_count_limit, request_reset_interval, request_reset_base_time, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
1156
+ .run(service.id, service.vendorId, service.name, service.apiUrl, service.apiKey, service.sourceType || null, service.supportedModels ? service.supportedModels.join(',') : null, service.modelLimits ? JSON.stringify(service.modelLimits) : null, service.enableProxy ? 1 : 0, service.enableTokenLimit ? 1 : 0, service.tokenLimit || null, service.tokenResetInterval || null, service.tokenResetBaseTime || null, service.enableRequestLimit ? 1 : 0, service.requestCountLimit || null, service.requestResetInterval || null, service.requestResetBaseTime || null, service.createdAt, service.updatedAt);
754
1157
  }
755
1158
  // Import routes
756
1159
  for (const route of importData.routes) {
@@ -761,8 +1164,8 @@ class DatabaseManager {
761
1164
  // Import rules
762
1165
  for (const rule of importData.rules) {
763
1166
  this.db
764
- .prepare('INSERT INTO rules (id, route_id, content_type, target_service_id, target_model, replaced_model, sort_order, timeout, token_limit, total_tokens_used, reset_interval, last_reset_at, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
765
- .run(rule.id, rule.routeId, rule.contentType || 'default', rule.targetServiceId, rule.targetModel || null, rule.replacedModel || null, rule.sortOrder || 0, rule.timeout || null, rule.tokenLimit || null, rule.totalTokensUsed || 0, rule.resetInterval || null, rule.lastResetAt || null, rule.createdAt, rule.updatedAt);
1167
+ .prepare('INSERT INTO rules (id, route_id, content_type, target_service_id, target_model, replaced_model, sort_order, timeout, token_limit, total_tokens_used, reset_interval, last_reset_at, token_reset_base_time, request_count_limit, total_requests_used, request_reset_interval, request_last_reset_at, request_reset_base_time, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
1168
+ .run(rule.id, rule.routeId, rule.contentType || 'default', rule.targetServiceId, rule.targetModel || null, rule.replacedModel || null, rule.sortOrder || 0, rule.timeout || null, rule.tokenLimit || null, rule.totalTokensUsed || 0, rule.resetInterval || null, rule.lastResetAt || null, rule.tokenResetBaseTime || null, rule.requestCountLimit || null, rule.totalRequestsUsed || 0, rule.requestResetInterval || null, rule.requestLastResetAt || null, rule.requestResetBaseTime || null, rule.createdAt, rule.updatedAt);
766
1169
  }
767
1170
  // Update config
768
1171
  this.updateConfig(importData.config);
@@ -777,7 +1180,7 @@ class DatabaseManager {
777
1180
  // Statistics operations
778
1181
  getStatistics() {
779
1182
  return __awaiter(this, arguments, void 0, function* (days = 30) {
780
- var _a, e_5, _b, _c, _d, e_6, _e, _f;
1183
+ var _a, e_8, _b, _c, _d, e_9, _e, _f;
781
1184
  var _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
782
1185
  const now = Date.now();
783
1186
  const startTime = now - days * 24 * 60 * 60 * 1000;
@@ -794,12 +1197,12 @@ class DatabaseManager {
794
1197
  }
795
1198
  }
796
1199
  }
797
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
1200
+ catch (e_8_1) { e_8 = { error: e_8_1 }; }
798
1201
  finally {
799
1202
  try {
800
1203
  if (!_z && !_a && (_b = _0.return)) yield _b.call(_0);
801
1204
  }
802
- finally { if (e_5) throw e_5.error; }
1205
+ finally { if (e_8) throw e_8.error; }
803
1206
  }
804
1207
  // Get all error logs
805
1208
  const errorLogs = [];
@@ -817,12 +1220,12 @@ class DatabaseManager {
817
1220
  }
818
1221
  }
819
1222
  }
820
- catch (e_6_1) { e_6 = { error: e_6_1 }; }
1223
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
821
1224
  finally {
822
1225
  try {
823
1226
  if (!_2 && !_d && (_e = _3.return)) yield _e.call(_3);
824
1227
  }
825
- finally { if (e_6) throw e_6.error; }
1228
+ finally { if (e_9) throw e_9.error; }
826
1229
  }
827
1230
  // Get vendors and services for mapping
828
1231
  const vendors = this.getVendors();
@@ -997,6 +1400,27 @@ class DatabaseManager {
997
1400
  };
998
1401
  });
999
1402
  }
1403
+ getRuleBlacklistStatus(serviceId, routeId, contentType) {
1404
+ return __awaiter(this, void 0, void 0, function* () {
1405
+ const key = `${routeId}:${contentType}:${serviceId}`;
1406
+ try {
1407
+ const value = yield this.blacklistDb.get(key);
1408
+ const entry = JSON.parse(value);
1409
+ // 检查是否过期
1410
+ if (Date.now() > entry.expiresAt) {
1411
+ yield this.blacklistDb.del(key);
1412
+ return null;
1413
+ }
1414
+ return entry;
1415
+ }
1416
+ catch (error) {
1417
+ if (error.code === 'LEVEL_NOT_FOUND') {
1418
+ return null;
1419
+ }
1420
+ throw error;
1421
+ }
1422
+ });
1423
+ }
1000
1424
  close() {
1001
1425
  this.db.close();
1002
1426
  this.logDb.close();