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.
- package/.github/workflows/publish-to-npm.yaml +34 -0
- package/CHANGELOG.md +17 -0
- package/dist/server/database.js +455 -31
- package/dist/server/main.js +60 -0
- package/dist/server/proxy-server.js +225 -39
- package/dist/ui/assets/index-D6RrKKB5.js +391 -0
- package/dist/ui/assets/index-DU8EG0kT.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +5 -2
- package/dist/ui/assets/index-CvBDcTGi.js +0 -391
- package/dist/ui/assets/index-vy5mPtJs.css +0 -1
package/dist/server/database.js
CHANGED
|
@@ -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:
|
|
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,
|
|
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 (
|
|
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 (
|
|
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,
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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();
|