Add Fleet control plane and split manage.sh deploy menu.
Strategy nodes gain fleet token APIs; control/ app for local ops; manage.sh offers strategy vs control one-click deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from .api import router as api_router
|
||||
from .config import get_control_settings
|
||||
from .db import ControlDB, set_control_db
|
||||
|
||||
|
||||
def resolve_frontend_dist() -> Path:
|
||||
# control/backend/app -> control/frontend/dist
|
||||
return Path(__file__).resolve().parents[2] / "frontend" / "dist"
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
from .envfile import ensure_env_control_defaults
|
||||
|
||||
# 首次启动补全 .env.control 缺项(已有值不覆盖)
|
||||
ensure_env_control_defaults()
|
||||
db = ControlDB()
|
||||
set_control_db(db)
|
||||
yield
|
||||
db.close()
|
||||
set_control_db(None)
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title="比特骆驼中控",
|
||||
version="0.1.0",
|
||||
lifespan=lifespan,
|
||||
)
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=[],
|
||||
allow_credentials=False,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
app.include_router(api_router)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health() -> dict:
|
||||
s = get_control_settings()
|
||||
return {"ok": True, "app": "control", "poll_interval_sec": s.control_poll_interval_sec}
|
||||
|
||||
|
||||
_DIST = resolve_frontend_dist()
|
||||
if (_DIST / "assets").is_dir():
|
||||
app.mount("/assets", StaticFiles(directory=str(_DIST / "assets")), name="assets")
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@app.get("/monitor")
|
||||
@app.get("/settings")
|
||||
@app.get("/login")
|
||||
async def spa(full_path: str = ""):
|
||||
index = _DIST / "index.html"
|
||||
if index.exists():
|
||||
return FileResponse(index)
|
||||
if Path(__file__).name:
|
||||
return {
|
||||
"ok": True,
|
||||
"msg": "control frontend not built; cd control/frontend && npm ci && npm run build",
|
||||
"health": "/health",
|
||||
}
|
||||
raise HTTPException(status_code=404, detail="frontend missing")
|
||||
Reference in New Issue
Block a user