81 lines
2.6 KiB
Python
81 lines
2.6 KiB
Python
#!/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 |