from typing import * import os.path import uuid from fastapi import FastAPI, Request, Response, WebSocket, WebSocketDisconnect from fastapi.responses import PlainTextResponse from pydantic import BaseModel from settings import settings import auth from state import StateManager from proto import Computer, ComputerType app = FastAPI() state_manager = StateManager() @app.get("/api/{token}/validate", tags=["frontend"]) async def validate_token(token: str): return {"success": auth.validate_frontend(token)} @app.websocket("/api/{token}/state") async def state_updates_websocket(websocket: WebSocket, token: str): if not auth.validate_frontend(token): await websocket.close() return await websocket.accept() await state_manager.on_connect(websocket) try: while True: await websocket.receive_json() except WebSocketDisconnect: await state_manager.on_disconnect(websocket) @app.get("/install", tags=["computer"], response_class=PlainTextResponse) async def serve_install_script(): deploy_url = ( f'{"https" if settings.deploy_tls else "http"}://{settings.delpoy_path}' ) return f""" shell.run("wget {os.path.join(deploy_url, "lua/json.lua")}") shell.run("wget {os.path.join(deploy_url, "lua/framebuffer.lua")}") """ class RegistrationRequest(BaseModel): type: ComputerType is_advanced: bool label: Optional[str] class RegistrationResponse(BaseModel): token: str @app.post("/computer/register", tags=["computer"], response_model=RegistrationResponse) async def issue_new_token(data: RegistrationRequest): computer = Computer( uuid=uuid.uuid4(), group="default", **data.dict(), ) await state_manager.on_computer_register(computer) return {"token": auth.encode({"type": "computer", "uuid": str(computer.uuid)})} if settings.dev_mode: print("Starting in development mode.") print(f"Proxying requests to npm server on localhost:{settings.dev_npm_port}") import httpx @app.get("/{path:path}") async def dev_mode_proxy(path: str, response: Response): async with httpx.AsyncClient() as proxy: proxy_response = await proxy.get( f"http://localhost:{settings.dev_npm_port}/{path}" ) response.body = proxy_response.content response.status_code = proxy_response.status_code return response else: print("Starting in production mode") from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse @app.middleware("http") async def index_catch_all(request: Request, call_next): response = await call_next(request) if response.status_code == 404: return FileResponse(f"{settings.frontend_path}/index.html") return response app.mount("/", StaticFiles(directory=settings.frontend_path))