Archived
chore(async-infra): 异步基础层 + 工具链 + 清理
异步基础层(core/):
- db.py aiosqlite + WAL:读路径无锁并发、写路径 asyncio.Lock 串行,
busy_timeout 自旋——实现「读写同时进行」(旧实现用 RLock 全读串行)
- http_client.py aiohttp 连接池 + 有界重试(5xx 重试 / 4xx 不重试)+
响应体上限 + 流式接口;按事件循环隔离 session(支持迁移期双 loop)
工具链:
- pyproject.toml ruff(E/F/W/I/B/UP/C4/ASYNC/S/RUF) + pyright(basic) + pytest(asyncio auto)
- requirements-fastapi.txt FastAPI/aiohttp/aiosqlite/aiofiles 等目标栈
- requirements-dev.txt 开发依赖(pytest/ruff/pyright)
清理:删除无用脚本 _csscheck.py 与产物标记 _css_ok.txt/_pkg_ok.txt,同步 .gitignore
验证:pytest 10/10(含「写 200 条同时 4 读协程零异常」并发用例);
ruff All checks passed;pyright 0 errors。
This commit is contained in:
1 parent
41356e89c4
commit
9f56f68b66
16 files changed
+706
-42
No files matched your search
+4
-4
@@ -5,16 +5,16 @@
|
||||
改为**启动时注入**(`init_secret_key`),从而解除对本模块对 Flask app 的依赖;
|
||||
签名/校验算法与口径保持逐字一致,迁移期新旧应用共用同一密钥即可互认 token。
|
||||
"""
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import secrets
|
||||
import time
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
|
||||
from core.config import AUDIO_HOST_MARKS, AUDIO_TOKEN_TTL, AUDIO_URL_KEYS
|
||||
|
||||
|
||||
# 由应用启动时注入(来源:auth_system.get_secret_key() → app.secret_key)
|
||||
_SECRET_KEY: bytes = b''
|
||||
|
||||
@@ -36,11 +36,11 @@ def sign_payload(payload: str) -> str:
|
||||
def make_audio_token(url: str) -> str:
|
||||
exp = int(time.time()) + AUDIO_TOKEN_TTL
|
||||
nonce = secrets.token_hex(4)
|
||||
payload = base64.urlsafe_b64encode(f'{exp}|{nonce}|{url}'.encode('utf-8')).decode().rstrip('=')
|
||||
payload = base64.urlsafe_b64encode(f'{exp}|{nonce}|{url}'.encode()).decode().rstrip('=')
|
||||
return payload + '.' + sign_payload(payload)
|
||||
|
||||
|
||||
def verify_audio_token(token: str) -> Optional[str]:
|
||||
def verify_audio_token(token: str) -> str | None:
|
||||
try:
|
||||
payload, sig = token.rsplit('.', 1)
|
||||
if not hmac.compare_digest(sig, sign_payload(payload)):
|
||||
|
||||
Reference in new issue
Block a user