Procházet zdrojové kódy

add remote control

welin před 3 měsíci
rodič
revize
8abb26aca1

+ 122 - 128
app/api/router.py

@@ -8,7 +8,7 @@ from app.core.logger import logger
 from app.core.config import settings
 from fastapi import APIRouter, Request, Response, Query, Depends, Body, UploadFile, File, HTTPException
 from fastapi.responses import RedirectResponse
-from sqlalchemy.orm import Session
+from sqlalchemy.ext.asyncio import AsyncSession
 from app.utils.redis_utils import redis_qpush
 from app.utils.validation_utils import validate_user_inputs
 from app.core.redis import get_redis_client
@@ -99,61 +99,55 @@ async def ping():
 # Docker 远程控制 (预配置服务器)
 # -----------------------
 
-def get_server_config(server_id: str) -> RemoteServerConfig:
-    """从配置中获取服务器连接信息"""
-    if server_id not in settings.remote_servers:
-        raise HTTPException(status_code=404, detail=f"Server {server_id} not found in configuration")
-    
-    cfg = settings.remote_servers[server_id]
-    return RemoteServerConfig(**cfg)
-
 @admin_required_router.get("/remote/servers", summary="获取所有预配置服务器", tags=["Docker远程控制"], response_model=ApiResponse[ServerListOut])
-async def list_remote_servers():
+async def list_remote_servers(db: AsyncSession = Depends(get_db)):
+    from app.services.remote_server_service import RemoteServerService
+    servers_db = await RemoteServerService.get_all(db)
     servers = [
-        ServerConfigItem(id=sid, name=sid, host=info["host"])
-        for sid, info in settings.remote_servers.items()
+        ServerConfigItem(id=s.server_id, name=s.name, host=s.host)
+        for s in servers_db
     ]
     return success(data=ServerListOut(servers=servers))
 
 @admin_required_router.post("/remote/server/docker/status", summary="获取预配置服务器容器状态", tags=["Docker远程控制"], response_model=ApiResponse[DockerStatusOut])
-async def server_docker_status(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_status(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     res = await DockerRemoteService.get_container_status(config)
     return success(data=DockerStatusOut(containers=res))
 
 @admin_required_router.post("/remote/server/docker/up", summary="启动预配置服务器Docker Compose", tags=["Docker远程控制"], response_model=ApiResponse[bool])
-async def server_docker_up(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_up(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     res = await DockerRemoteService.docker_compose_up(config, request.services)
     return success(data=res)
 
 @admin_required_router.post("/remote/server/docker/down", summary="停止预配置服务器Docker Compose", tags=["Docker远程控制"], response_model=ApiResponse[bool])
-async def server_docker_down(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_down(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     res = await DockerRemoteService.docker_compose_down(config, request.services)
     return success(data=res)
 
 @admin_required_router.post("/remote/server/docker/restart", summary="重启预配置服务器容器", tags=["Docker远程控制"], response_model=ApiResponse[bool])
-async def server_docker_restart(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_restart(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     res = await DockerRemoteService.docker_restart(config, request.container_name)
     return success(data=res)
 
 @admin_required_router.post("/remote/server/docker/start", summary="启动预配置服务器容器", tags=["Docker远程控制"], response_model=ApiResponse[bool])
-async def server_docker_start(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_start(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     res = await DockerRemoteService.docker_start(config, request.container_name)
     return success(data=res)
 
 @admin_required_router.post("/remote/server/docker/stop", summary="停止预配置服务器容器", tags=["Docker远程控制"], response_model=ApiResponse[bool])
-async def server_docker_stop(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_stop(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     res = await DockerRemoteService.docker_stop(config, request.container_name)
     return success(data=res)
 
 @admin_required_router.post("/remote/server/docker/logs", summary="查看预配置服务器容器日志", tags=["Docker远程控制"], response_model=ApiResponse[DockerLogsOut])
-async def server_docker_logs(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_logs(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     # 构造 DockerLogsRequest
     log_req = DockerLogsRequest(
         **config.model_dump(),
@@ -165,14 +159,14 @@ async def server_docker_logs(request: RemoteActionRequest):
     return success(data=DockerLogsOut(logs=res))
 
 @admin_required_router.post("/remote/server/config/read", summary="读取预配置服务器配置文件", tags=["Docker远程控制"], response_model=ApiResponse[Dict[str, Any]])
-async def server_docker_config_read(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_config_read(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     res = await DockerRemoteService.read_config(config, request.config_file)
     return success(data={"config": res})
 
 @admin_required_router.post("/remote/server/config/update", summary="更新预配置服务器配置文件", tags=["Docker远程控制"], response_model=ApiResponse[bool])
-async def server_docker_config_update(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_config_update(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     # 构造 ConfigUpdateRequest
     update_req = ConfigUpdateRequest(
         **config.model_dump(),
@@ -184,14 +178,14 @@ async def server_docker_config_update(request: RemoteActionRequest):
     return success(data=res)
 
 @admin_required_router.post("/remote/server/log/list", summary="列出预配置服务器日志文件", tags=["Docker远程控制"], response_model=ApiResponse[LogListOut])
-async def server_docker_logs_list(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_logs_list(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     res = await DockerRemoteService.list_logs(config)
     return success(data=LogListOut(log_files=res))
 
 @admin_required_router.post("/remote/server/log/read", summary="读取预配置服务器日志文件内容", tags=["Docker远程控制"], response_model=ApiResponse[LogReadOut])
-async def server_docker_logs_read(request: RemoteActionRequest):
-    config = get_server_config(request.server_id)
+async def server_docker_logs_read(request: RemoteActionRequest, db: AsyncSession = Depends(get_db)):
+    config = await DockerRemoteService.get_server_config(db, request.server_id)
     # 构造 LogReadRequest
     read_req = LogReadRequest(
         **config.model_dump(),
@@ -336,36 +330,36 @@ async def troov_del_prob(
     return success(data=obj)
 
 @admin_required_router.post("/dynamic-configurations", summary="创建动态配置", tags=["动态配置"], response_model=ApiResponse[ConfigurationOut])
-async def dynamic_config_create(config_in: ConfigurationCreate, db: Session = Depends(get_db)):
+async def dynamic_config_create(config_in: ConfigurationCreate, db: AsyncSession = Depends(get_db)):
     obj = await ConfigurationService.create(db, config_in)
     return success(data=obj)
 
 @admin_required_router.get("/dynamic-configurations/all", summary="读取所有动态配置", tags=["动态配置"], response_model=ApiResponse[List[ConfigurationOut]])
-async def dynamic_config_get_all(db: Session = Depends(get_db)):
+async def dynamic_config_get_all(db: AsyncSession = Depends(get_db)):
     obj = await ConfigurationService.get_all(db)
     return success(data=obj)
     
 @admin_required_router.get("/dynamic-configurations/key/{config_key}", summary="根据Key读取动态配置", tags=["动态配置"], response_model=ApiResponse[ConfigurationOut])
-async def dynamic_config_get_by_key(config_key: str, db: Session = Depends(get_db)):
+async def dynamic_config_get_by_key(config_key: str, db: AsyncSession = Depends(get_db)):
     config = await ConfigurationService.get_by_key(db, config_key)
     return success(data=config)
 
 
 @admin_required_router.put("/dynamic-configurations/key/{config_key}", summary="根据Key更新动态配置", tags=["动态配置"], response_model=ApiResponse[ConfigurationOut])
-async def dynamic_config_update_by_key(config_key: str, config_in: ConfigurationUpdate, db: Session = Depends(get_db)):
+async def dynamic_config_update_by_key(config_key: str, config_in: ConfigurationUpdate, db: AsyncSession = Depends(get_db)):
     config = await ConfigurationService.update_by_key(db, config_key, config_in)
     return success(data=config)
 
 
 @admin_required_router.delete("/dynamic-configurations/key/{config_key}", summary="根据Key删除动态配置", tags=["动态配置"], response_model=ApiResponse[ConfigurationOut])
-async def dynamic_config_delete_by_key(config_key: str, db: Session = Depends(get_db)):
+async def dynamic_config_delete_by_key(config_key: str, db: AsyncSession = Depends(get_db)):
     config = await ConfigurationService.delete_by_key(db, config_key)
     return success(data=config)
 
 @admin_required_router.post("/http-session", summary="创建http session", tags=["会话管理"],response_model=ApiResponse[HttpSessionOut])
 async def http_session_create(
     data: HttpSessionCreate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     logger.info(f"[Create HttpSession] sid={data.session_id}")
     obj = await HttpSessionService.create(db, data)
@@ -375,7 +369,7 @@ async def http_session_create(
 @admin_required_router.delete("/http-session", summary="删除http session", tags=["会话管理"], response_model=ApiResponse)
 async def http_session_delete_by_sid(
     session_id: str = Query(...),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     logger.info(f"[Delete HttpSession] sid={session_id}")
     await HttpSessionService.delete_by_sid(db, session_id)
@@ -386,7 +380,7 @@ async def http_session_delete_by_sid(
 async def http_session_update_by_sid(
     session_id: str = Query(...),
     data: HttpSessionUpdate = Body(...),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     logger.info(f"[Update HttpSession] sid={session_id}")
     obj = await HttpSessionService.update_by_sid(db, session_id, data)
@@ -395,7 +389,7 @@ async def http_session_update_by_sid(
 @admin_required_router.get("/http-session", summary="读取http session", tags=["会话管理"],response_model=ApiResponse[HttpSessionOut])
 async def http_session_get_by_sid(
     session_id: str = Query(...),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     logger.info(f"[Get HttpSession] sid={session_id}")
     obj = await HttpSessionService.get_by_sid(db, session_id)
@@ -403,36 +397,36 @@ async def http_session_get_by_sid(
 
 
 @admin_required_router.get("/email-authorizations", summary="查询所有内部邮箱", tags=["邮箱接口"], response_model=ApiResponse[List[EmailAuthorizationOut]])
-async def email_authorizations_get(db: Session = Depends(get_db)):
+async def email_authorizations_get(db: AsyncSession = Depends(get_db)):
     obj = await EmailAuthorizationService.get_all(db)
     return success(data=obj)
 
 
 @admin_required_router.post("/email-authorizations", summary="创建内部邮箱", tags=["邮箱接口"], response_model=ApiResponse[EmailAuthorizationOut])
-async def email_authorizations_create(data: EmailAuthorizationCreate, db: Session = Depends(get_db)):
+async def email_authorizations_create(data: EmailAuthorizationCreate, db: AsyncSession = Depends(get_db)):
     obj = await EmailAuthorizationService.create(db, data)
     return success(data=obj)
 
 @admin_required_router.get("/email-authorizations/{id}", summary="通过id查询内部邮箱", tags=["邮箱接口"], response_model=ApiResponse[EmailAuthorizationOut])
-async def email_authorizations_get_by_id(id: int, db: Session = Depends(get_db)):
+async def email_authorizations_get_by_id(id: int, db: AsyncSession = Depends(get_db)):
     email_auth = await EmailAuthorizationService.get_by_id(db, id)
     return success(data=email_auth)
 
 
 @admin_required_router.put("/email-authorizations/{id}", summary="通过id更新内部邮箱", tags=["邮箱接口"], response_model=ApiResponse[EmailAuthorizationOut])
-async def email_authorizations_update_by_id(id: int, data: EmailAuthorizationUpdate, db: Session = Depends(get_db)):
+async def email_authorizations_update_by_id(id: int, data: EmailAuthorizationUpdate, db: AsyncSession = Depends(get_db)):
     updated = await EmailAuthorizationService.update(db, id, data)
     return success(data=updated)
 
 
 @admin_required_router.delete("/email-authorizations/{id}", summary="通过id删除内部邮箱", tags=["邮箱接口"], response_model=ApiResponse[EmailAuthorizationOut])
-async def email_authorizations_delete_by_id(id: int, db: Session = Depends(get_db)):
+async def email_authorizations_delete_by_id(id: int, db: AsyncSession = Depends(get_db)):
     deleted = await EmailAuthorizationService.delete(db, id)
     return success(data=deleted)
 
 
 @admin_required_router.get("/email-authorizations/email/{email}", summary="通过邮箱地址查询内部邮箱", tags=["邮箱接口"], response_model=ApiResponse[EmailAuthorizationOut])
-async def email_authorizations_get_by_email(email: str, db: Session = Depends(get_db)):
+async def email_authorizations_get_by_email(email: str, db: AsyncSession = Depends(get_db)):
     email_auth = await EmailAuthorizationService.get_by_email(db, email)
     return success(data=email_auth)
 
@@ -445,7 +439,7 @@ async def email_authorizations_fetch_email(
     bodyKeywords: str = Query("", description="邮件内容关键词, 支持多个关键词, 用逗号隔开"),
     sentDate: str = Query(..., description="发件日期, UTC时间, 格式: yyyy-mm-dd hh:mm:ss"),
     expiry: int = Query(300, description="邮件有效期, 单位秒, 从sentDate 开始算起"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     auth = await EmailAuthorizationService.get_by_email(db, email)
     print(auth)
@@ -469,7 +463,7 @@ async def email_authorizations_fetch_email_from_topn(
     subjectKeywords: str = Query("", description="邮件主题关键词, 支持多个关键词, 用逗号隔开"),
     bodyKeywords: str = Query("", description="邮件内容关键词, 支持多个关键词, 用逗号隔开"),
     top: int = Query(10, description="指定从最近几封邮件读取"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     auth = await EmailAuthorizationService.get_by_email(db, email)
     result = await EmailAuthorizationService.fetch_email_authorizations_from_top_n(
@@ -491,7 +485,7 @@ async def email_authorizations_forward_email(
     recipient: str = Query(..., description="收件人账号或者名字"),
     subjectKeywords: str = Query("", description="邮件主题关键词, 支持多个关键词, 用逗号隔开"),
     bodyKeywords: str = Query("", description="邮件内容关键词, 支持多个关键词, 用逗号隔开"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     auth = await EmailAuthorizationService.get_by_email(db, emailAccount)
     result = await EmailAuthorizationService.forward_first_matching_email(
@@ -512,7 +506,7 @@ async def email_authorizations_forward_email2(
     recipient: str = Query(..., description="收件人账号或者名字"),
     subjectKeywords: str = Query("", description="邮件主题关键词, 支持多个关键词, 用逗号隔开"),
     bodyKeywords: str = Query("", description="邮件内容关键词, 支持多个关键词, 用逗号隔开"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     auth = await EmailAuthorizationService.get_by_email(db, emailAccount)
     result = await EmailAuthorizationService.forward_first_matching_email2(
@@ -533,7 +527,7 @@ async def email_authorizations_send_email(
     subject: str = Query(..., description="邮件主题"),
     contentType: str = Query("text", description="内容格式,支持 text 和 html"),
     content: EmailContent = Body("", description="邮件内容"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     auth = await EmailAuthorizationService.get_by_email(db, emailAccount)
     result = await EmailAuthorizationService.send_email(
@@ -552,7 +546,7 @@ async def email_authorizations_send_email_bulk(
     subject: str = Query(..., description="邮件主题"),
     contentType: str = Query("text", description="内容格式,支持 text 和 html"),
     content: EmailContent = Body(..., description="邮件内容"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     auth = await EmailAuthorizationService.get_by_email(db, emailAccount)
     result = await EmailAuthorizationService.send_email_bulk(
@@ -578,26 +572,26 @@ async def resource_get_file(fid: str):
 @admin_required_router.post("/s/generate", summary="生成短链接地址<压缩地址长度>", tags=["Short URL"], response_model=ApiResponse[ShortUrlOut])
 async def short_url_generate(
     data: ShortUrlCreate,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
 ):
     """生成短链接"""
     record = await ShortUrlService.create_short_url(db, data.long_url)
     return success(data=record)
 
 @public_router.get("/s/{short_key}", summary="访问短链接地址<自动重定向到真实链接地址>", tags=["Short URL"])
-async def short_url_request(short_key: str, db: Session = Depends(get_db)):
+async def short_url_request(short_key: str, db: AsyncSession = Depends(get_db)):
     """访问短链接自动重定向"""
     long_url = await ShortUrlService.get_long_url(db, short_key)
     return RedirectResponse(url=long_url, status_code=302)
 
 @admin_required_router.post("/tasks", summary="创建任务", tags=["任务管理接口"], response_model=ApiResponse[TaskOut])
-async def task_create(data: TaskCreate, db: Session = Depends(get_db)):
+async def task_create(data: TaskCreate, db: AsyncSession = Depends(get_db)):
     """创建任务"""
     task = await TaskService.create(db, data)
     return success(data=task)
 
 @admin_required_router.get("/tasks/{task_id:int}", summary="根据taskId读取任务状态", tags=["任务管理接口"], response_model=ApiResponse[TaskOut])
-async def task_get_by_id(task_id: int, db: Session = Depends(get_db)):
+async def task_get_by_id(task_id: int, db: AsyncSession = Depends(get_db)):
     """获取任务"""
     task = await TaskService.get_by_id(db, task_id)
     return success(data=task)
@@ -607,14 +601,14 @@ async def task_get_pending(
     page: int = Query(0, description="第几页"),
     size: int = Query(10, description="分页大小"),
     command: str = Query(..., description="任务类型"),
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
 ):
     """分页获取等待执行的任务"""
     obj = await TaskService.get_pending(db, command, page, size)
     return success(data=obj)
 
 @admin_required_router.put("/tasks/{task_id}", summary="根据taskId更新任务状态", tags=["任务管理接口"], response_model=ApiResponse[TaskOut])
-async def task_update_by_id(task_id: int, data: TaskUpdate, db: Session = Depends(get_db)):
+async def task_update_by_id(task_id: int, data: TaskUpdate, db: AsyncSession = Depends(get_db)):
     """更新任务状态或结果"""
     updated = await TaskService.update(db, task_id, data)
     return success(data=updated)
@@ -622,7 +616,7 @@ async def task_update_by_id(task_id: int, data: TaskUpdate, db: Session = Depend
 @admin_required_router.get("/task/pop", summary="任务出队(pop)", tags=["任务管理接口"], response_model=ApiResponse[TaskOut])
 async def task_pop_task(
     queue_name: str,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
 ):
     task = await QueueService.pop_task(db, queue_name)
     return success(data=task)
@@ -652,7 +646,7 @@ async def wechat_send(
 @admin_required_router.post("/cards/publish", summary="创建新的消息卡片", tags=["信息卡片接口"], response_model=ApiResponse[CardOut])
 async def cards_publish(
     data: CardCreate = Body(...),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     obj = await CardService.create(db, data)
     return success(data=obj)
@@ -663,7 +657,7 @@ async def cards_view_paginated2(
     page: int = Query(0, description="第几页"),
     size: int = Query(10, description="分页大小"),
     culture: str = Query("english", description="语言, 可设置 chinese, english"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     obj = await CardService.list_by_keyword(db, keyword, page, size, culture)
     return success(data=obj)
@@ -681,7 +675,7 @@ async def slots_latest_get(
     country: str = Query("", description="目的国家"),
     city: str = Query("", description="递交城市"),
     visa_type: str = Query("", description="签证类型"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     res = await SlotSnapshotService.latest_for(db, country, city, visa_type)
     return success(data=res)
@@ -689,7 +683,7 @@ async def slots_latest_get(
 @admin_required_router.post("/slots/report", summary="上报最近的slot", tags=["Slot数据"], response_model=ApiResponse[SlotSnapshotOut])
 async def slots_report(
     payload: SlotSnapshotCreate,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     res = await SlotSnapshotService.report(db, redis_client, payload)
@@ -698,7 +692,7 @@ async def slots_report(
 @public_router.post("/webhook/smshelper", summary="双开助手Webhook", tags=["webhook"], response_model=ApiResponse)
 async def webhook_smshelper(
     payload: SMSHelperWebhookPayload,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     logger.info(f'smshelper webhook title={payload.title}, content={payload.content}')
@@ -711,7 +705,7 @@ async def webhook_smshelper(
 @public_router.post("/webhook/stripe", summary="Stripe Webhook", tags=["webhook"], response_model=ApiResponse)
 async def webhook_stripe(
     request: Request,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     payload = request.body()
@@ -730,7 +724,7 @@ async def webhook_stripe(
 async def vas_auto_register(
     payload: AutoRegisterRequest,
     request: Request,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     user_agent = request.headers.get("user-agent", "unknown")
     client_host = request.client.host
@@ -746,7 +740,7 @@ async def vas_auto_register(
 async def vas_send_bind_code(
     payload: SendBindCodeRequest,
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     await AuthService.send_bind_code(db, payload, current_user, redis_client)
@@ -755,7 +749,7 @@ async def vas_send_bind_code(
 @public_router.post("/auth/send-reset-code", summary="发送邮箱注册码 重置密码用", tags=["用户管理"], response_model=ApiResponse)
 async def vas_send_reset_code(
     payload: SendResetCodeRequest,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     await AuthService.send_reset_code(db, payload, redis_client)
@@ -766,7 +760,7 @@ async def vas_bind_email(
     payload: BindEmailRequest,
     request: Request,
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     user_agent = request.headers.get("user-agent", "unknown")
@@ -782,7 +776,7 @@ async def vas_bind_email(
 @public_router.post("/auth/reset-password", summary="重置密码", tags=["用户管理"], response_model=ApiResponse)
 async def vas_reset_password(
     payload: ResetPasswordRequest,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     res = await AuthService.reset_password(db, payload)
     return success(data=res)
@@ -791,7 +785,7 @@ async def vas_reset_password(
 async def vas_login(
     payload: LoginRequest,
     request: Request,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     user_agent = request.headers.get("user-agent", "unknown")
     client_host = request.client.host
@@ -808,7 +802,7 @@ async def vas_user_list_all(
     page: int = Query(0, description="第几页"),
     size: int = Query(10, description="分页大小"),
     keyword: str = Query("", description="查询条件"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     users = await UserService.list_all(db, page, size, keyword)
     return success(data=users)
@@ -816,7 +810,7 @@ async def vas_user_list_all(
 @admin_required_router.get("/user/detail", summary="获取用户信息", tags=["用户管理"], response_model=ApiResponse[VasUserOut])
 async def vas_user_get_detail(
     user_id: str,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     user = await UserService.get(db, user_id)
     return success(data=user)
@@ -825,7 +819,7 @@ async def vas_user_get_detail(
 async def vas_user_update(
     uid: str,
     payload: VasUserUpdate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     updated = await UserService.update(db, uid, payload)
     return success(data=updated)
@@ -834,14 +828,14 @@ async def vas_user_update(
 async def vas_user_update(
     payload: VasUserSetProfiles,
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     updated = await UserService.set_profiles(db, current_user, payload)
     return success(data=updated)
 
 @admin_required_router.get("/vas/statistics/overview", summary="系统概览", tags=["Visafly签证系统"], response_model=ApiResponse[VasStatisticsOverviewOut])
 async def vas_statistics_overview(
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     overview = await StatisticsService.overview(db)
     return success(data=overview)
@@ -849,7 +843,7 @@ async def vas_statistics_overview(
 @admin_required_router.post("/vas/product/create", summary="创建商品", tags=["Visafly签证系统"], response_model=ApiResponse[VasProductOut])
 async def vas_product_create(
     payload: VasProductCreate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     created_product = await ProductService.create(db, payload)
     return success(data=created_product)
@@ -858,7 +852,7 @@ async def vas_product_create(
 async def vas_product_update(
     id: int,
     payload: VasProductUpdate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     product = await ProductService.update(db, id, payload)
     return success(data=product)
@@ -870,7 +864,7 @@ async def vas_product_list(
     page: int = Query(0, description="第几页"),
     size: int = Query(10, description="分页大小"),
     keyword: str = Query("", description="查询条件"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     products = await ProductService.list_product(db, country, visa_type, page, size, keyword)
     return success(data=products)
@@ -878,7 +872,7 @@ async def vas_product_list(
 @public_router.get("/vas/product/detail", summary="获取商品列表", tags=["Visafly签证系统"], response_model=ApiResponse[VasProductOut])
 async def vas_product_get_by_id(
     product_id: int,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     products = await ProductService.get(db, product_id)
     return success(data=products)
@@ -886,7 +880,7 @@ async def vas_product_get_by_id(
 @admin_required_router.post("/vas/product_routing/create", summary="创建商品路由列表", tags=["Visafly签证系统"], response_model=ApiResponse[VasProductRoutingOut])
 async def vas_product_routing_create(
     payload: VasProductRoutingCreate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     payload = await ProductRoutingService.create(db, payload)
     return success(data=payload)
@@ -894,7 +888,7 @@ async def vas_product_routing_create(
 @admin_required_router.delete("/vas/product_routing/delete", summary="删除商品路由列表", tags=["Visafly签证系统"], response_model=ApiResponse)
 async def vas_product_routing_date(
     id: int,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     await ProductRoutingService.delete(db, id)
     return success()
@@ -902,7 +896,7 @@ async def vas_product_routing_date(
 @admin_required_router.get("/vas/product_routing/list", summary="获取商品路由列表", tags=["Visafly签证系统"], response_model=ApiResponse[List[VasProductRoutingOut]])
 async def vas_product_routing_list_by_product(
     product_id: int,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     product_routings = await ProductRoutingService.list_by_product(db, product_id)
     return success(data=product_routings)
@@ -910,7 +904,7 @@ async def vas_product_routing_list_by_product(
 @admin_required_router.post("/vas/llm/data_parsing", summary="llm数据解析", tags=["Visafly签证系统"], response_model=ApiResponse[ParseUserInputsOut])
 async def vas_llm_data_parsing(
     payload: ParseUserInputsPayload,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     out = await LlmService.handle_parse(db, payload)
     return success(data=out)
@@ -918,7 +912,7 @@ async def vas_llm_data_parsing(
 @public_router.get("/vas/schema/detail", summary="获取schema", tags=["Visafly签证系统"], response_model=ApiResponse[VasSchemaOut])
 async def vas_schema_get(
     schema_id: int,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     schema = await SchemaService.get(db, schema_id)
     return success(data=schema)
@@ -926,7 +920,7 @@ async def vas_schema_get(
 @admin_required_router.post("/vas/schema/create", summary="新增schema", tags=["Visafly签证系统"], response_model=ApiResponse[VasSchemaOut])
 async def vas_schema_create(
     payload: VasSchemaCreate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     schema = await SchemaService.create(db, payload)
     return success(data=schema)
@@ -935,7 +929,7 @@ async def vas_schema_create(
 async def vas_schema_update(
     id: int,
     payload: VasSchemaUpdate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     schema = await SchemaService.update(db, id, payload)
     return success(data=schema)
@@ -943,14 +937,14 @@ async def vas_schema_update(
 @admin_required_router.delete("/vas/schema/delete", summary="删除schema", tags=["Visafly签证系统"], response_model=ApiResponse)
 async def vas_schema_delete(
     id: int,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     await SchemaService.delete(db, id)
     return success()
 
 @admin_required_router.get("/vas/schema/list", summary="获取schema列表", tags=["Visafly签证系统"], response_model=ApiResponse[List[VasSchemaOut]])
 async def vas_schema_list(
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     schemas = await SchemaService.list_all(db)
     return success(data=schemas)
@@ -959,7 +953,7 @@ async def vas_schema_list(
 async def vas_order_create(
     payload: VasOrderCreate,
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     product = await ProductService.get(db, payload.product_id)
@@ -977,7 +971,7 @@ async def vas_order_create(
 async def vas_order_create_by_admin(
     payload: VasOrderCreate,
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     product = await ProductService.get(db, payload.product_id)
@@ -994,7 +988,7 @@ async def vas_order_create_by_admin(
 @admin_required_router.get("/vas/order/detail", summary="查询订单", tags=["Visafly签证系统"], response_model=ApiResponse[VasOrderOut])
 async def vas_order_create(
     order_id: str,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
 ):
     order = await OrderService.get(db, order_id)
     return success(data=order)
@@ -1003,7 +997,7 @@ async def vas_order_create(
 async def vas_order_patch_user_inputs(
     order_id: str,
     payload: VasOrderPatchUserInputs,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
 ):
     order = await OrderService.patch_user_inputs(db, order_id, payload)
     return success(data=order)
@@ -1014,7 +1008,7 @@ async def vas_order_list_by_user(
     size: int = Query(10, description="分页大小"),
     keyword: str = Query("", description="查询条件"),
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     orders = await OrderService.list_by_user(db, current_user.id, page, size, keyword)
     return success(data=orders)
@@ -1024,7 +1018,7 @@ async def vas_order_list_all(
     page: int = Query(0, description="第几页"),
     size: int = Query(10, description="分页大小"),
     keyword: str = Query("", description="查询条件"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     orders = await OrderService.list_all(db, page, size, keyword)
     return success(data=orders)
@@ -1033,7 +1027,7 @@ async def vas_order_list_all(
 async def vas_order_cancel(
     order_id: str,
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     cancelled_order = await OrderService.cancel(db, order_id)
@@ -1041,14 +1035,14 @@ async def vas_order_cancel(
 
 @protected_router.get("/vas/payment_provider/list_enabled", summary="获取支付方式", tags=["Visafly签证系统"], response_model=ApiResponse[List[VasPaymentProviderOut]])
 async def vas_payment_provider_simple_get(
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     providers = await PaymentProviderService.list_enabled(db)
     return success(data=providers)
 
 @admin_required_router.get("/vas/payment_provider/list_all", summary="获取支付方式", tags=["Visafly签证系统"], response_model=ApiResponse[List[VasPaymentProviderOut]])
 async def vas_payment_provider_list_all(
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     providers = await PaymentProviderService.list_all(db)
     return success(data=providers)
@@ -1056,7 +1050,7 @@ async def vas_payment_provider_list_all(
 @admin_required_router.post("/vas/payment_provider/create", summary="新增支付服务提供商", tags=["Visafly签证系统"], response_model=ApiResponse[VasPaymentProviderOut])
 async def vas_payment_provider_create(
     payload: VasPaymentProviderCreate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     provider = await PaymentProviderService.create(db, payload)
     return success(data=provider)
@@ -1065,7 +1059,7 @@ async def vas_payment_provider_create(
 async def vas_payment_provider_update(
     id: int,
     payload: VasPaymentProviderUpdate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     provider = await PaymentProviderService.update(db, id, payload)
     return success(data=provider)
@@ -1073,7 +1067,7 @@ async def vas_payment_provider_update(
 @admin_required_router.delete("/vas/payment_provider/delete", summary="删除支付服务提供商", tags=["Visafly签证系统"], response_model=ApiResponse)
 async def vas_payment_provider_delete(
     id: int,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     await PaymentProviderService.delete(db, id)
     return success()
@@ -1081,7 +1075,7 @@ async def vas_payment_provider_delete(
 @protected_router.post("/vas/payment/create", summary="创建支付", tags=["Visafly签证系统"], response_model=ApiResponse[VasPaymentOut])
 async def vas_payment_create(
     payload: VasPaymentCreate,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     rate_table = {
@@ -1095,7 +1089,7 @@ async def vas_payment_create(
 @protected_router.get("/vas/payment/detail", summary="获取支付详情", tags=["Visafly签证系统"], response_model=ApiResponse[VasPaymentOut])
 async def vas_payment_create(
     payment_id: int,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
 ):
     res = await PaymentService.get_by_id(db, payment_id)
     return success(data=res)
@@ -1105,7 +1099,7 @@ async def vas_payment_confirm_by_admin(
     id: int,
     payload: VasPaymentConfirmationUpdate,
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     res = await PaymentService.confirm_by_admin(db, id, payload, current_user)
     return success(data=res)
@@ -1114,7 +1108,7 @@ async def vas_payment_confirm_by_admin(
 async def vas_payment_admin_update_status(
     payment_id: int,
     payload: AdminUpdateStatusPayload,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     res = await PaymentService.admin_update_status(db, payment_id, payload)
     return success(data=res)
@@ -1123,7 +1117,7 @@ async def vas_payment_admin_update_status(
 async def vas_payment_confirm_by_user(
     payload: VasPaymentConfirmationCreate,
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     res = await PaymentService.confirm_by_user(db, payload, current_user, redis_client)
@@ -1134,7 +1128,7 @@ async def vas_payment_confirm_list(
     page: int = Query(0, description="第几页"),
     size: int = Query(10, description="分页大小"),
     keyword: str = Query("", description="查询条件"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     res = await PaymentService.list_payment_confirmation(db, keyword, page, size)
     return success(data=res)
@@ -1142,23 +1136,23 @@ async def vas_payment_confirm_list(
 @protected_router.get("/vas/payment/list_by_order", summary="获取某个订单下的所有payment记录", tags=["Visafly签证系统"], response_model=ApiResponse[List[VasPaymentOut]])
 async def vas_payment_list_by_order(
     order_id: str,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     payments = await PaymentService.list_by_order(db, order_id)
     return success(data=payments)
 
 @admin_required_router.post("/vas/payment_qr/create", summary="新增收款码", tags=["Visafly签证系统"], response_model=ApiResponse[VasPaymentQrOut])
-async def vas_payment_qr_create(payload: VasPaymentQrCreate, db: Session = Depends(get_db)):
+async def vas_payment_qr_create(payload: VasPaymentQrCreate, db: AsyncSession = Depends(get_db)):
     qr = await PaymentQrService.create(db, payload)
     return success(data=qr)
 
 @protected_router.get("/vas/payment_qr/list_by_provider", summary="获取某个服务商的所有付款码", tags=["Visafly签证系统"], response_model=ApiResponse[List[VasPaymentQrOut]])
-async def vas_payment_qr_list_qrcode_by_provider(provider_id: int, db: Session = Depends(get_db)):
+async def vas_payment_qr_list_qrcode_by_provider(provider_id: int, db: AsyncSession = Depends(get_db)):
     qr = await PaymentQrService.list_by_provider(db, provider_id)
     return success(data=qr)
     
 @protected_router.get("/vas/payment_qr/qrcode", summary="获取支付的QRCode", tags=["Visafly签证系统"], response_model=ApiResponse[VasPaymentQrOut])
-async def vas_payment_qr_get_qrcode_by_id(id: int, db: Session = Depends(get_db)):
+async def vas_payment_qr_get_qrcode_by_id(id: int, db: AsyncSession = Depends(get_db)):
     qr = await PaymentQrService.get_by_id(db, id)
     return success(data=qr)
 
@@ -1166,7 +1160,7 @@ async def vas_payment_qr_get_qrcode_by_id(id: int, db: Session = Depends(get_db)
 async def vas_payment_qr_update(
     id: int,
     payload: VasPaymentQrSetEnableIn,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     qr = await PaymentQrService.set_enable(db, id, payload)
     return success(data=qr)
@@ -1174,7 +1168,7 @@ async def vas_payment_qr_update(
 @admin_required_router.delete("/vas/payment_qr/delete", summary="删除QRCode", tags=["Visafly签证系统"], response_model=ApiResponse)
 async def vas_payment_qr_update(
     id: int,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     await PaymentQrService.delete(db, id)
     return success()
@@ -1187,7 +1181,7 @@ async def vas_task_list(
     status: str = Query("", description="task 自定义索引"),
     routing_key: str = Query("", description="task 自定义索引"),
     script_version: str = Query("", description="脚本版本, 用来向后兼容"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     tasks = await VasTaskService.list_task(db, status, routing_key, script_version, keyword, page, size)
     return success(data=tasks)
@@ -1196,7 +1190,7 @@ async def vas_task_list(
 async def vas_task_update(
     id: int,
     payload: VasTaskUpdate,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     task = await VasTaskService.update(db, id, payload)
     return success(data=task)
@@ -1205,25 +1199,25 @@ async def vas_task_update(
 async def vas_task_pending(
     order_id: str = Query(..., description="订单编号"),
     script_version: str = Query("", description="脚本版本, 用来向后兼容"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     tasks = await VasTaskService.get_active_task_by_order_id(db, order_id)
     return success(data=tasks)
 
 @admin_required_router.post("/vas/task/return_to_queue", summary="重新进入等候状态", tags=["Visafly签证系统"], response_model=ApiResponse[VasTaskOut])
-async def vas_task_return_to_queue(task_id:int, db: Session = Depends(get_db)):
+async def vas_task_return_to_queue(task_id:int, db: AsyncSession = Depends(get_db)):
     obj = await VasTaskService.return_to_queue(db, task_id)
     return success(data=obj)
 
 @admin_required_router.post("/vas/task/manual_confirm", summary="设置任务完成", tags=["Visafly签证系统"], response_model=ApiResponse[VasTaskOut])
-async def vas_task_manual_confirm(task_id:int, db: Session = Depends(get_db)):
+async def vas_task_manual_confirm(task_id:int, db: AsyncSession = Depends(get_db)):
     obj = await VasTaskService.manual_confirm(db, task_id)
     return success(data=obj)
 
 @admin_required_router.get("/vas/task/pop", summary="任务出队(pop)", tags=["Visafly签证系统"], response_model=ApiResponse[VasTaskOut])
 async def vas_task_pop_task(
     queue_name: str,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
 ):
     task = await QueueService.pop_vas_task(db, queue_name)
     return success(data=task)
@@ -1232,7 +1226,7 @@ async def vas_task_pop_task(
 async def vas_ticket_create(
     data:VasTicketCreate,
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     redis_client: Redis = Depends(get_redis_client)
 ):
     obj = await TicketService.create(db, data, current_user, redis_client)
@@ -1244,7 +1238,7 @@ async def vas_ticket_list_by_user(
     size: int = Query(10, description="分页大小"),
     keyword: str = Query("", description="查询条件"),
     current_user: VasUser = Depends(get_current_user),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     tickets = await TicketService.list_by_user(db, current_user.id, page, size, keyword)
     return success(data=tickets)
@@ -1254,7 +1248,7 @@ async def vas_ticket_list_all(
     page: int = Query(0, description="第几页"),
     size: int = Query(10, description="分页大小"),
     keyword: str = Query("", description="查询条件"),
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     tickets = await TicketService.list_all(db, page, size, keyword)
     return success(data=tickets)
@@ -1263,7 +1257,7 @@ async def vas_ticket_list_all(
 async def update_ticket_status(
     ticket_id: int,
     payload: VasTicketStatusUpdate,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     user=Depends(get_current_user)
 ):
     res = await TicketService.update_status(
@@ -1279,7 +1273,7 @@ async def update_ticket_status(
 async def create_ticket_message(
     ticket_id: int,
     payload: VasTicketMessageCreate,
-    db: Session = Depends(get_db),
+    db: AsyncSession = Depends(get_db),
     user=Depends(get_current_user)
 ):
     res = await TicketService.add_message(
@@ -1297,7 +1291,7 @@ async def get_ticket_messages(
     ticket_id: int,
     page: int = 1,
     size: int = 20,
-    db: Session = Depends(get_db)
+    db: AsyncSession = Depends(get_db)
 ):
     msgs = await TicketService.list_messages(
         db=db,

+ 0 - 27
app/core/config.py

@@ -23,33 +23,6 @@ class Settings(BaseSettings):
     openai_api_key: str
     stripe_api_key: str
 
-    # -----------------------
-    # Remote Servers
-    # -----------------------
-    remote_servers: dict = {
-        "MCP1": {
-            "host": "45.137.220.138",
-            "port": 22,
-            "username": "root",
-            "password": "s3UqbkWxW72",
-            "project_path": "/root/troov-asyncio"
-        },
-        "MCP2": {
-            "host": "185.148.147.103",
-            "port": 22,
-            "username": "root",
-            "password": "nBEqFzWe7z7pbprypmUt",
-            "project_path": "/root/troov-asyncio"
-        },
-        "MCP3": {
-            "host": "185.148.147.119",
-            "port": 22,
-            "username": "root",
-            "password": "5hcm07IAnBAv87Ey",
-            "project_path": "/root/troov-asyncio"
-        }
-    }
-
     model_config = SettingsConfigDict(
         env_file=".env",
         env_file_encoding="utf-8",

+ 8 - 0
app/models/__init__.py

@@ -0,0 +1,8 @@
+from .user import VasUser
+from .order import VasOrder
+from .schema import VasSchema
+from .product import VasProduct
+from .payment import VasPayment
+from .card import Card
+from .configuration import Configuration
+from .remote_server import RemoteServer

+ 19 - 0
app/models/remote_server.py

@@ -0,0 +1,19 @@
+from sqlalchemy import Column, Integer, String, Text, TIMESTAMP, func
+from app.core.database import Base
+
+
+class RemoteServer(Base):
+    __tablename__ = "remote_server"
+
+    id = Column(Integer, primary_key=True, autoincrement=True)
+    server_id = Column(String(50), unique=True, nullable=False, comment="服务器唯一标识,如 MCP1")
+    name = Column(String(100), nullable=False, comment="服务器名称")
+    host = Column(String(255), nullable=False, comment="服务器地址")
+    port = Column(Integer, default=22, comment="SSH端口")
+    username = Column(String(100), default="root", comment="SSH用户名")
+    password = Column(String(255), nullable=True, comment="SSH密码")
+    key_file = Column(String(255), nullable=True, comment="SSH私钥路径")
+    project_path = Column(String(255), default="/root/troov-asyncio", comment="项目路径")
+    
+    created_at = Column(TIMESTAMP, server_default=func.now(), comment="创建时间")
+    updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now(), comment="更新时间")

+ 37 - 0
app/schemas/remote_server.py

@@ -0,0 +1,37 @@
+from typing import Optional, List
+from pydantic import BaseModel, Field
+from datetime import datetime
+
+
+class RemoteServerBase(BaseModel):
+    server_id: str = Field(..., description="服务器唯一标识,如 MCP1")
+    name: str = Field(..., description="服务器名称")
+    host: str = Field(..., description="服务器地址")
+    port: int = Field(22, description="SSH端口")
+    username: str = Field("root", description="SSH用户名")
+    password: Optional[str] = Field(None, description="SSH密码")
+    key_file: Optional[str] = Field(None, description="SSH私钥路径")
+    project_path: str = Field("/root/troov-asyncio", description="项目路径")
+
+
+class RemoteServerCreate(RemoteServerBase):
+    pass
+
+
+class RemoteServerUpdate(BaseModel):
+    name: Optional[str] = None
+    host: Optional[str] = None
+    port: Optional[int] = None
+    username: Optional[str] = None
+    password: Optional[str] = None
+    key_file: Optional[str] = None
+    project_path: Optional[str] = None
+
+
+class RemoteServerOut(RemoteServerBase):
+    id: int
+    created_at: datetime
+    updated_at: datetime
+
+    class Config:
+        from_attributes = True

+ 22 - 0
app/services/docker_remote_service.py

@@ -10,11 +10,33 @@ from app.schemas.docker_remote import (
     LogReadRequest,
 )
 from app.core.logger import logger
+from app.core.config import settings
+from fastapi import HTTPException
+from sqlalchemy.ext.asyncio import AsyncSession
+from sqlalchemy import select
+from app.models.remote_server import RemoteServer
 
 
 class DockerRemoteService:
     """Docker远程控制服务"""
     
+    @staticmethod
+    async def get_server_config(db: AsyncSession, server_id: str) -> RemoteServerConfig:
+        """从数据库中获取服务器连接信息"""
+        result = await db.execute(select(RemoteServer).filter(RemoteServer.server_id == server_id))
+        server = result.scalar_one_or_none()
+        if not server:
+            raise HTTPException(status_code=404, detail=f"Server {server_id} not found in database")
+        
+        return RemoteServerConfig(
+            host=server.host,
+            port=server.port,
+            username=server.username,
+            password=server.password,
+            key_file=server.key_file,
+            project_path=server.project_path
+        )
+    
     @staticmethod
     async def get_container_status(config: RemoteServerConfig) -> Dict[str, DockerContainerStatus]:
         """获取容器状态"""

+ 49 - 0
app/services/remote_server_service.py

@@ -0,0 +1,49 @@
+from typing import List, Optional
+from sqlalchemy.ext.asyncio import AsyncSession
+from sqlalchemy import select
+from app.models.remote_server import RemoteServer
+from app.schemas.remote_server import RemoteServerCreate, RemoteServerUpdate
+
+
+class RemoteServerService:
+    @staticmethod
+    async def get_all(db: AsyncSession) -> List[RemoteServer]:
+        result = await db.execute(select(RemoteServer))
+        return result.scalars().all()
+
+    @staticmethod
+    async def get_by_server_id(db: AsyncSession, server_id: str) -> Optional[RemoteServer]:
+        result = await db.execute(select(RemoteServer).filter(RemoteServer.server_id == server_id))
+        return result.scalar_one_or_none()
+
+    @staticmethod
+    async def create(db: AsyncSession, server_in: RemoteServerCreate) -> RemoteServer:
+        obj = RemoteServer(**server_in.model_dump())
+        db.add(obj)
+        await db.commit()
+        await db.refresh(obj)
+        return obj
+
+    @staticmethod
+    async def update(db: AsyncSession, server_id: str, server_in: RemoteServerUpdate) -> Optional[RemoteServer]:
+        obj = await RemoteServerService.get_by_server_id(db, server_id)
+        if not obj:
+            return None
+        
+        update_data = server_in.model_dump(exclude_unset=True)
+        for field, value in update_data.items():
+            setattr(obj, field, value)
+        
+        db.add(obj)
+        await db.commit()
+        await db.refresh(obj)
+        return obj
+
+    @staticmethod
+    async def delete(db: AsyncSession, server_id: str) -> bool:
+        obj = await RemoteServerService.get_by_server_id(db, server_id)
+        if not obj:
+            return False
+        await db.delete(obj)
+        await db.commit()
+        return True