refactor(core): 抽出框架无关核心层 core/,为 FastAPI 迁移铺路

第一步模块拆分(纯搬运,零行为变化):
- 新增 core/ 包:config(常量/配置) + state(运行时状态) + utils(纯函数) + security(音频签名)
- main.py 改为从 core 导入并以原下划线名再导出,250+ 既有调用点零改动

关键设计:
- 状态全部原地修改,import 即共享同一对象(21 项身份断言 + 10 项冒烟全绿)
- 音频签名密钥由启动时 _init_audio_secret(app.secret_key) 注入,
  解除 core.security 对 Flask app 的依赖,新老应用可互认 token

验证:py_compile 通过;冒烟 10/10 PASS;对象身份 22/22 PASS;
waitress 真实启动 /health 200 version=2.4.0。main.py 减 229 行。
This commit is contained in:
snowy-yang committed 2026-09-26 00:16:04 +08:00
1 parent d209af847a
commit c2a8da3e43
6 files changed
+405 -227

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
"""进程内运行时状态(框架无关)。
自 main.py 原样迁出:这些容器全部**原地修改**(永不重新绑定),因此
`from core.state import DOWNLOAD_TASKS` 与 main 内的旧引用共享同一对象,
搬移不改变任何并发行为。
注意:这些状态**仅存于进程内存**,重启即丢(任务记录/限流桶/统计/缓存);
持久数据(账本/用户/设置)在 SQLite(auth_system)。集中在此以便
Flask/FastAPI 迁移期共用,并为后续封装成带锁的单例(State 对象)留出唯一入口。
依赖仅限标准库 threading/collections——任何下载器/HTTP 相关对象
(如批量打包信号量)不放在这里,随对应服务模块搬迁。
"""
import collections
import threading
from typing import Any, Dict, List
# ============ 短链展开结果缓存 ============
# 用户反复解析同一分享链接不再重复请求 163cn.tv(有界防膨胀)
SHORTLINK_CACHE: Dict[str, str] = {}
SHORTLINK_CACHE_LOCK = threading.Lock()
# ============ 公网限流(按 IP 滑动窗口,防刷防爆破) ============
RATE_BUCKETS = {}
RATE_LOCK = threading.Lock()
# ============ 批量打包排队估算 ============
# 最近完成批次(成功打包过)的耗时记录,用于估算排队用户的预计等待时间
BATCH_DURATIONS = collections.deque(maxlen=10)
BATCH_DURATIONS_LOCK = threading.Lock()
# ============ 下载任务表 ============
# (批量打包 + 单曲下载统一):task_id -> {type, total, done, failed, status, start, msg, cancel, pause, device_id, result, params}
# 前端通过 /api/batch_progress 轮询进度,支持取消;完成后文件按 35 分钟保留期清理
DOWNLOAD_TASKS: Dict[str, Dict[str, Any]] = {}
DOWNLOAD_TASKS_LOCK = threading.Lock()
# ============ 设备在线心跳 ============
# device_id -> 最近心跳时间。心跳超时(PAUSE_AFTER_SECONDS)未上线的设备,其批量任务
# 自动暂停让出排队名额;超时超过 CANCEL_AFTER_SECONDS(30 分钟)则自动取消任务并删文件
DEVICE_LAST_SEEN: Dict[str, float] = {}
DEVICE_LAST_SEEN_LOCK = threading.Lock()
# ============ 接口请求统计 ============
REQUEST_STATS: Dict[str, Dict[str, Any]] = {}
STATS_LOCK = threading.Lock()
# 用户解析/下载操作记录(IP);仅保留最近 2000 条
REQ_LOG: List[Dict[str, Any]] = []
# ============ 上游探测缓存 ============
# 全局账号 MUSIC_U(5 分钟缓存;后台重新扫码后自动跟随新值)
GLOBAL_MUSIC_U_CACHE = {'v': None, 'ts': 0.0}
# 服务器网易云账号昵称缓存(10 分钟):非管理员可见响应中遮蔽真实昵称
SERVER_NICK_CACHE = {'nick': None, 'ts': 0.0}
SERVER_NICK_LOCK = threading.Lock() # 第 91 条(P3-9):刷新单飞锁,防并发重复打上游
VIP_PROBE_LOCK = threading.Lock() # 第 100 条:音质探测单飞锁(有界等待)
# 全局账号 VIP 探测缓存(5 分钟):probe 一次要打 8 次网易云接口,
# 公网下账号栏高频刷新会连累服务器账号触发风控。
VIP_CACHE = {'data': None, 'ts': 0.0}
VIP_USER_CACHE = {} # user 路径按 cookie 哈希的 5 分钟缓存