# web/server.py import os from pathlib import Path from fastapi import FastAPI, HTTPException from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from pydantic import BaseModel from core.app_manager import AppManager from vs_log_macros import VSC_INFO, VSC_ERROR app = FastAPI(title="Visa Plugin Manager") # === 1. 路径计算 (关键修改) === # 获取 web/server.py 所在的绝对路径目录 CURRENT_DIR = Path(__file__).resolve().parent # 拼接出 static 目录: .../web/static STATIC_DIR = CURRENT_DIR / "static" # 拼接出 index.html 路径 INDEX_FILE = STATIC_DIR / "index.html" VSC_INFO("web", f"Static Directory configured at: {STATIC_DIR}") VSC_INFO("web", f"Index File expected at: {INDEX_FILE}") # 确保目录存在 if not STATIC_DIR.exists(): VSC_INFO("web", "Static directory missing, creating...") STATIC_DIR.mkdir(parents=True, exist_ok=True) # === 2. 挂载静态文件 === # 挂载 /static 路径,用于访问 CSS/JS 等资源 (虽然本例是CDN,但保留以备用) app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") # === 3. 根路径路由 === @app.get("/") async def read_index(): # 显式检查文件是否存在,方便调试 if not INDEX_FILE.exists(): return { "error": "Index file not found", "expected_path": str(INDEX_FILE), "tip": "Please ensure 'index.html' exists in the 'web/static' folder." } return FileResponse(str(INDEX_FILE)) # === 数据模型 === class GroupControl(BaseModel): group_id: str class OTARequest(BaseModel): plugin_name: str # === API 接口 === @app.get("/status") def get_status(): return {"data": AppManager.Instance().get_status()} @app.post("/reload_config") def reload_config(): AppManager.Instance().load_configs() return {"message": "Configuration reloaded"} @app.post("/start") def start_group(payload: GroupControl): if AppManager.Instance().start_group(payload.group_id): return {"message": f"Group {payload.group_id} started"} raise HTTPException(status_code=400, detail="Failed to start group") @app.post("/stop") def stop_group(payload: GroupControl): if AppManager.Instance().stop_group(payload.group_id): return {"message": f"Group {payload.group_id} stopped"} raise HTTPException(status_code=400, detail="Group not running or failed to stop") @app.post("/restart") def restart_group(payload: GroupControl): if AppManager.Instance().restart_group(payload.group_id): return {"message": f"Group {payload.group_id} restarted"} raise HTTPException(status_code=400, detail="Failed to restart") @app.post("/ota") def ota_update(payload: OTARequest): try: restarted = AppManager.Instance().ota_update_plugin(payload.plugin_name) return { "message": f"Plugin {payload.plugin_name} reloaded", "restarted_groups": restarted } except Exception as e: raise HTTPException(status_code=500, detail=str(e)) def run_web_server(host="0.0.0.0", port=8000): import uvicorn # log_level warning 减少控制台刷屏 uvicorn.run(app, host=host, port=port, log_level="info")