app.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import os
  2. import datetime
  3. import uuid
  4. from enum import Enum
  5. from typing import Optional
  6. from fastapi import FastAPI, HTTPException
  7. from fastapi.middleware.cors import CORSMiddleware
  8. from pydantic import BaseModel
  9. import aiosqlite
  10. DB_FILE = os.environ.get("DB_LOCATION", "tank.db")
  11. LAST_UPDATE = datetime.datetime.now()
  12. app = FastAPI()
  13. app.add_middleware(
  14. CORSMiddleware,
  15. allow_origins=["*"],
  16. allow_credentials=False,
  17. allow_methods=["*"],
  18. allow_headers=["*"],
  19. )
  20. @app.on_event("startup")
  21. async def startup():
  22. async with aiosqlite.connect(DB_FILE) as db:
  23. await db.execute('CREATE TABLE IF NOT EXISTS games (\
  24. id TEXT NOT NULL PRIMARY KEY, \
  25. name TEXT NOT NULL, \
  26. state TEXT CHECK( state IN ("LOBBY", "PLAYING", "FINISHED")) NOT NULL DEFAULT "LOBBY", \
  27. width INTEGER NOT NULL, \
  28. height INTEGER NOT NULL, \
  29. distribute TEXT DEFAULT NULL, \
  30. players TEXT NOT NULL DEFAULT "" \
  31. );')
  32. await db.commit()
  33. class CreateGame(BaseModel):
  34. name: str
  35. width: int
  36. height: int
  37. class GameInfo(BaseModel):
  38. id: str
  39. name: str
  40. class GamesList(BaseModel):
  41. games: list[GameInfo]
  42. class GameState(str, Enum):
  43. lobby = "LOBBY"
  44. playing = "PLAYING"
  45. finished = "FINISHED"
  46. class Game(BaseModel):
  47. name: str
  48. state: GameState
  49. width: int
  50. height: int
  51. distribute: Optional[str]
  52. players: str
  53. @app.get("/games")
  54. async def games() -> GamesList:
  55. async with aiosqlite.connect(DB_FILE) as db:
  56. async with db.execute("SELECT id, name FROM games;") as cursor:
  57. results = await cursor.fetchall()
  58. return GamesList(games=[GameInfo(id=r[0], name=r[1]) for r in results])
  59. @app.put("/game")
  60. async def create_game(create: CreateGame) -> GameInfo:
  61. game_id = uuid.uuid4().hex
  62. async with aiosqlite.connect(DB_FILE) as db:
  63. await db.execute("INSERT INTO games \
  64. (id, name, width, height) VALUES \
  65. (:id, :name, :width, :height)\
  66. ;", {
  67. "id": game_id,
  68. "name": create.name,
  69. "width": create.width,
  70. "height": create.height,
  71. })
  72. await db.commit()
  73. return GameInfo(id=game_id, name=create.name)
  74. @app.get("/game/{game_id}")
  75. async def get_game(game_id: str) -> Game:
  76. async with aiosqlite.connect(DB_FILE) as db:
  77. async with db.execute("SELECT name, state, width, height, distribute, players FROM games WHERE id = ?", (game_id,)) as cursor:
  78. result = await cursor.fetchone()
  79. if result is None:
  80. raise HTTPException(status_code=404)
  81. return Game(
  82. name=result[0],
  83. state=result[1],
  84. width=result[2],
  85. height=result[3],
  86. distribute=result[4],
  87. players=result[5],
  88. )