From db2c94fd191a7ac2bdab025a3a51de40a05015b3 Mon Sep 17 00:00:00 2001 From: Lan Date: Fri, 13 Feb 2026 23:45:44 +0800 Subject: [PATCH] feat: add configuration management with async settings refresh and middleware integration --- core/config.py | 21 +++++++++++++++++++++ core/tasks.py | 9 ++++++--- main.py | 12 ++++++++---- 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 core/config.py diff --git a/core/config.py b/core/config.py new file mode 100644 index 0000000..a2dd349 --- /dev/null +++ b/core/config.py @@ -0,0 +1,21 @@ +from apps.base.models import KeyValue +from apps.base.utils import ip_limit +from core.settings import DEFAULT_CONFIG, settings + + +async def ensure_settings_row() -> None: + await KeyValue.get_or_create(key="settings", defaults={"value": DEFAULT_CONFIG}) + + +def _sync_ip_limits() -> None: + ip_limit["error"].minutes = settings.errorMinute + ip_limit["error"].count = settings.errorCount + ip_limit["upload"].minutes = settings.uploadMinute + ip_limit["upload"].count = settings.uploadCount + + +async def refresh_settings() -> None: + """从数据库读取最新配置并应用到运行时。""" + config_record = await KeyValue.filter(key="settings").first() + settings.user_config = config_record.value if config_record and config_record.value else {} + _sync_ip_limits() diff --git a/core/tasks.py b/core/tasks.py index c595ae2..1347c0d 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -11,15 +11,17 @@ from tortoise.expressions import Q from apps.base.models import FileCodes, UploadChunk from apps.base.utils import ip_limit, get_chunk_file_path_name +from core.config import refresh_settings from core.settings import settings, data_root from core.storage import FileStorageInterface, storages from core.utils import get_now async def delete_expire_files(): - file_storage: FileStorageInterface = storages[settings.file_storage]() while True: try: + await refresh_settings() + file_storage: FileStorageInterface = storages[settings.file_storage]() # 遍历 share目录下的所有文件夹,删除空的文件夹,并判断父目录是否为空,如果为空也删除 if settings.file_storage == "local": for root, dirs, files in os.walk(f"{data_root}/share/data"): @@ -46,10 +48,11 @@ async def delete_expire_files(): async def clean_incomplete_uploads(): - file_storage: FileStorageInterface = storages[settings.file_storage]() - expire_hours = getattr(settings, "chunk_expire_hours", 24) while True: try: + await refresh_settings() + file_storage: FileStorageInterface = storages[settings.file_storage]() + expire_hours = getattr(settings, "chunk_expire_hours", 24) now = await get_now() expire_time = now - datetime.timedelta(hours=expire_hours) expired_sessions = await UploadChunk.filter( diff --git a/main.py b/main.py index b3ec45f..fee4d6c 100644 --- a/main.py +++ b/main.py @@ -17,6 +17,7 @@ from apps.admin.views import admin_api from apps.base.models import KeyValue from apps.base.utils import ip_limit from apps.base.views import share_api, chunk_api, presign_api +from core.config import ensure_settings_row, refresh_settings from core.database import db_startup_lock, get_db_config, init_db from core.logger import logger from core.response import APIResponse @@ -58,13 +59,11 @@ async def lifespan(app: FastAPI): async def load_config(): - user_config, _ = await KeyValue.get_or_create( - key="settings", defaults={"value": DEFAULT_CONFIG} - ) + await ensure_settings_row() await KeyValue.update_or_create( key="sys_start", defaults={"value": int(time.time() * 1000)} ) - settings.user_config = user_config.value + await refresh_settings() await migrate_password_to_hash() @@ -87,6 +86,11 @@ async def migrate_password_to_hash(): app = FastAPI(lifespan=lifespan) +@app.middleware("http") +async def refresh_settings_middleware(request, call_next): + await refresh_settings() + return await call_next(request) + app.add_middleware( CORSMiddleware, allow_origins=["*"],