v1.0.0提交

This commit is contained in:
2026-03-31 16:03:55 +08:00
parent 5f3945ae03
commit dce843fd9d
25 changed files with 1702 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PerToolBox Server - 热度统计路由
Copyright (C) 2024 Sea Network Technology Studio
Author: Canglan <admin@sea-studio.top>
License: AGPL v3
"""
from datetime import datetime
from fastapi import APIRouter
from ...utils.redis_client import redis_client
from ...models import ToolStatsTotal
from ...dependencies import DbDependency
from ...middleware.rate_limit import rate_limit
router = APIRouter(prefix="/api/v1", tags=["stats"])
# 预定义工具名称(对应前端页面)
TOOL_NAMES = [
"todos", "notes", "password", "qrcode",
"crypto_hash", "crypto_base64", "crypto_url", "crypto_aes", "json"
]
@router.post("/tool/usage")
@rate_limit(requests=20, period=60)
async def record_usage(tool_name: str, db: DbDependency):
"""记录页面访问次数(热度)"""
if tool_name not in TOOL_NAMES:
raise HTTPException(status_code=400, detail="无效的工具名")
today = datetime.now().strftime("%Y-%m-%d")
today_key = f"tool:stats:today:{tool_name}:{today}"
total_key = f"tool:stats:total:{tool_name}"
# 增加今日计数设置48小时过期
today_count = redis_client.incr(today_key)
redis_client.expire(today_key, 48 * 3600)
# 增加总计数
total_count = redis_client.incr(total_key)
# 异步更新 MySQL可选这里简单处理
# 实际可改为定时任务同步,此处为简化,直接更新
stats = db.query(ToolStatsTotal).filter(ToolStatsTotal.tool_name == tool_name).first()
if stats:
stats.total_count = total_count
else:
stats = ToolStatsTotal(tool_name=tool_name, total_count=total_count)
db.add(stats)
db.commit()
return {"success": True}
@router.get("/tool/stats")
@rate_limit(requests=100, period=60)
async def get_stats(db: DbDependency):
"""获取所有工具的今日/总访问次数"""
today = datetime.now().strftime("%Y-%m-%d")
result = {}
for tool_name in TOOL_NAMES:
today_key = f"tool:stats:today:{tool_name}:{today}"
total_key = f"tool:stats:total:{tool_name}"
today_count = redis_client.get(today_key)
total_count = redis_client.get(total_key)
if total_count is None:
# 从 MySQL 读取
stats = db.query(ToolStatsTotal).filter(ToolStatsTotal.tool_name == tool_name).first()
total_count = stats.total_count if stats else 0
else:
total_count = int(total_count)
result[tool_name] = {
"today": int(today_count) if today_count else 0,
"total": total_count
}
return result