132 lines
3.4 KiB
Python
132 lines
3.4 KiB
Python
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, ComputerToken, 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) is not None}
|
|
|
|
|
|
@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)})}
|
|
|
|
|
|
@app.websocket("/computer/{token}/socket")
|
|
async def computer_websocket(websocket: WebSocket, token: str):
|
|
|
|
token = auth.validate_computer(token)
|
|
|
|
if not token:
|
|
await websocket.close()
|
|
return
|
|
|
|
await websocket.accept()
|
|
await state_manager.on_computer_connect(token.uuid)
|
|
|
|
try:
|
|
while True:
|
|
await websocket.receive_json()
|
|
except WebSocketDisconnect:
|
|
await state_manager.on_computer_disconnect(token.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}", tags=["dev mode please ignore"])
|
|
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))
|