aicodeswitch 2.0.10 → 2.1.1

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.
@@ -51,6 +51,7 @@ const stream_1 = require("stream");
51
51
  const crypto_1 = __importDefault(require("crypto"));
52
52
  const streaming_1 = require("./transformers/streaming");
53
53
  const chunk_collector_1 = require("./transformers/chunk-collector");
54
+ const rules_status_service_1 = require("./rules-status-service");
54
55
  const claude_openai_1 = require("./transformers/claude-openai");
55
56
  const SUPPORTED_TARGETS = ['claude-code', 'codex'];
56
57
  class ProxyServer {
@@ -114,7 +115,7 @@ class ProxyServer {
114
115
  initialize() {
115
116
  // Dynamic proxy middleware
116
117
  this.app.use((req, res, next) => __awaiter(this, void 0, void 0, function* () {
117
- var _a, _b, _c, _d, _e;
118
+ var _a, _b, _c, _d, _e, _f, _g;
118
119
  // 仅处理支持的目标路径
119
120
  if (!SUPPORTED_TARGETS.some(target => req.path.startsWith(`/${target}/`))) {
120
121
  return next();
@@ -200,7 +201,9 @@ class ProxyServer {
200
201
  error: (lastError === null || lastError === void 0 ? void 0 : lastError.message) || 'All services failed',
201
202
  });
202
203
  }
203
- // 记录错误日志
204
+ // 确定目标类型
205
+ const targetType = req.path.startsWith('/claude-code/') ? 'claude-code' : 'codex';
206
+ // 记录错误日志 - 包含请求详情
204
207
  yield this.dbManager.addErrorLog({
205
208
  timestamp: Date.now(),
206
209
  method: req.method,
@@ -210,6 +213,10 @@ class ProxyServer {
210
213
  errorStack: lastError === null || lastError === void 0 ? void 0 : lastError.stack,
211
214
  requestHeaders: this.normalizeHeaders(req.headers),
212
215
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
216
+ // 添加请求详情
217
+ targetType,
218
+ requestModel: (_e = req.body) === null || _e === void 0 ? void 0 : _e.model,
219
+ responseTime: 0,
213
220
  });
214
221
  // 根据路径判断目标类型并返回适当的错误格式
215
222
  const isClaudeCode = req.path.startsWith('/claude-code/');
@@ -232,7 +239,7 @@ class ProxyServer {
232
239
  }
233
240
  catch (error) {
234
241
  console.error('Proxy error:', error);
235
- if (((_e = this.config) === null || _e === void 0 ? void 0 : _e.enableLogging) !== false && SUPPORTED_TARGETS.some(target => req.path.startsWith(`/${target}/`))) {
242
+ if (((_f = this.config) === null || _f === void 0 ? void 0 : _f.enableLogging) !== false && SUPPORTED_TARGETS.some(target => req.path.startsWith(`/${target}/`))) {
236
243
  yield this.dbManager.addLog({
237
244
  timestamp: Date.now(),
238
245
  method: req.method,
@@ -242,7 +249,8 @@ class ProxyServer {
242
249
  error: error.message,
243
250
  });
244
251
  }
245
- // Add error log
252
+ // Add error log - 包含请求详情
253
+ const targetType = req.path.startsWith('/claude-code/') ? 'claude-code' : 'codex';
246
254
  yield this.dbManager.addErrorLog({
247
255
  timestamp: Date.now(),
248
256
  method: req.method,
@@ -252,6 +260,10 @@ class ProxyServer {
252
260
  errorStack: error.stack,
253
261
  requestHeaders: this.normalizeHeaders(req.headers),
254
262
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
263
+ // 添加请求详情
264
+ targetType,
265
+ requestModel: (_g = req.body) === null || _g === void 0 ? void 0 : _g.model,
266
+ responseTime: 0,
255
267
  });
256
268
  // 根据路径判断目标类型并返回适当的错误格式
257
269
  const isClaudeCode = req.path.startsWith('/claude-code/');
@@ -280,7 +292,7 @@ class ProxyServer {
280
292
  }
281
293
  createFixedRouteHandler(targetType) {
282
294
  return (req, res) => __awaiter(this, void 0, void 0, function* () {
283
- var _a, _b, _c, _d, _e;
295
+ var _a, _b, _c, _d, _e, _f, _g;
284
296
  try {
285
297
  // 检查API Key验证
286
298
  if (this.config.apiKey) {
@@ -370,7 +382,7 @@ class ProxyServer {
370
382
  error: (lastError === null || lastError === void 0 ? void 0 : lastError.message) || 'All services failed',
371
383
  });
372
384
  }
373
- // 记录错误日志
385
+ // 记录错误日志 - 包含请求详情(使用函数参数 targetType)
374
386
  yield this.dbManager.addErrorLog({
375
387
  timestamp: Date.now(),
376
388
  method: req.method,
@@ -380,6 +392,10 @@ class ProxyServer {
380
392
  errorStack: lastError === null || lastError === void 0 ? void 0 : lastError.stack,
381
393
  requestHeaders: this.normalizeHeaders(req.headers),
382
394
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
395
+ // 添加请求详情
396
+ targetType,
397
+ requestModel: (_e = req.body) === null || _e === void 0 ? void 0 : _e.model,
398
+ responseTime: 0,
383
399
  });
384
400
  // 根据路径判断目标类型并返回适当的错误格式
385
401
  const isClaudeCode = req.path.startsWith('/claude-code/');
@@ -402,7 +418,7 @@ class ProxyServer {
402
418
  }
403
419
  catch (error) {
404
420
  console.error(`Fixed route error for ${targetType}:`, error);
405
- if (((_e = this.config) === null || _e === void 0 ? void 0 : _e.enableLogging) !== false && SUPPORTED_TARGETS.some(target => req.path.startsWith(`/${target}/`))) {
421
+ if (((_f = this.config) === null || _f === void 0 ? void 0 : _f.enableLogging) !== false && SUPPORTED_TARGETS.some(target => req.path.startsWith(`/${target}/`))) {
406
422
  yield this.dbManager.addLog({
407
423
  timestamp: Date.now(),
408
424
  method: req.method,
@@ -412,7 +428,7 @@ class ProxyServer {
412
428
  error: error.message,
413
429
  });
414
430
  }
415
- // Add error log
431
+ // Add error log - 包含请求详情(使用函数参数 targetType)
416
432
  yield this.dbManager.addErrorLog({
417
433
  timestamp: Date.now(),
418
434
  method: req.method,
@@ -422,6 +438,10 @@ class ProxyServer {
422
438
  errorStack: error.stack,
423
439
  requestHeaders: this.normalizeHeaders(req.headers),
424
440
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
441
+ // 添加请求详情
442
+ targetType,
443
+ requestModel: (_g = req.body) === null || _g === void 0 ? void 0 : _g.model,
444
+ responseTime: 0,
425
445
  });
426
446
  res.status(500).json({ error: error.message });
427
447
  }
@@ -762,6 +782,10 @@ class ProxyServer {
762
782
  const body = req.body;
763
783
  if (!body)
764
784
  return 'default';
785
+ // 检查是否为 count_tokens 请求(后台类型)
786
+ if (req.path.includes('/count_tokens')) {
787
+ return 'background';
788
+ }
765
789
  const explicitType = this.getExplicitContentType(req, body);
766
790
  if (explicitType) {
767
791
  return explicitType;
@@ -890,6 +914,17 @@ class ProxyServer {
890
914
  }
891
915
  hasBackgroundSignal(body) {
892
916
  var _a, _b, _c;
917
+ // 检测 count tokens 请求:messages 只有一条,role 为 "user",content 为 "count"
918
+ const messages = body === null || body === void 0 ? void 0 : body.messages;
919
+ if (Array.isArray(messages) && messages.length === 1) {
920
+ const firstMessage = messages[0];
921
+ if ((firstMessage === null || firstMessage === void 0 ? void 0 : firstMessage.role) === 'user' &&
922
+ ((firstMessage === null || firstMessage === void 0 ? void 0 : firstMessage.content) === 'count' ||
923
+ (typeof (firstMessage === null || firstMessage === void 0 ? void 0 : firstMessage.content) === 'string' && firstMessage.content.trim() === 'count'))) {
924
+ return true;
925
+ }
926
+ }
927
+ // 检测其他后台信号
893
928
  const candidates = [
894
929
  body === null || body === void 0 ? void 0 : body.background,
895
930
  (_a = body === null || body === void 0 ? void 0 : body.metadata) === null || _a === void 0 ? void 0 : _a.background,
@@ -1345,7 +1380,7 @@ class ProxyServer {
1345
1380
  }
1346
1381
  proxyRequest(req, res, route, rule, service) {
1347
1382
  return __awaiter(this, void 0, void 0, function* () {
1348
- var _a, _b;
1383
+ var _a, _b, _c, _d;
1349
1384
  res.locals.skipLog = true;
1350
1385
  const startTime = Date.now();
1351
1386
  const sourceType = (service.sourceType || 'openai-chat');
@@ -1359,6 +1394,8 @@ class ProxyServer {
1359
1394
  let streamChunksForLog;
1360
1395
  let upstreamRequestForLog;
1361
1396
  let actuallyUsedProxy = false; // 标记是否实际使用了代理
1397
+ // 标记规则正在使用
1398
+ rules_status_service_1.rulesStatusBroadcaster.markRuleInUse(route.id, rule.id);
1362
1399
  const finalizeLog = (statusCode, error) => __awaiter(this, void 0, void 0, function* () {
1363
1400
  var _a, _b;
1364
1401
  if (logged)
@@ -1428,6 +1465,11 @@ class ProxyServer {
1428
1465
  const totalTokens = (usageForLog.inputTokens || 0) + (usageForLog.outputTokens || 0);
1429
1466
  if (totalTokens > 0) {
1430
1467
  this.dbManager.incrementRuleTokenUsage(rule.id, totalTokens);
1468
+ // 获取更新后的规则数据并广播
1469
+ const updatedRule = this.dbManager.getRule(rule.id);
1470
+ if (updatedRule) {
1471
+ rules_status_service_1.rulesStatusBroadcaster.broadcastUsageUpdate(rule.id, updatedRule.totalTokensUsed || 0, updatedRule.totalRequestsUsed || 0);
1472
+ }
1431
1473
  }
1432
1474
  }
1433
1475
  // 更新规则的请求次数(只在成功请求时更新)
@@ -1437,6 +1479,11 @@ class ProxyServer {
1437
1479
  // 检查是否是重复请求(如网络重试)
1438
1480
  if (!this.isRequestProcessed(requestHash)) {
1439
1481
  this.dbManager.incrementRuleRequestCount(rule.id, 1);
1482
+ // 获取更新后的规则数据并广播
1483
+ const updatedRule = this.dbManager.getRule(rule.id);
1484
+ if (updatedRule) {
1485
+ rules_status_service_1.rulesStatusBroadcaster.broadcastUsageUpdate(rule.id, updatedRule.totalTokensUsed || 0, updatedRule.totalRequestsUsed || 0);
1486
+ }
1440
1487
  }
1441
1488
  // 定期清理过期缓存
1442
1489
  if (Math.random() < 0.01) { // 1%概率清理,避免每次都清理
@@ -1580,10 +1627,14 @@ class ProxyServer {
1580
1627
  console.error('[Proxy] Response stream error:', err);
1581
1628
  });
1582
1629
  (0, stream_1.pipeline)(response.data, parser, eventCollector, converter, serializer, res, (error) => __awaiter(this, void 0, void 0, function* () {
1630
+ var _a;
1583
1631
  if (error) {
1584
1632
  console.error('[Proxy] Pipeline error for claude-code:', error);
1585
- // 记录到错误日志
1633
+ // 记录到错误日志 - 包含请求详情和实际转发信息
1586
1634
  try {
1635
+ // 获取供应商信息
1636
+ const vendors = this.dbManager.getVendors();
1637
+ const vendor = vendors.find(v => v.id === service.vendorId);
1587
1638
  yield this.dbManager.addErrorLog({
1588
1639
  timestamp: Date.now(),
1589
1640
  method: req.method,
@@ -1594,6 +1645,16 @@ class ProxyServer {
1594
1645
  requestHeaders: this.normalizeHeaders(req.headers),
1595
1646
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
1596
1647
  upstreamRequest: upstreamRequestForLog,
1648
+ // 添加请求详情
1649
+ ruleId: rule.id,
1650
+ targetType,
1651
+ targetServiceId: service.id,
1652
+ targetServiceName: service.name,
1653
+ targetModel: rule.targetModel,
1654
+ vendorId: service.vendorId,
1655
+ vendorName: vendor === null || vendor === void 0 ? void 0 : vendor.name,
1656
+ requestModel: (_a = req.body) === null || _a === void 0 ? void 0 : _a.model,
1657
+ responseTime: Date.now() - startTime,
1597
1658
  });
1598
1659
  }
1599
1660
  catch (logError) {
@@ -1651,10 +1712,14 @@ class ProxyServer {
1651
1712
  console.error('[Proxy] Response stream error:', err);
1652
1713
  });
1653
1714
  (0, stream_1.pipeline)(response.data, parser, eventCollector, converter, serializer, res, (error) => __awaiter(this, void 0, void 0, function* () {
1715
+ var _a;
1654
1716
  if (error) {
1655
1717
  console.error('[Proxy] Pipeline error for codex:', error);
1656
- // 记录到错误日志
1718
+ // 记录到错误日志 - 包含请求详情和实际转发信息
1657
1719
  try {
1720
+ // 获取供应商信息
1721
+ const vendors = this.dbManager.getVendors();
1722
+ const vendor = vendors.find(v => v.id === service.vendorId);
1658
1723
  yield this.dbManager.addErrorLog({
1659
1724
  timestamp: Date.now(),
1660
1725
  method: req.method,
@@ -1665,6 +1730,16 @@ class ProxyServer {
1665
1730
  requestHeaders: this.normalizeHeaders(req.headers),
1666
1731
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
1667
1732
  upstreamRequest: upstreamRequestForLog,
1733
+ // 添加请求详情
1734
+ ruleId: rule.id,
1735
+ targetType,
1736
+ targetServiceId: service.id,
1737
+ targetServiceName: service.name,
1738
+ targetModel: rule.targetModel,
1739
+ vendorId: service.vendorId,
1740
+ vendorName: vendor === null || vendor === void 0 ? void 0 : vendor.name,
1741
+ requestModel: (_a = req.body) === null || _a === void 0 ? void 0 : _a.model,
1742
+ responseTime: Date.now() - startTime,
1668
1743
  });
1669
1744
  }
1670
1745
  catch (logError) {
@@ -1698,7 +1773,6 @@ class ProxyServer {
1698
1773
  });
1699
1774
  res.on('finish', () => {
1700
1775
  streamChunksForLog = eventCollector.getChunks();
1701
- console.log('[Proxy] Default stream request finished, collected chunks:', (streamChunksForLog === null || streamChunksForLog === void 0 ? void 0 : streamChunksForLog.length) || 0);
1702
1776
  // 尝试从event collector中提取usage信息
1703
1777
  const extractedUsage = eventCollector.extractUsage();
1704
1778
  if (extractedUsage) {
@@ -1757,6 +1831,9 @@ class ProxyServer {
1757
1831
  else {
1758
1832
  errorDetail = JSON.stringify(responseData);
1759
1833
  }
1834
+ // 获取供应商信息
1835
+ const vendors = this.dbManager.getVendors();
1836
+ const vendor = vendors.find(v => v.id === service.vendorId);
1760
1837
  yield this.dbManager.addErrorLog({
1761
1838
  timestamp: Date.now(),
1762
1839
  method: req.method,
@@ -1768,6 +1845,17 @@ class ProxyServer {
1768
1845
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
1769
1846
  responseHeaders: responseHeadersForLog,
1770
1847
  responseBody: responseBodyForLog,
1848
+ // 添加请求详情和实际转发信息
1849
+ ruleId: rule.id,
1850
+ targetType,
1851
+ targetServiceId: service.id,
1852
+ targetServiceName: service.name,
1853
+ targetModel: rule.targetModel,
1854
+ vendorId: service.vendorId,
1855
+ vendorName: vendor === null || vendor === void 0 ? void 0 : vendor.name,
1856
+ requestModel: (_b = req.body) === null || _b === void 0 ? void 0 : _b.model,
1857
+ upstreamRequest: upstreamRequestForLog,
1858
+ responseTime: Date.now() - startTime,
1771
1859
  });
1772
1860
  this.copyResponseHeaders(responseHeaders, res);
1773
1861
  if (contentType.includes('application/json')) {
@@ -1811,12 +1899,15 @@ class ProxyServer {
1811
1899
  console.error('Proxy error:', error);
1812
1900
  // 检测是否是 timeout 错误
1813
1901
  const isTimeout = error.code === 'ECONNABORTED' ||
1814
- ((_b = error.message) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes('timeout')) ||
1902
+ ((_c = error.message) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes('timeout')) ||
1815
1903
  (error.errno && error.errno === 'ETIMEDOUT');
1816
1904
  const errorMessage = isTimeout
1817
1905
  ? 'Request timeout - the upstream API took too long to respond'
1818
1906
  : (error.message || 'Internal server error');
1819
- // 将错误记录到错误日志
1907
+ // 将错误记录到错误日志 - 包含请求详情和实际转发信息
1908
+ // 获取供应商信息
1909
+ const vendors = this.dbManager.getVendors();
1910
+ const vendor = vendors.find(v => v.id === service.vendorId);
1820
1911
  yield this.dbManager.addErrorLog({
1821
1912
  timestamp: Date.now(),
1822
1913
  method: req.method,
@@ -1826,6 +1917,17 @@ class ProxyServer {
1826
1917
  errorStack: error.stack,
1827
1918
  requestHeaders: this.normalizeHeaders(req.headers),
1828
1919
  requestBody: req.body ? JSON.stringify(req.body) : undefined,
1920
+ // 添加请求详情和实际转发信息
1921
+ ruleId: rule.id,
1922
+ targetType,
1923
+ targetServiceId: service.id,
1924
+ targetServiceName: service.name,
1925
+ targetModel: rule.targetModel,
1926
+ vendorId: service.vendorId,
1927
+ vendorName: vendor === null || vendor === void 0 ? void 0 : vendor.name,
1928
+ requestModel: (_d = req.body) === null || _d === void 0 ? void 0 : _d.model,
1929
+ upstreamRequest: upstreamRequestForLog,
1930
+ responseTime: Date.now() - startTime,
1829
1931
  });
1830
1932
  yield finalizeLog(isTimeout ? 504 : 500, errorMessage);
1831
1933
  // 根据请求类型返回适当格式的错误响应
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RulesStatusWS = exports.rulesStatusBroadcaster = exports.RulesStatusBroadcaster = void 0;
4
+ exports.createRulesStatusWSServer = createRulesStatusWSServer;
5
+ // @ts-ignore - ws 类型声明可能需要手动安装 @types/ws
6
+ const ws_1 = require("ws");
7
+ /**
8
+ * 规则状态 WebSocket 连接管理
9
+ */
10
+ class RulesStatusWS {
11
+ constructor(ws, req) {
12
+ Object.defineProperty(this, "ws", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: void 0
17
+ });
18
+ this.ws = ws;
19
+ console.log(`[RulesStatusWS] 新的 WebSocket 连接: ${req.socket.remoteAddress}`);
20
+ this.ws.on('close', () => {
21
+ console.log(`[RulesStatusWS] WebSocket 连接关闭`);
22
+ });
23
+ this.ws.on('error', (err) => {
24
+ console.error(`[RulesStatusWS] WebSocket 错误:`, err);
25
+ });
26
+ }
27
+ /**
28
+ * 发送规则状态消息到客户端
29
+ */
30
+ sendStatus(message) {
31
+ if (this.ws.readyState === ws_1.WebSocket.OPEN) {
32
+ this.ws.send(JSON.stringify(message));
33
+ }
34
+ }
35
+ }
36
+ exports.RulesStatusWS = RulesStatusWS;
37
+ /**
38
+ * 规则状态广播服务
39
+ * 管理所有连接的客户端,负责广播规则使用状态
40
+ */
41
+ class RulesStatusBroadcaster {
42
+ constructor() {
43
+ Object.defineProperty(this, "clients", {
44
+ enumerable: true,
45
+ configurable: true,
46
+ writable: true,
47
+ value: new Set()
48
+ });
49
+ Object.defineProperty(this, "activeRules", {
50
+ enumerable: true,
51
+ configurable: true,
52
+ writable: true,
53
+ value: new Map()
54
+ }); // routeId -> Set of ruleIds
55
+ Object.defineProperty(this, "ruleTimeouts", {
56
+ enumerable: true,
57
+ configurable: true,
58
+ writable: true,
59
+ value: new Map()
60
+ });
61
+ Object.defineProperty(this, "INACTIVITY_TIMEOUT", {
62
+ enumerable: true,
63
+ configurable: true,
64
+ writable: true,
65
+ value: 30000
66
+ }); // 30秒无活动后标记为空闲
67
+ }
68
+ /**
69
+ * 添加客户端
70
+ */
71
+ addClient(client) {
72
+ this.clients.add(client);
73
+ console.log(`[RulesStatusBroadcaster] 客户端已连接,当前客户端数: ${this.clients.size}`);
74
+ }
75
+ /**
76
+ * 移除客户端
77
+ */
78
+ removeClient(client) {
79
+ this.clients.delete(client);
80
+ console.log(`[RulesStatusBroadcaster] 客户端已断开,当前客户端数: ${this.clients.size}`);
81
+ }
82
+ /**
83
+ * 标记规则正在使用
84
+ */
85
+ markRuleInUse(routeId, ruleId) {
86
+ // 添加到活动规则集合
87
+ if (!this.activeRules.has(routeId)) {
88
+ this.activeRules.set(routeId, new Set());
89
+ }
90
+ this.activeRules.get(routeId).add(ruleId);
91
+ // 清除之前的超时定时器
92
+ const timeoutKey = `${routeId}:${ruleId}`;
93
+ const existingTimeout = this.ruleTimeouts.get(timeoutKey);
94
+ if (existingTimeout) {
95
+ clearTimeout(existingTimeout);
96
+ }
97
+ // 广播状态
98
+ this.broadcastStatus({
99
+ type: 'rule_status',
100
+ data: {
101
+ ruleId,
102
+ status: 'in_use',
103
+ timestamp: Date.now(),
104
+ },
105
+ });
106
+ // 设置超时定时器,如果30秒内没有新活动则标记为空闲
107
+ const timeout = setTimeout(() => {
108
+ this.markRuleIdle(routeId, ruleId);
109
+ }, this.INACTIVITY_TIMEOUT);
110
+ this.ruleTimeouts.set(timeoutKey, timeout);
111
+ }
112
+ /**
113
+ * 标记规则空闲
114
+ */
115
+ markRuleIdle(routeId, ruleId) {
116
+ const timeoutKey = `${routeId}:${ruleId}`;
117
+ // 清除超时定时器
118
+ const existingTimeout = this.ruleTimeouts.get(timeoutKey);
119
+ if (existingTimeout) {
120
+ clearTimeout(existingTimeout);
121
+ this.ruleTimeouts.delete(timeoutKey);
122
+ }
123
+ // 从活动规则集合中移除
124
+ if (this.activeRules.has(routeId)) {
125
+ this.activeRules.get(routeId).delete(ruleId);
126
+ if (this.activeRules.get(routeId).size === 0) {
127
+ this.activeRules.delete(routeId);
128
+ }
129
+ }
130
+ // 广播空闲状态
131
+ this.broadcastStatus({
132
+ type: 'rule_status',
133
+ data: {
134
+ ruleId,
135
+ status: 'idle',
136
+ timestamp: Date.now(),
137
+ },
138
+ });
139
+ }
140
+ /**
141
+ * 广播规则使用量更新
142
+ */
143
+ broadcastUsageUpdate(ruleId, totalTokensUsed, totalRequestsUsed) {
144
+ this.broadcastStatus({
145
+ type: 'rule_status',
146
+ data: {
147
+ ruleId,
148
+ status: 'in_use',
149
+ totalTokensUsed,
150
+ totalRequestsUsed,
151
+ timestamp: Date.now(),
152
+ },
153
+ });
154
+ }
155
+ /**
156
+ * 广播消息到所有客户端
157
+ */
158
+ broadcastStatus(message) {
159
+ const deadClients = [];
160
+ this.clients.forEach((client) => {
161
+ try {
162
+ client.sendStatus(message);
163
+ }
164
+ catch (error) {
165
+ console.error('[RulesStatusBroadcaster] 发送消息失败:', error);
166
+ deadClients.push(client);
167
+ }
168
+ });
169
+ // 清理断开的客户端
170
+ deadClients.forEach((client) => {
171
+ this.removeClient(client);
172
+ });
173
+ }
174
+ /**
175
+ * 获取当前活动的规则列表
176
+ */
177
+ getActiveRules() {
178
+ return new Map(this.activeRules);
179
+ }
180
+ }
181
+ exports.RulesStatusBroadcaster = RulesStatusBroadcaster;
182
+ // 全局单例
183
+ exports.rulesStatusBroadcaster = new RulesStatusBroadcaster();
184
+ /**
185
+ * 创建 WebSocket 服务器用于规则状态
186
+ */
187
+ function createRulesStatusWSServer() {
188
+ const wss = new ws_1.WebSocketServer({ noServer: true });
189
+ wss.on('connection', (ws, req) => {
190
+ const wsHandler = new RulesStatusWS(ws, req);
191
+ exports.rulesStatusBroadcaster.addClient(wsHandler);
192
+ ws.on('close', () => {
193
+ exports.rulesStatusBroadcaster.removeClient(wsHandler);
194
+ });
195
+ });
196
+ return wss;
197
+ }