feat: add /api/keys endpoint — masked API keys with usage data (rolling/weekly/monthly)

This commit is contained in:
hmo
2026-07-19 10:53:32 +08:00
parent 3128db09c6
commit 94f5f9ec92
+66
View File
@@ -1190,6 +1190,7 @@ def api_rdp_toggle():
# ════════════════════════════════════════════════════════════
_USAGE_STATS_FILE = TEMP_DIR / "usage_stats.json"
_USAGE_COLLECTOR_SCRIPT = _SCRIPT_DIR / "usage_collector.py"
_USAGE_MONITOR_DIR = _SCRIPT_DIR / "usage_monitor"
_usage_collector_running = False
@app.route("/api/usage")
@@ -1234,6 +1235,71 @@ def api_usage_refresh():
return jsonify({"ok": True, "message": "collection triggered (~10s), poll /api/usage shortly"})
# ── Key Registry ──────────────────────────────────────────────
_ACCOUNTS_FILE = _USAGE_MONITOR_DIR / "accounts.json"
@app.route("/api/keys")
def api_keys():
"""返回所有可用 API key(masked 首尾)及各自用量。
合并 accounts.jsonkey 原文)和 usage_stats.json(用量数据)。
"""
try:
# 读 key 原文
if not _ACCOUNTS_FILE.exists():
return jsonify({"ok": False, "error": "accounts.json not found", "keys": []})
with open(str(_ACCOUNTS_FILE), "r", encoding="utf-8") as f:
accounts_data = json.load(f)
accounts = accounts_data.get("accounts", [])
# 读用量数据
usage_by_kid = {}
if _USAGE_STATS_FILE.exists():
with open(str(_USAGE_STATS_FILE), "r", encoding="utf-8") as f:
usage_data = json.load(f)
for a in usage_data.get("accounts", []):
usage_by_kid[a.get("key_id", "")] = a
# 合并
keys_out = []
for a in accounts:
kid = a.get("key_id", "")
raw_key = a.get("key", "")
# Mask: 前8后4,不足12字符则不mask
if len(raw_key) > 12:
masked = raw_key[:8] + "..." + raw_key[-4:]
else:
masked = raw_key # 短 key 不 mask
entry = {
"key_id": kid,
"label": a.get("label", kid),
"key_masked": masked,
}
# 附加用量
usage = usage_by_kid.get(kid)
if usage:
entry["workspace_id"] = usage.get("workspace_id", "")
for period in ["rolling", "weekly", "monthly"]:
p = usage.get(period)
if p:
entry[period] = {
"usage_percent": p.get("usage_percent"),
"reset_in_sec": p.get("reset_in_sec"),
"status": p.get("status", "unknown"),
}
entry["session_expired"] = usage.get("session_expired", False)
entry["last_update"] = usage.get("last_update_iso", "")
keys_out.append(entry)
return jsonify({
"ok": True,
"count": len(keys_out),
"keys": keys_out,
})
except Exception as e:
return jsonify({"ok": False, "error": str(e), "keys": []})
# ── Auto-collect timer (every 5 min, keeps cookies alive) ──
_USAGE_AUTO_INTERVAL = 300