187 lines
6.2 KiB
Python
187 lines
6.2 KiB
Python
import logging
|
||
import time
|
||
from typing import Any, Dict, Tuple
|
||
from fastapi import APIRouter, Query, Body, Path, BackgroundTasks
|
||
from fastapi.background import P
|
||
from tortoise.expressions import Q
|
||
|
||
from app.controllers.token import token_controller
|
||
from app.schemas.base import Fail, Success, SuccessExtra
|
||
from app.schemas.token import BossTokenUpdate,BossTokenCreate
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
token_router = APIRouter()
|
||
|
||
# 简单内存缓存:key 为查询参数组合,value 为 (缓存时间戳, 响应数据)
|
||
_TOKENS_CACHE: Dict[Tuple[Any, Any, int, int], Tuple[float, Dict[str, Any]]] = {}
|
||
_CACHE_TTL_SECONDS: int =60
|
||
|
||
|
||
@token_router.get("/tokens", summary="获取Boss Token列表")
|
||
async def list_boss_tokens(
|
||
page: int = Query(1, description="页码"),
|
||
page_size: int = Query(10, description="每页数量"),
|
||
status: int = Query(None, description="状态筛选"),
|
||
):
|
||
"""获取Boss Token列表"""
|
||
from tortoise.expressions import Q
|
||
|
||
q = Q()
|
||
if status is not None:
|
||
q &= Q(status=status)
|
||
|
||
total, token_objs = await token_controller.get_tokens(page=page, page_size=page_size, search=q)
|
||
data = [await obj.to_dict() for obj in token_objs]
|
||
|
||
return SuccessExtra(data=data, total=total, page=page, page_size=page_size)
|
||
|
||
|
||
@token_router.get("/tokens/{token_id}", summary="获取Boss Token详情")
|
||
async def get_boss_token(
|
||
token_id: int = Path(..., description="Token ID"),
|
||
):
|
||
"""获取Boss Token详情"""
|
||
token_obj = await token_controller.get_token(token_id)
|
||
token_dict = await token_obj.to_dict()
|
||
return Success(data=token_dict)
|
||
|
||
|
||
@token_router.post("/tokens", summary="创建Boss Token")
|
||
async def create_boss_token(
|
||
token_data: BossTokenCreate = Body(..., description="Token数据"),
|
||
):
|
||
"""创建Boss Token"""
|
||
await token_controller.create_token(token_data)
|
||
# 清空缓存,确保新数据立即生效
|
||
_TOKENS_CACHE.clear()
|
||
return Success(msg="创建成功")
|
||
|
||
|
||
@token_router.put("/tokens/{token_id}", summary="更新Boss Token")
|
||
async def update_boss_token(
|
||
token_id: int = Path(..., description="Token ID"),
|
||
token_data: BossTokenUpdate = Body(..., description="Token数据"),
|
||
):
|
||
"""更新Boss Token"""
|
||
await token_controller.update_token(token_id, token_data)
|
||
# 清空缓存,确保更新立即生效
|
||
_TOKENS_CACHE.clear()
|
||
return Success(msg="更新成功")
|
||
|
||
|
||
@token_router.delete("/tokens/{token_id}", summary="删除Boss Token")
|
||
async def delete_boss_token(
|
||
token_id: int = Path(..., description="Token ID"),
|
||
):
|
||
"""删除Boss Token"""
|
||
await token_controller.delete_token(token_id)
|
||
# 清空缓存,确保删除立即生效
|
||
_TOKENS_CACHE.clear()
|
||
return Success(msg="删除成功")
|
||
|
||
|
||
@token_router.post("/tokens/cache/clear", summary="强制清除Token缓存")
|
||
async def clear_token_cache():
|
||
"""强制清除Token列表缓存"""
|
||
global _TOKENS_CACHE
|
||
cache_size = len(_TOKENS_CACHE)
|
||
_TOKENS_CACHE.clear()
|
||
logger.info(f"手动清除Token缓存,清除了 {cache_size} 条缓存数据")
|
||
return Success(msg=f"成功清除 {cache_size} 条Token缓存")
|
||
from typing import Optional, Dict, Any
|
||
from fastapi import APIRouter, Query, HTTPException
|
||
from tortoise.transactions import in_transaction
|
||
from app.models.token import BossToken
|
||
from app.schemas.base import Success
|
||
|
||
token_router = APIRouter()
|
||
|
||
|
||
@token_router.get("/tokens")
|
||
async def list_tokens(
|
||
wt2: Optional[str] = Query(None),
|
||
mpt: Optional[str] = Query(None),
|
||
page: int = Query(1, ge=1),
|
||
page_size: int = Query(10, ge=1, le=200),
|
||
):
|
||
"""获取 BossToken 列表,带两小时内存缓存。
|
||
|
||
Args:
|
||
wt2 (Optional[str]): 按 `wt2` 模糊匹配。
|
||
mpt (Optional[str]): 按 `mpt` 模糊匹配。
|
||
page (int): 页码。
|
||
page_size (int): 每页数量。
|
||
|
||
Returns:
|
||
Dict[str, Any]: 响应字典,包含 `code`、`data`、`total`。
|
||
"""
|
||
cache_key: Tuple[Any, Any, int, int] = (wt2, mpt, page, page_size)
|
||
now = time.monotonic()
|
||
cached = _TOKENS_CACHE.get(cache_key)
|
||
if cached and (now - cached[0] < _CACHE_TTL_SECONDS):
|
||
return cached[1]
|
||
|
||
qs = BossToken.all()
|
||
if wt2:
|
||
qs = qs.filter(wt2__icontains=wt2)
|
||
if mpt:
|
||
qs = qs.filter(mpt__icontains=mpt)
|
||
total = await qs.count()
|
||
items = await qs.order_by("-id").offset((page - 1) * page_size).limit(page_size)
|
||
data = [
|
||
{
|
||
"id": item.id,
|
||
"wt2": item.wt2,
|
||
"mpt": item.mpt,
|
||
"is_active": item.is_active,
|
||
"failed_count": item.failed_count,
|
||
"last_used_time": item.last_used_time,
|
||
"created_at": item.created_at,
|
||
}
|
||
for item in items
|
||
]
|
||
resp: Dict[str, Any] = {"code": 200, "data": data, "total": total}
|
||
_TOKENS_CACHE[cache_key] = (now, resp)
|
||
return resp
|
||
|
||
|
||
@token_router.post("/tokens")
|
||
async def create_token(payload: Dict[str, Any]):
|
||
try:
|
||
async with in_transaction():
|
||
item = await BossToken.create(
|
||
wt2=payload.get("wt2"),
|
||
mpt=payload.get("mpt"),
|
||
is_active=bool(payload.get("is_active", True)),
|
||
failed_count=int(payload.get("failed_count", 0)),
|
||
last_used_time=payload.get("last_used_time"),
|
||
)
|
||
_TOKENS_CACHE.clear()
|
||
return Success(data={"id": item.id})
|
||
except Exception as e:
|
||
raise HTTPException(status_code=400, detail=str(e))
|
||
|
||
|
||
@token_router.put("/tokens/{id}")
|
||
async def update_token(id: int, payload: Dict[str, Any]):
|
||
token_id = id
|
||
item = await BossToken.get_or_none(id=token_id)
|
||
if not item:
|
||
raise HTTPException(status_code=404, detail="Token not found")
|
||
for field in ["wt2", "mpt", "is_active", "failed_count", "last_used_time"]:
|
||
if field in payload:
|
||
setattr(item, field, payload[field])
|
||
await item.save()
|
||
_TOKENS_CACHE.clear()
|
||
return Success(data={"id": item.id})
|
||
|
||
|
||
@token_router.delete("/tokens/{token_id}")
|
||
async def delete_token(token_id: int):
|
||
item = await BossToken.get_or_none(id=token_id)
|
||
if not item:
|
||
raise HTTPException(status_code=404, detail="Token not found")
|
||
await item.delete()
|
||
_TOKENS_CACHE.clear()
|
||
return Success(data={"id": token_id}) |