| """ |
| 配置路由模块 - 处理 /config/* 相关的HTTP请求 |
| """ |
|
|
| from fastapi import APIRouter, Depends, HTTPException |
| from fastapi.responses import JSONResponse |
|
|
| import config |
| from log import log |
| from src.keeplive import keepalive_service |
| from src.models import ConfigSaveRequest |
| from src.storage_adapter import get_storage_adapter |
| from src.utils import verify_panel_token |
| from .utils import get_env_locked_keys |
|
|
|
|
| |
| router = APIRouter(prefix="/config", tags=["config"]) |
|
|
|
|
| @router.get("/get") |
| async def get_config(token: str = Depends(verify_panel_token)): |
| """获取当前配置""" |
| try: |
|
|
|
|
| |
| current_config = {} |
|
|
| |
| current_config["code_assist_endpoint"] = await config.get_code_assist_endpoint() |
| current_config["credentials_dir"] = await config.get_credentials_dir() |
| current_config["proxy"] = await config.get_proxy_config() or "" |
|
|
| |
| current_config["oauth_proxy_url"] = await config.get_oauth_proxy_url() |
| current_config["googleapis_proxy_url"] = await config.get_googleapis_proxy_url() |
| current_config["resource_manager_api_url"] = await config.get_resource_manager_api_url() |
| current_config["service_usage_api_url"] = await config.get_service_usage_api_url() |
| current_config["antigravity_api_url"] = await config.get_antigravity_api_url() |
|
|
| |
| current_config["auto_ban_enabled"] = await config.get_auto_ban_enabled() |
| current_config["auto_ban_error_codes"] = await config.get_auto_ban_error_codes() |
|
|
| |
| current_config["retry_429_max_retries"] = await config.get_retry_429_max_retries() |
| current_config["retry_429_enabled"] = await config.get_retry_429_enabled() |
| current_config["retry_429_interval"] = await config.get_retry_429_interval() |
| |
| current_config["anti_truncation_max_attempts"] = await config.get_anti_truncation_max_attempts() |
|
|
| |
| current_config["compatibility_mode_enabled"] = await config.get_compatibility_mode_enabled() |
|
|
| |
| current_config["return_thoughts_to_frontend"] = await config.get_return_thoughts_to_frontend() |
|
|
| |
| current_config["antigravity_stream2nostream"] = await config.get_antigravity_stream2nostream() |
| current_config["antigravity_switch_credential_enabled"] = await config.get_antigravity_switch_credential_enabled() |
|
|
| |
| current_config["keepalive_url"] = await config.get_keepalive_url() |
| current_config["keepalive_interval"] = await config.get_keepalive_interval() |
|
|
| |
| current_config["host"] = await config.get_server_host() |
| current_config["port"] = await config.get_server_port() |
| current_config["api_password"] = await config.get_api_password() |
| current_config["panel_password"] = await config.get_panel_password() |
| current_config["password"] = await config.get_server_password() |
|
|
| |
| storage_adapter = await get_storage_adapter() |
| storage_config = await storage_adapter.get_all_config() |
|
|
| |
| env_locked_keys = get_env_locked_keys() |
|
|
| |
| for key, value in storage_config.items(): |
| if key not in env_locked_keys: |
| current_config[key] = value |
|
|
| return JSONResponse(content={"config": current_config, "env_locked": list(env_locked_keys)}) |
|
|
| except Exception as e: |
| log.error(f"获取配置失败: {e}") |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|
|
|
| @router.post("/save") |
| async def save_config(request: ConfigSaveRequest, token: str = Depends(verify_panel_token)): |
| """保存配置""" |
| try: |
|
|
| new_config = request.config |
|
|
| log.debug(f"收到的配置数据: {list(new_config.keys())}") |
| log.debug(f"收到的password值: {new_config.get('password', 'NOT_FOUND')}") |
|
|
| |
| if "retry_429_max_retries" in new_config: |
| if ( |
| not isinstance(new_config["retry_429_max_retries"], int) |
| or new_config["retry_429_max_retries"] < 0 |
| ): |
| raise HTTPException(status_code=400, detail="最大429重试次数必须是大于等于0的整数") |
|
|
| if "retry_429_enabled" in new_config: |
| if not isinstance(new_config["retry_429_enabled"], bool): |
| raise HTTPException(status_code=400, detail="429重试开关必须是布尔值") |
|
|
| |
| if "retry_429_interval" in new_config: |
| try: |
| interval = float(new_config["retry_429_interval"]) |
| if interval < 0.01 or interval > 10: |
| raise HTTPException(status_code=400, detail="429重试间隔必须在0.01-10秒之间") |
| except (ValueError, TypeError): |
| raise HTTPException(status_code=400, detail="429重试间隔必须是有效的数字") |
|
|
| if "anti_truncation_max_attempts" in new_config: |
| if ( |
| not isinstance(new_config["anti_truncation_max_attempts"], int) |
| or new_config["anti_truncation_max_attempts"] < 1 |
| or new_config["anti_truncation_max_attempts"] > 10 |
| ): |
| raise HTTPException( |
| status_code=400, detail="抗截断最大重试次数必须是1-10之间的整数" |
| ) |
|
|
| if "compatibility_mode_enabled" in new_config: |
| if not isinstance(new_config["compatibility_mode_enabled"], bool): |
| raise HTTPException(status_code=400, detail="兼容性模式开关必须是布尔值") |
|
|
| if "return_thoughts_to_frontend" in new_config: |
| if not isinstance(new_config["return_thoughts_to_frontend"], bool): |
| raise HTTPException(status_code=400, detail="思维链返回开关必须是布尔值") |
|
|
| if "antigravity_stream2nostream" in new_config: |
| if not isinstance(new_config["antigravity_stream2nostream"], bool): |
| raise HTTPException(status_code=400, detail="Antigravity流式转非流式开关必须是布尔值") |
|
|
| if "antigravity_switch_credential_enabled" in new_config: |
| if not isinstance(new_config["antigravity_switch_credential_enabled"], bool): |
| raise HTTPException(status_code=400, detail="Antigravity切换凭证开关必须是布尔值") |
|
|
| |
| if "keepalive_url" in new_config: |
| if not isinstance(new_config["keepalive_url"], str): |
| raise HTTPException(status_code=400, detail="保活URL必须是字符串") |
|
|
| if "keepalive_interval" in new_config: |
| try: |
| interval = int(new_config["keepalive_interval"]) |
| if interval < 5 or interval > 86400: |
| raise HTTPException(status_code=400, detail="保活间隔必须在 5-86400 秒之间") |
| new_config["keepalive_interval"] = interval |
| except (ValueError, TypeError): |
| raise HTTPException(status_code=400, detail="保活间隔必须是有效整数") |
| |
| if "host" in new_config: |
| if not isinstance(new_config["host"], str) or not new_config["host"].strip(): |
| raise HTTPException(status_code=400, detail="服务器主机地址不能为空") |
|
|
| if "port" in new_config: |
| if ( |
| not isinstance(new_config["port"], int) |
| or new_config["port"] < 1 |
| or new_config["port"] > 65535 |
| ): |
| raise HTTPException(status_code=400, detail="端口号必须是1-65535之间的整数") |
|
|
| if "api_password" in new_config: |
| if not isinstance(new_config["api_password"], str): |
| raise HTTPException(status_code=400, detail="API访问密码必须是字符串") |
|
|
| if "panel_password" in new_config: |
| if not isinstance(new_config["panel_password"], str): |
| raise HTTPException(status_code=400, detail="控制面板密码必须是字符串") |
|
|
| if "password" in new_config: |
| if not isinstance(new_config["password"], str): |
| raise HTTPException(status_code=400, detail="访问密码必须是字符串") |
|
|
| |
| env_locked_keys = get_env_locked_keys() |
|
|
| |
| storage_adapter = await get_storage_adapter() |
| for key, value in new_config.items(): |
| if key not in env_locked_keys: |
| await storage_adapter.set_config(key, value) |
| if key in ("password", "api_password", "panel_password"): |
| log.debug(f"设置{key}字段为: {value}") |
|
|
| |
| await config.reload_config() |
|
|
| |
| keepalive_keys = {"keepalive_url", "keepalive_interval"} |
| if keepalive_keys & set(new_config.keys()): |
| try: |
| await keepalive_service.restart() |
| except Exception as e: |
| log.warning(f"重启保活服务失败: {e}") |
|
|
| |
| test_api_password = await config.get_api_password() |
| test_panel_password = await config.get_panel_password() |
| test_password = await config.get_server_password() |
| log.debug(f"保存后立即读取的API密码: {test_api_password}") |
| log.debug(f"保存后立即读取的面板密码: {test_panel_password}") |
| log.debug(f"保存后立即读取的通用密码: {test_password}") |
|
|
| |
| response_data = { |
| "message": "配置保存成功", |
| "saved_config": {k: v for k, v in new_config.items() if k not in env_locked_keys}, |
| } |
|
|
| return JSONResponse(content=response_data) |
|
|
| except HTTPException: |
| raise |
| except Exception as e: |
| log.error(f"保存配置失败: {e}") |
| raise HTTPException(status_code=500, detail=str(e)) |
|
|