mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat: 添加 Redis TLS 支持
- 在 .env.example 中新增 REDIS_ENABLE_TLS 配置项 - 更新 config.example.js 以支持 TLS 连接 - 修改 RedisClient 类以根据配置启用或禁用 TLS
This commit is contained in:
@@ -16,6 +16,7 @@ REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=
|
||||
REDIS_DB=0
|
||||
REDIS_ENABLE_TLS=
|
||||
|
||||
# 🎯 Claude API 配置
|
||||
CLAUDE_API_URL=https://api.anthropic.com/v1/messages
|
||||
|
||||
@@ -28,7 +28,8 @@ const config = {
|
||||
commandTimeout: 5000,
|
||||
retryDelayOnFailover: 100,
|
||||
maxRetriesPerRequest: 3,
|
||||
lazyConnect: true
|
||||
lazyConnect: true,
|
||||
enableTLS: process.env.REDIS_ENABLE_TLS || false,
|
||||
},
|
||||
|
||||
// 🎯 Claude API配置
|
||||
|
||||
406
package-lock.json
generated
406
package-lock.json
generated
@@ -15,21 +15,15 @@
|
||||
"commander": "^11.1.0",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"crypto": "^1.0.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"express-validator": "^7.0.1",
|
||||
"helmet": "^7.1.0",
|
||||
"https-proxy-agent": "^7.0.2",
|
||||
"inquirer": "^9.2.15",
|
||||
"ioredis": "^5.3.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-cron": "^3.0.3",
|
||||
"ora": "^5.4.1",
|
||||
"rate-limiter-flexible": "^5.0.5",
|
||||
"redis": "^4.6.10",
|
||||
"socks-proxy-agent": "^8.0.2",
|
||||
"table": "^6.8.1",
|
||||
"uuid": "^9.0.1",
|
||||
@@ -1309,71 +1303,6 @@
|
||||
"@noble/hashes": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/bloom": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/bloom/-/bloom-1.2.0.tgz",
|
||||
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/client": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/client/-/client-1.6.1.tgz",
|
||||
"integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cluster-key-slot": "1.1.2",
|
||||
"generic-pool": "3.9.0",
|
||||
"yallist": "4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/client/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@redis/graph": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/graph/-/graph-1.1.1.tgz",
|
||||
"integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/json": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/json/-/json-1.0.7.tgz",
|
||||
"integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/search": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/search/-/search-1.2.0.tgz",
|
||||
"integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/time-series": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/time-series/-/time-series-1.1.0.tgz",
|
||||
"integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
"version": "0.27.8",
|
||||
"resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
||||
@@ -1666,12 +1595,6 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/append-field": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/append-field/-/append-field-1.0.0.tgz",
|
||||
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
|
||||
@@ -2044,29 +1967,13 @@
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz",
|
||||
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||
"dependencies": {
|
||||
"streamsearch": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz",
|
||||
@@ -2472,21 +2379,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concat-stream": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmmirror.com/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"engines": [
|
||||
"node >= 0.8"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^2.2.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@@ -2537,12 +2429,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.5.tgz",
|
||||
@@ -2593,13 +2479,6 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/crypto/-/crypto-1.0.1.tgz",
|
||||
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
|
||||
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz",
|
||||
@@ -2760,15 +2639,6 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@@ -3195,19 +3065,6 @@
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express-validator": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/express-validator/-/express-validator-7.2.1.tgz",
|
||||
"integrity": "sha512-CjNE6aakfpuwGaHQZ3m8ltCG2Qvivd7RHtVMS/6nVxOM7xVGqr4bhflsm4+N5FP5zI7Zxp+Hae+9RE+o8e3ZOQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.21",
|
||||
"validator": "~13.12.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/external-editor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/external-editor/-/external-editor-3.1.0.tgz",
|
||||
@@ -3490,15 +3347,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/generic-pool": {
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmmirror.com/generic-pool/-/generic-pool-3.9.0.tgz",
|
||||
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
@@ -4119,12 +3967,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz",
|
||||
@@ -4917,67 +4759,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash.includes": "^4.3.0",
|
||||
"lodash.isboolean": "^3.0.3",
|
||||
"lodash.isinteger": "^4.0.4",
|
||||
"lodash.isnumber": "^3.0.3",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.once": "^4.0.0",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jsonwebtoken/node_modules/semver": {
|
||||
"version": "7.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.2.tgz",
|
||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmmirror.com/jwa/-/jwa-1.4.2.tgz",
|
||||
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "^1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz",
|
||||
@@ -5051,60 +4832,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.defaults": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isarguments": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isboolean": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isnumber": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isstring": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
@@ -5112,12 +4851,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.truncate": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
|
||||
@@ -5333,27 +5066,6 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz",
|
||||
@@ -5397,25 +5109,6 @@
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/multer": {
|
||||
"version": "1.4.5-lts.2",
|
||||
"resolved": "https://registry.npmmirror.com/multer/-/multer-1.4.5-lts.2.tgz",
|
||||
"integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==",
|
||||
"deprecated": "Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version.",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"append-field": "^1.0.0",
|
||||
"busboy": "^1.0.0",
|
||||
"concat-stream": "^1.5.2",
|
||||
"mkdirp": "^0.5.4",
|
||||
"object-assign": "^4.1.1",
|
||||
"type-is": "^1.6.4",
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mute-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/mute-stream/-/mute-stream-1.0.0.tgz",
|
||||
@@ -5441,27 +5134,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-cron": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/node-cron/-/node-cron-3.0.3.tgz",
|
||||
"integrity": "sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"uuid": "8.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-cron/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/node-int64": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/node-int64/-/node-int64-0.4.0.tgz",
|
||||
@@ -5987,12 +5659,6 @@
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prompts": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmmirror.com/prompts/-/prompts-2.4.2.tgz",
|
||||
@@ -6133,27 +5799,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz",
|
||||
@@ -6167,23 +5812,6 @@
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redis": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmmirror.com/redis/-/redis-4.7.1.tgz",
|
||||
"integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"./packages/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"@redis/bloom": "1.2.0",
|
||||
"@redis/client": "1.6.1",
|
||||
"@redis/graph": "1.1.1",
|
||||
"@redis/json": "1.0.7",
|
||||
"@redis/search": "1.2.0",
|
||||
"@redis/time-series": "1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redis-errors": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||
@@ -6787,14 +6415,6 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
@@ -7178,12 +6798,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmmirror.com/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
@@ -7291,15 +6905,6 @@
|
||||
"node": ">=10.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "13.12.0",
|
||||
"resolved": "https://registry.npmmirror.com/validator/-/validator-13.12.0.tgz",
|
||||
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz",
|
||||
@@ -7471,15 +7076,6 @@
|
||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
|
||||
|
||||
@@ -17,7 +17,8 @@ class RedisClient {
|
||||
db: config.redis.db,
|
||||
retryDelayOnFailover: config.redis.retryDelayOnFailover,
|
||||
maxRetriesPerRequest: config.redis.maxRetriesPerRequest,
|
||||
lazyConnect: config.redis.lazyConnect
|
||||
lazyConnect: config.redis.lazyConnect,
|
||||
tls: config.redis.enableTLS ? {} : false
|
||||
});
|
||||
|
||||
this.client.on('connect', () => {
|
||||
@@ -71,13 +72,13 @@ class RedisClient {
|
||||
async setApiKey(keyId, keyData, hashedKey = null) {
|
||||
const key = `apikey:${keyId}`;
|
||||
const client = this.getClientSafe();
|
||||
|
||||
|
||||
// 维护哈希映射表(用于快速查找)
|
||||
// hashedKey参数是实际的哈希值,用于建立映射
|
||||
if (hashedKey) {
|
||||
await client.hset('apikey:hash_map', hashedKey, keyId);
|
||||
}
|
||||
|
||||
|
||||
await client.hset(key, keyData);
|
||||
await client.expire(key, 86400 * 365); // 1年过期
|
||||
}
|
||||
@@ -89,14 +90,14 @@ class RedisClient {
|
||||
|
||||
async deleteApiKey(keyId) {
|
||||
const key = `apikey:${keyId}`;
|
||||
|
||||
|
||||
// 获取要删除的API Key哈希值,以便从映射表中移除
|
||||
const keyData = await this.client.hgetall(key);
|
||||
if (keyData && keyData.apiKey) {
|
||||
// keyData.apiKey现在存储的是哈希值,直接从映射表删除
|
||||
await this.client.hdel('apikey:hash_map', keyData.apiKey);
|
||||
}
|
||||
|
||||
|
||||
return await this.client.del(key);
|
||||
}
|
||||
|
||||
@@ -108,7 +109,7 @@ class RedisClient {
|
||||
if (key === 'apikey:hash_map') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
const keyData = await this.client.hgetall(key);
|
||||
if (keyData && Object.keys(keyData).length > 0) {
|
||||
apiKeys.push({ id: key.replace('apikey:', ''), ...keyData });
|
||||
@@ -124,12 +125,12 @@ class RedisClient {
|
||||
if (!keyId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
const keyData = await this.client.hgetall(`apikey:${keyId}`);
|
||||
if (keyData && Object.keys(keyData).length > 0) {
|
||||
return { id: keyId, ...keyData };
|
||||
}
|
||||
|
||||
|
||||
// 如果数据不存在,清理映射表
|
||||
await this.client.hdel('apikey:hash_map', hashedKey);
|
||||
return null;
|
||||
@@ -142,26 +143,26 @@ class RedisClient {
|
||||
const currentMonth = `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}`;
|
||||
const daily = `usage:daily:${keyId}:${today}`;
|
||||
const monthly = `usage:monthly:${keyId}:${currentMonth}`;
|
||||
|
||||
|
||||
// 按模型统计的键
|
||||
const modelDaily = `usage:model:daily:${model}:${today}`;
|
||||
const modelMonthly = `usage:model:monthly:${model}:${currentMonth}`;
|
||||
|
||||
|
||||
// API Key级别的模型统计
|
||||
const keyModelDaily = `usage:${keyId}:model:daily:${model}:${today}`;
|
||||
const keyModelMonthly = `usage:${keyId}:model:monthly:${model}:${currentMonth}`;
|
||||
|
||||
|
||||
// 智能处理输入输出token分配
|
||||
const finalInputTokens = inputTokens || 0;
|
||||
const finalOutputTokens = outputTokens || (finalInputTokens > 0 ? 0 : tokens);
|
||||
const finalCacheCreateTokens = cacheCreateTokens || 0;
|
||||
const finalCacheReadTokens = cacheReadTokens || 0;
|
||||
|
||||
|
||||
// 重新计算真实的总token数(包括缓存token)
|
||||
const totalTokens = finalInputTokens + finalOutputTokens + finalCacheCreateTokens + finalCacheReadTokens;
|
||||
// 核心token(不包括缓存)- 用于与历史数据兼容
|
||||
const coreTokens = finalInputTokens + finalOutputTokens;
|
||||
|
||||
|
||||
await Promise.all([
|
||||
// 核心token统计(保持向后兼容)
|
||||
this.client.hincrby(key, 'totalTokens', coreTokens),
|
||||
@@ -245,10 +246,10 @@ class RedisClient {
|
||||
const createdAt = keyData.createdAt ? new Date(keyData.createdAt) : new Date();
|
||||
const now = new Date();
|
||||
const daysSinceCreated = Math.max(1, Math.ceil((now - createdAt) / (1000 * 60 * 60 * 24)));
|
||||
|
||||
|
||||
const totalTokens = parseInt(total.totalTokens) || 0;
|
||||
const totalRequests = parseInt(total.totalRequests) || 0;
|
||||
|
||||
|
||||
// 计算平均RPM (requests per minute) 和 TPM (tokens per minute)
|
||||
const totalMinutes = Math.max(1, daysSinceCreated * 24 * 60);
|
||||
const avgRPM = totalRequests / totalMinutes;
|
||||
@@ -261,14 +262,14 @@ class RedisClient {
|
||||
const inputTokens = parseInt(data.totalInputTokens) || parseInt(data.inputTokens) || 0;
|
||||
const outputTokens = parseInt(data.totalOutputTokens) || parseInt(data.outputTokens) || 0;
|
||||
const requests = parseInt(data.totalRequests) || parseInt(data.requests) || 0;
|
||||
|
||||
|
||||
// 新增缓存token字段
|
||||
const cacheCreateTokens = parseInt(data.totalCacheCreateTokens) || parseInt(data.cacheCreateTokens) || 0;
|
||||
const cacheReadTokens = parseInt(data.totalCacheReadTokens) || parseInt(data.cacheReadTokens) || 0;
|
||||
const allTokens = parseInt(data.totalAllTokens) || parseInt(data.allTokens) || 0;
|
||||
|
||||
|
||||
const totalFromSeparate = inputTokens + outputTokens;
|
||||
|
||||
|
||||
if (totalFromSeparate === 0 && tokens > 0) {
|
||||
// 旧数据:没有输入输出分离
|
||||
return {
|
||||
@@ -325,7 +326,7 @@ class RedisClient {
|
||||
// 获取所有API Key ID
|
||||
const apiKeyIds = [];
|
||||
const apiKeyKeys = await client.keys('apikey:*');
|
||||
|
||||
|
||||
for (const key of apiKeyKeys) {
|
||||
if (key === 'apikey:hash_map') continue; // 跳过哈希映射表
|
||||
const keyId = key.replace('apikey:', '');
|
||||
@@ -444,7 +445,7 @@ class RedisClient {
|
||||
// 🔗 OAuth会话管理
|
||||
async setOAuthSession(sessionId, sessionData, ttl = 600) { // 10分钟过期
|
||||
const key = `oauth:${sessionId}`;
|
||||
|
||||
|
||||
// 序列化复杂对象,特别是 proxy 配置
|
||||
const serializedData = {};
|
||||
for (const [dataKey, value] of Object.entries(sessionData)) {
|
||||
@@ -454,7 +455,7 @@ class RedisClient {
|
||||
serializedData[dataKey] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await this.client.hset(key, serializedData);
|
||||
await this.client.expire(key, ttl);
|
||||
}
|
||||
@@ -462,7 +463,7 @@ class RedisClient {
|
||||
async getOAuthSession(sessionId) {
|
||||
const key = `oauth:${sessionId}`;
|
||||
const data = await this.client.hgetall(key);
|
||||
|
||||
|
||||
// 反序列化 proxy 字段
|
||||
if (data.proxy) {
|
||||
try {
|
||||
@@ -472,7 +473,7 @@ class RedisClient {
|
||||
data.proxy = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -485,11 +486,11 @@ class RedisClient {
|
||||
async checkRateLimit(identifier, limit = 100, window = 60) {
|
||||
const key = `ratelimit:${identifier}`;
|
||||
const current = await this.client.incr(key);
|
||||
|
||||
|
||||
if (current === 1) {
|
||||
await this.client.expire(key, window);
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
allowed: current <= limit,
|
||||
current,
|
||||
@@ -518,34 +519,34 @@ class RedisClient {
|
||||
try {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const dailyKeys = await this.client.keys(`usage:daily:*:${today}`);
|
||||
|
||||
|
||||
let totalRequestsToday = 0;
|
||||
let totalTokensToday = 0;
|
||||
let totalInputTokensToday = 0;
|
||||
let totalOutputTokensToday = 0;
|
||||
let totalCacheCreateTokensToday = 0;
|
||||
let totalCacheReadTokensToday = 0;
|
||||
|
||||
|
||||
// 批量获取所有今日数据,提高性能
|
||||
if (dailyKeys.length > 0) {
|
||||
const pipeline = this.client.pipeline();
|
||||
dailyKeys.forEach(key => pipeline.hgetall(key));
|
||||
const results = await pipeline.exec();
|
||||
|
||||
|
||||
for (const [error, dailyData] of results) {
|
||||
if (error || !dailyData) continue;
|
||||
|
||||
|
||||
totalRequestsToday += parseInt(dailyData.requests) || 0;
|
||||
const currentDayTokens = parseInt(dailyData.tokens) || 0;
|
||||
totalTokensToday += currentDayTokens;
|
||||
|
||||
|
||||
// 处理旧数据兼容性:如果有总token但没有输入输出分离,则使用总token作为输出token
|
||||
const inputTokens = parseInt(dailyData.inputTokens) || 0;
|
||||
const outputTokens = parseInt(dailyData.outputTokens) || 0;
|
||||
const cacheCreateTokens = parseInt(dailyData.cacheCreateTokens) || 0;
|
||||
const cacheReadTokens = parseInt(dailyData.cacheReadTokens) || 0;
|
||||
const totalTokensFromSeparate = inputTokens + outputTokens;
|
||||
|
||||
|
||||
if (totalTokensFromSeparate === 0 && currentDayTokens > 0) {
|
||||
// 旧数据:没有输入输出分离,假设70%为输出,30%为输入(基于一般对话比例)
|
||||
totalOutputTokensToday += Math.round(currentDayTokens * 0.7);
|
||||
@@ -555,7 +556,7 @@ class RedisClient {
|
||||
totalInputTokensToday += inputTokens;
|
||||
totalOutputTokensToday += outputTokens;
|
||||
}
|
||||
|
||||
|
||||
// 添加cache token统计
|
||||
totalCacheCreateTokensToday += cacheCreateTokens;
|
||||
totalCacheReadTokensToday += cacheReadTokens;
|
||||
@@ -565,12 +566,12 @@ class RedisClient {
|
||||
// 获取今日创建的API Key数量(批量优化)
|
||||
const allApiKeys = await this.client.keys('apikey:*');
|
||||
let apiKeysCreatedToday = 0;
|
||||
|
||||
|
||||
if (allApiKeys.length > 0) {
|
||||
const pipeline = this.client.pipeline();
|
||||
allApiKeys.forEach(key => pipeline.hget(key, 'createdAt'));
|
||||
const results = await pipeline.exec();
|
||||
|
||||
|
||||
for (const [error, createdAt] of results) {
|
||||
if (!error && createdAt && createdAt.startsWith(today)) {
|
||||
apiKeysCreatedToday++;
|
||||
@@ -610,40 +611,40 @@ class RedisClient {
|
||||
let totalInputTokens = 0;
|
||||
let totalOutputTokens = 0;
|
||||
let oldestCreatedAt = new Date();
|
||||
|
||||
|
||||
// 批量获取所有usage数据和key数据,提高性能
|
||||
const usageKeys = allApiKeys.map(key => `usage:${key.replace('apikey:', '')}`);
|
||||
const pipeline = this.client.pipeline();
|
||||
|
||||
|
||||
// 添加所有usage查询
|
||||
usageKeys.forEach(key => pipeline.hgetall(key));
|
||||
// 添加所有key数据查询
|
||||
allApiKeys.forEach(key => pipeline.hgetall(key));
|
||||
|
||||
|
||||
const results = await pipeline.exec();
|
||||
const usageResults = results.slice(0, usageKeys.length);
|
||||
const keyResults = results.slice(usageKeys.length);
|
||||
|
||||
|
||||
for (let i = 0; i < allApiKeys.length; i++) {
|
||||
const totalData = usageResults[i][1] || {};
|
||||
const keyData = keyResults[i][1] || {};
|
||||
|
||||
|
||||
totalRequests += parseInt(totalData.totalRequests) || 0;
|
||||
totalTokens += parseInt(totalData.totalTokens) || 0;
|
||||
totalInputTokens += parseInt(totalData.totalInputTokens) || 0;
|
||||
totalOutputTokens += parseInt(totalData.totalOutputTokens) || 0;
|
||||
|
||||
|
||||
const createdAt = keyData.createdAt ? new Date(keyData.createdAt) : new Date();
|
||||
if (createdAt < oldestCreatedAt) {
|
||||
oldestCreatedAt = createdAt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const now = new Date();
|
||||
// 保持与个人API Key计算一致的算法:按天计算然后转换为分钟
|
||||
const daysSinceOldest = Math.max(1, Math.ceil((now - oldestCreatedAt) / (1000 * 60 * 60 * 24)));
|
||||
const totalMinutes = daysSinceOldest * 24 * 60;
|
||||
|
||||
|
||||
return {
|
||||
systemRPM: Math.round((totalRequests / totalMinutes) * 100) / 100,
|
||||
systemTPM: Math.round((totalTokens / totalMinutes) * 100) / 100,
|
||||
@@ -693,7 +694,7 @@ class RedisClient {
|
||||
for (const pattern of patterns) {
|
||||
const keys = await this.client.keys(pattern);
|
||||
const pipeline = this.client.pipeline();
|
||||
|
||||
|
||||
for (const key of keys) {
|
||||
const ttl = await this.client.ttl(key);
|
||||
if (ttl === -1) { // 没有设置过期时间的键
|
||||
@@ -704,7 +705,7 @@ class RedisClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await pipeline.exec();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user