# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. import os import uuid from datetime import datetime from fastapi import APIRouter, HTTPException from pydantic import BaseModel from classquiz.config import redis from classquiz.db.models import PlayGame, Controllers from classquiz.routers.box_controller.embedded.socket import router as socket_router router = APIRouter() router.include_router(socket_router, prefix="/socket") class JoinGameInput(BaseModel): id: uuid.UUID secret_key: str code: str class JoinGameResponse(BaseModel): id: str @router.post("/join") async def join_game(data: JoinGameInput) -> JoinGameResponse: controller = await Controllers.objects.get_or_none(id=data.id, secret_key=data.secret_key) game_pin = await redis.get(f"game:cqc:code:{data.code}") if game_pin is None: raise HTTPException(status_code=404, detail="Game not found") game = await redis.get(f"game:{game_pin}") game = PlayGame.parse_raw(game) # Check if game is already running if game.started: raise HTTPException(status_code=400, detail="Game started already") # check if username already exists if await redis.get(f"game_session:{game_pin}:players:{controller.player_name}") is not None: raise HTTPException(status_code=409, detail="Username already exists") player_id = os.urandom(5).hex() await redis.set(f"game:cqc:player:{player_id}", controller.player_name) return JoinGameResponse(id=f"{player_id}:{game_pin}") class RegisterWithCodeInput(BaseModel): code: str class RegisterWithCodeResponse(BaseModel): id: uuid.UUID secret_key: str @router.post("/register") async def register_with_code(data: RegisterWithCodeInput) -> RegisterWithCodeResponse: c_id = await redis.get(f"controller_setup:{data.code}") if c_id is None: raise HTTPException(status_code=404, detail="Code not found") await redis.delete(f"controller_setup:{data.code}") c_id = uuid.UUID(c_id) controller = await Controllers.objects.get(id=c_id) controller.first_seen = datetime.now() controller.last_seen = datetime.now() await controller.update() return RegisterWithCodeResponse(id=controller.id, secret_key=controller.secret_key) @router.get("/ping") async def ping_server(id: uuid.UUID, secret_key: str, version: str): controller = await Controllers.objects.get_or_none(id=id, secret_key=secret_key) if controller is None: raise HTTPException(status_code=404, detail="Key and/or id invalid") controller.last_seen = datetime.now() controller.os_version = version await controller.update()