File size: 10,418 Bytes
96d34f2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | """
配置路由模块 - 处理 /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:
# 读取当前配置(包括环境变量和TOML文件中的配置)
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()
# 429重试配置
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()
# Antigravity流式转非流式配置
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))
|