Files
eth_hedge_sim/control/backend/app/main.py
T
dekun da5eb4c18c 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>
2026-07-30 10:46:40 +08:00

75 lines
1.9 KiB
Python

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")