Switch to Svelte
This commit is contained in:
@@ -1,49 +1,37 @@
|
||||
from typing import Optional
|
||||
from fastapi import FastAPI, Request, Form, Depends, HTTPException, status
|
||||
from fastapi.responses import RedirectResponse, HTMLResponse
|
||||
from fastapi import FastAPI, Request, Form, Depends, HTTPException, status, APIRouter
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from sqlmodel import Session, select
|
||||
import uvicorn
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from . import crud
|
||||
from .database import create_db_and_tables, get_session
|
||||
from .templates import templates, BASE_DIR
|
||||
from .models import GameEvent
|
||||
|
||||
app = FastAPI(title="Rats with Gats Remote Play")
|
||||
BASE_DIR = Path(__file__).parent
|
||||
|
||||
# Mount static files
|
||||
app.mount("/static", StaticFiles(directory=BASE_DIR / "static"), name="static")
|
||||
app = FastAPI(title="Rats with Gats Remote Play API")
|
||||
api = APIRouter()
|
||||
|
||||
# Register startup event to create tables
|
||||
@app.on_event("startup")
|
||||
def on_startup():
|
||||
create_db_and_tables()
|
||||
|
||||
# --- HTTP Core Route Handlers ---
|
||||
# --- API Core Route Handlers ---
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
def home(request: Request):
|
||||
return templates.TemplateResponse("index.html", {"request": request})
|
||||
|
||||
@app.post("/game/create")
|
||||
@api.post("/game")
|
||||
def create_game_route(
|
||||
crew_name: str = Form(...),
|
||||
db: Session = Depends(get_session)
|
||||
):
|
||||
game = crud.create_game(db, crew_name=crew_name.strip())
|
||||
# Redirect creator to the join page with creator flag
|
||||
return RedirectResponse(url=f"/game/{game.id}/join?creator=true", status_code=status.HTTP_303_SEE_OTHER)
|
||||
return {"id": game.id}
|
||||
|
||||
@app.get("/game/{game_id}/join", response_class=HTMLResponse)
|
||||
def join_game_form(request: Request, game_id: str, creator: bool = False, db: Session = Depends(get_session)):
|
||||
game = crud.get_game(db, game_id)
|
||||
if not game:
|
||||
raise HTTPException(status_code=404, detail="Game not found")
|
||||
return templates.TemplateResponse("join_form.html", {"request": request, "game": game, "creator": creator})
|
||||
|
||||
@app.post("/game/{game_id}/join")
|
||||
@api.post("/game/{game_id}/join")
|
||||
def join_game_submit(
|
||||
game_id: str,
|
||||
name: str = Form(...),
|
||||
@@ -56,80 +44,46 @@ def join_game_submit(
|
||||
# First player is automatically the creator
|
||||
is_creator = len(game.players) == 0
|
||||
player = crud.add_player(db, game_id, name.strip(), is_creator=is_creator)
|
||||
|
||||
return RedirectResponse(url=f"/game/{game_id}/player/{player.id}", status_code=status.HTTP_303_SEE_OTHER)
|
||||
return {"id": player.id}
|
||||
|
||||
@app.get("/game/{game_id}/player/{player_id}", response_class=HTMLResponse)
|
||||
def player_dashboard(request: Request, game_id: str, player_id: str, db: Session = Depends(get_session)):
|
||||
@api.get("/game/{game_id}/player/{player_id}/state")
|
||||
def get_game_state(game_id: str, player_id: str, db: Session = Depends(get_session)):
|
||||
game = crud.get_game(db, game_id)
|
||||
player = crud.get_player(db, player_id)
|
||||
if not game or not player:
|
||||
raise HTTPException(status_code=404, detail="Game or Player not found")
|
||||
|
||||
return templates.TemplateResponse("dashboard.html", {
|
||||
"request": request,
|
||||
"game": game,
|
||||
"player": player
|
||||
})
|
||||
|
||||
# --- HTMX Core Polling Route ---
|
||||
|
||||
@app.get("/game/{game_id}/player/{player_id}/phase-check")
|
||||
def phase_check_route(game_id: str, player_id: str, current: str, rank: Optional[int] = None, needs_name: Optional[bool] = None, hand_len: Optional[int] = None, db: Session = Depends(get_session)):
|
||||
game = crud.get_game(db, game_id)
|
||||
if not game:
|
||||
raise HTTPException(status_code=404, detail="Game not found")
|
||||
|
||||
player = crud.get_player(db, player_id)
|
||||
if not player:
|
||||
raise HTTPException(status_code=404, detail="Player not found")
|
||||
|
||||
state_changed = False
|
||||
if game.phase != current:
|
||||
state_changed = True
|
||||
elif rank is not None and player.rank != rank:
|
||||
state_changed = True
|
||||
elif needs_name is not None and player.needs_name != needs_name:
|
||||
state_changed = True
|
||||
elif hand_len is not None:
|
||||
import json
|
||||
current_hand = json.loads(player.hand_cards)
|
||||
if len(current_hand) != hand_len:
|
||||
state_changed = True
|
||||
|
||||
if state_changed:
|
||||
# Phase or state changed! Trigger page reload on client via HTMX header
|
||||
return HTMLResponse(status_code=200, headers={"HX-Trigger": "phase-changed"})
|
||||
return HTMLResponse(status_code=204) # No content, no reload
|
||||
|
||||
@app.get("/game/{game_id}/player/{player_id}/events", response_class=HTMLResponse)
|
||||
def get_events_snippet(request: Request, game_id: str, player_id: str, db: Session = Depends(get_session)):
|
||||
game = crud.get_game(db, game_id)
|
||||
if not game:
|
||||
raise HTTPException(status_code=404, detail="Game not found")
|
||||
|
||||
events = db.exec(select(GameEvent).where(GameEvent.game_id == game_id).order_by(GameEvent.timestamp.asc())).all()
|
||||
|
||||
return templates.TemplateResponse("event_log_snippet.html", {
|
||||
"request": request,
|
||||
"events": events
|
||||
})
|
||||
return {
|
||||
"game": game.model_dump(),
|
||||
"player": player.model_dump(),
|
||||
"players": [p.model_dump() for p in game.players],
|
||||
"obstacles": [o.model_dump() for o in game.obstacles],
|
||||
"votes": [v.model_dump() for v in game.votes],
|
||||
"events": [e.model_dump() for e in events],
|
||||
}
|
||||
|
||||
# --- Register Modular Phase Routers ---
|
||||
|
||||
from .phase_view import router as phase_view_router
|
||||
from .routes_lobby import router as lobby_router
|
||||
from .routes_character import router as character_router
|
||||
from .routes_scene import router as scene_router
|
||||
from .routes_upkeep import router as upkeep_router
|
||||
from .routes_admin import router as admin_router
|
||||
|
||||
app.include_router(phase_view_router)
|
||||
app.include_router(lobby_router)
|
||||
app.include_router(character_router)
|
||||
app.include_router(scene_router)
|
||||
app.include_router(upkeep_router)
|
||||
app.include_router(admin_router)
|
||||
api.include_router(lobby_router)
|
||||
api.include_router(character_router)
|
||||
api.include_router(scene_router)
|
||||
api.include_router(upkeep_router)
|
||||
api.include_router(admin_router)
|
||||
|
||||
# Mount API at /api
|
||||
app.include_router(api, prefix="/api")
|
||||
|
||||
# Mount SPA
|
||||
static_dir = BASE_DIR / "static"
|
||||
if os.path.exists(static_dir):
|
||||
app.mount("/", StaticFiles(directory=static_dir, html=True), name="static")
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
Reference in New Issue
Block a user