diff options
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ui/app.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/ui/app.py | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/ui/app.py b/packages/meshbay-node/src/meshbay_node/ui/app.py index 090eb21..50beb26 100644 --- a/packages/meshbay-node/src/meshbay_node/ui/app.py +++ b/packages/meshbay-node/src/meshbay_node/ui/app.py @@ -13,6 +13,7 @@ no server-rendered UI: the Node page ships in the desktop client (see """ import logging +import os from fastapi import FastAPI, HTTPException, Query from fastapi.responses import JSONResponse @@ -146,6 +147,9 @@ def create_ui_app(state: dict) -> FastAPI: return { "version": __version__, + # Whoever asks it to stop waits for this process to be gone, not only + # for the API to close: _shutdown() runs on after the API has closed. + "pid": os.getpid(), "status": status, "needs": needs, "hub_url": state.get("hub_url", ""), @@ -542,6 +546,21 @@ def create_ui_app(state: dict) -> FastAPI: # seconds, on a real library) — see ops.start_reload for why. return await _op(lambda: ops.start_reload(state)) + # ── Stop ───────────────────────────────────────────────────────────── + + @app.post("/api/shutdown") + async def shutdown(): + # The graceful stop every front door tries first (the desktop app, the + # CLI, the installer): it reaches a node in any session -- a service + # node runs in session 0, where taskkill and CTRL_BREAK from the user's + # desktop do not -- and runs the node's own _shutdown(). Behind the + # per-run token like everything here. + request_shutdown = state.get("request_shutdown") + if request_shutdown is None: + return JSONResponse({"error": "not ready to stop yet"}, status_code=503) + request_shutdown() + return {"stopping": True} + # ── Node settings (operator only, localhost) ─────────────────────────── @app.get("/api/node-settings") |