's'
This commit is contained in:
119
web.py
119
web.py
@@ -35,6 +35,14 @@ from src.control_plane import (
|
||||
system_snapshot,
|
||||
write_root_file,
|
||||
)
|
||||
from src.config_governance import (
|
||||
delete_managed_file as governed_delete_managed_file,
|
||||
inspect_file,
|
||||
list_backups,
|
||||
optimize_content,
|
||||
restore_backup,
|
||||
save_managed_file as governed_save_managed_file,
|
||||
)
|
||||
from src.hub_routes import configure_hub, router as hub_router
|
||||
from src.web_process_backend import WebProcessBackend, force_kill_ffmpeg, strip_ansi_codes
|
||||
|
||||
@@ -186,6 +194,35 @@ app.add_middleware(
|
||||
)
|
||||
|
||||
|
||||
class ProcessNameBody(BaseModel):
|
||||
process: str = Field(..., min_length=1, max_length=160)
|
||||
|
||||
|
||||
class ServiceActionPostBody(BaseModel):
|
||||
service: str = Field(..., min_length=1, max_length=64)
|
||||
action: str = Field(..., pattern="^(start|stop|restart)$")
|
||||
|
||||
|
||||
class ManagedFileBody(BaseModel):
|
||||
root: str = Field(..., min_length=1, max_length=64)
|
||||
path: str = Field(..., min_length=1, max_length=240)
|
||||
content: str = ""
|
||||
|
||||
|
||||
class ConfigAnalyzeBody(ManagedFileBody):
|
||||
pass
|
||||
|
||||
|
||||
class ConfigOptimizeBody(ManagedFileBody):
|
||||
action: str = Field(..., min_length=1, max_length=64)
|
||||
|
||||
|
||||
class ConfigRestoreBody(BaseModel):
|
||||
root: str = Field(..., min_length=1, max_length=64)
|
||||
path: str = Field(..., min_length=1, max_length=240)
|
||||
backup_id: str = Field(..., min_length=1, max_length=320)
|
||||
|
||||
|
||||
async def read_log_path(path: Optional[str], lines: int) -> str:
|
||||
if not path:
|
||||
return "无日志路径\n"
|
||||
@@ -370,8 +407,8 @@ async def get_managed_file(
|
||||
@app.post("/managed_file")
|
||||
async def save_managed_file(request: Request):
|
||||
try:
|
||||
data = await request.json()
|
||||
return write_root_file(data["root"], data["path"], data.get("content", ""))
|
||||
data = ManagedFileBody(**(await request.json()))
|
||||
return governed_save_managed_file(data.root, data.path, data.content)
|
||||
except KeyError as exc:
|
||||
return JSONResponse({"error": f"Missing field: {exc}"}, status_code=400)
|
||||
except (PermissionError, ValueError) as exc:
|
||||
@@ -384,7 +421,7 @@ async def delete_managed_file(
|
||||
path: str = Query(..., description="相对路径"),
|
||||
):
|
||||
try:
|
||||
return delete_root_file(root, path)
|
||||
return governed_delete_managed_file(root, path)
|
||||
except KeyError as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=404)
|
||||
except FileNotFoundError:
|
||||
@@ -393,6 +430,65 @@ async def delete_managed_file(
|
||||
return JSONResponse({"error": str(exc)}, status_code=400)
|
||||
|
||||
|
||||
@app.get("/config_insights")
|
||||
async def get_config_insights(
|
||||
root: str = Query(..., description="管理目录 id"),
|
||||
path: str = Query(..., description="相对路径"),
|
||||
):
|
||||
try:
|
||||
return inspect_file(root, path)
|
||||
except KeyError as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=404)
|
||||
except (PermissionError, ValueError) as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=400)
|
||||
|
||||
|
||||
@app.post("/config_insights")
|
||||
async def post_config_insights(body: ConfigAnalyzeBody):
|
||||
try:
|
||||
return inspect_file(body.root, body.path, draft_content=body.content)
|
||||
except KeyError as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=404)
|
||||
except (PermissionError, ValueError) as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=400)
|
||||
|
||||
|
||||
@app.get("/config_backups")
|
||||
async def get_config_backups(
|
||||
root: str = Query(..., description="管理目录 id"),
|
||||
path: str = Query(..., description="相对路径"),
|
||||
limit: int = Query(12, ge=1, le=50),
|
||||
):
|
||||
try:
|
||||
return {"backups": list_backups(root, path, limit=limit)}
|
||||
except KeyError as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=404)
|
||||
except (PermissionError, ValueError) as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=400)
|
||||
|
||||
|
||||
@app.post("/config_optimize")
|
||||
async def post_config_optimize(body: ConfigOptimizeBody):
|
||||
try:
|
||||
return optimize_content(body.root, body.path, body.action, body.content)
|
||||
except KeyError as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=404)
|
||||
except (PermissionError, ValueError) as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=400)
|
||||
|
||||
|
||||
@app.post("/config_restore")
|
||||
async def post_config_restore(body: ConfigRestoreBody):
|
||||
try:
|
||||
return restore_backup(body.root, body.path, body.backup_id)
|
||||
except KeyError as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=404)
|
||||
except FileNotFoundError:
|
||||
return JSONResponse({"error": f"Backup not found: {body.backup_id}"}, status_code=404)
|
||||
except (PermissionError, ValueError) as exc:
|
||||
return JSONResponse({"error": str(exc)}, status_code=400)
|
||||
|
||||
|
||||
@app.get("/hardware_profile")
|
||||
async def hardware_profile(refresh: bool = Query(False, description="重新探测硬件")):
|
||||
return await load_hardware_profile(force_refresh=refresh)
|
||||
@@ -436,10 +532,8 @@ async def save_config(request: Request, process: str = Query(..., description="
|
||||
except Exception:
|
||||
return JSONResponse({"error": "无效的 JSON 数据"}, status_code=400)
|
||||
|
||||
config_file = CONFIG_DIR / "youtube.ini"
|
||||
try:
|
||||
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
config_file.write_text(content, encoding="utf-8")
|
||||
governed_save_managed_file("app-config", "youtube.ini", content)
|
||||
return {"message": "配置保存成功"}
|
||||
except OSError as e:
|
||||
return JSONResponse({"error": f"保存失败: {str(e)}"}, status_code=500)
|
||||
@@ -480,24 +574,13 @@ async def save_url_config(request: Request, process: str = Query(..., descriptio
|
||||
except Exception:
|
||||
return JSONResponse({"error": "无效的 JSON 数据"}, status_code=400)
|
||||
|
||||
config_file = CONFIG_DIR / "URL_config.ini"
|
||||
try:
|
||||
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
config_file.write_text(content, encoding="utf-8")
|
||||
governed_save_managed_file("app-config", "URL_config.ini", content)
|
||||
return {"message": "配置保存成功"}
|
||||
except OSError as e:
|
||||
return JSONResponse({"error": f"保存失败: {str(e)}"}, status_code=500)
|
||||
|
||||
|
||||
class ProcessNameBody(BaseModel):
|
||||
process: str = Field(..., min_length=1, max_length=160)
|
||||
|
||||
|
||||
class ServiceActionPostBody(BaseModel):
|
||||
service: str = Field(..., min_length=1, max_length=64)
|
||||
action: str = Field(..., pattern="^(start|stop|restart)$")
|
||||
|
||||
|
||||
def _not_found_hint(process: str) -> str:
|
||||
if process_backend.mode == "local":
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user