194 lines
6.3 KiB
Python
194 lines
6.3 KiB
Python
import redis
|
|
import json
|
|
import uuid
|
|
import random
|
|
import hashids
|
|
import asyncio
|
|
from fastapi import FastAPI
|
|
from starlette.responses import HTMLResponse
|
|
from starlette.exceptions import HTTPException
|
|
from pydantic import BaseModel
|
|
from typing import List, Dict
|
|
# pylint: disable=unused-wildcard-import
|
|
from .models import *
|
|
from starlette.websockets import WebSocket
|
|
from starlette.middleware.cors import CORSMiddleware
|
|
|
|
hashes = hashids.Hashids("a very good salt yes this is nice ok",
|
|
4, "ABCDEFGHJKLMNPQRSTUVXYZ23456789")
|
|
|
|
app = FastAPI(title="Cards against idiots")
|
|
r = redis.Redis(host='redis', port=6379, password='yeet')
|
|
app.add_middleware(CORSMiddleware, allow_origins=[
|
|
'*'], allow_methods=["*"], allow_headers=["*"])
|
|
|
|
# loop = asyncio.get_event_loop()
|
|
# r = aioredis.create_redis("redis://redis", loop=loop)
|
|
cards = {}
|
|
|
|
with open("cards.json", encoding="UTF-8") as file:
|
|
cards = json.load(file)
|
|
|
|
|
|
@app.get("/cards/random", response_model=Card)
|
|
async def get_random_card():
|
|
return random.choice(cards["black"])
|
|
|
|
|
|
@app.get("/packs", response_model=Dict[str, Pack])
|
|
async def get_all_packs():
|
|
return cards["metadata"]
|
|
|
|
|
|
@app.get("/packs/{id}")
|
|
async def get_pack(id: str):
|
|
return cards["metadata"][id]
|
|
|
|
|
|
@app.websocket("/ws/room/{code}/{kind}")
|
|
async def ws_room(ws: WebSocket, code: str, kind: str):
|
|
await ws.accept()
|
|
if kind == "sub":
|
|
ps = r.pubsub()
|
|
ps.subscribe(code)
|
|
while True:
|
|
# 1: Message from pub/sub
|
|
msg = ps.get_message()
|
|
if msg and type(msg["data"]) is bytes:
|
|
await ws.send_bytes(msg["data"].decode("utf-8"))
|
|
elif msg:
|
|
await ws.send_text("1")
|
|
else:
|
|
await asyncio.sleep(0)
|
|
|
|
elif kind == "pub": # 2: Message from WS
|
|
while True:
|
|
msg = Message(**(await ws.receive_json()))
|
|
get_r = r.hget("rooms", code)
|
|
# Room should already be created even if we are the first person to join
|
|
if not get_r:
|
|
await ws.close()
|
|
return
|
|
|
|
room = Room(**json.loads(get_r))
|
|
|
|
if msg.msgtype is MessageType.JOIN:
|
|
# ps.subscribe(code)
|
|
name: str = str(msg.data)
|
|
|
|
if room.started:
|
|
await ws.send_text("you fucked up dawg")
|
|
await ws.close()
|
|
return
|
|
if len(name) > 25:
|
|
return ws.close(1009)
|
|
p = Player(name=name, uuid=uuid.uuid4())
|
|
|
|
if not room.admin_uuid:
|
|
room.admin_uuid = p.uuid
|
|
|
|
room.players.append(p)
|
|
|
|
r.hset("rooms", room.code, room.json())
|
|
|
|
await ws.send_json({"msgtype": "JOIN", "data": {"owner": room.admin_uuid == p.uuid, "you": len(room.players)-1, "uuid": str(p.uuid)}})
|
|
await ws.send_json({"msgtype": "ROOM", "data": PubRoom(**room.dict()).dict()})
|
|
r.publish(code, Message(msgtype=MessageType.ROOM,
|
|
data=PubRoom(**room.dict())).json())
|
|
elif msg.msgtype is MessageType.START:
|
|
pid: str = str(msg.data)
|
|
|
|
if pid == str(room.admin_uuid):
|
|
room.started = True
|
|
r.hset("rooms", room.code, room.json())
|
|
|
|
r.publish(code, Message(msgtype=MessageType.ROOM,
|
|
data=PubRoom(**room.dict())).json())
|
|
if room.started and not next_round(code):
|
|
await ws.close()
|
|
|
|
elif msg.msgtype is MessageType.ANSWER:
|
|
answer = AnswerReceived(**json.loads(msg.data))
|
|
|
|
mapper = {str(p.uuid): i for i, p in enumerate(room.players)}
|
|
|
|
mapped = AnswerSending(**answer.dict(), index=mapper[str(answer.uuid)])
|
|
room.answers.append(mapped)
|
|
r.hset("rooms", room.code, room.json())
|
|
|
|
if len(room.answers) == (len(room.players) - 1):
|
|
r.publish(code, Message(
|
|
msgtype=MessageType.ANSWER, data=room.answers).json())
|
|
|
|
elif msg.msgtype is MessageType.PICK:
|
|
answer = AnswerSendingButItHasAUUIDBecauseItIsImportantToCheckIfItWasSentByTheCzar(
|
|
**json.loads(msg.data))
|
|
if str(answer.uuid) != str(room.players[room.czar].uuid):
|
|
continue
|
|
r.publish(code, Message(
|
|
msgtype=MessageType.PICK, data=answer).json())
|
|
room.players[answer.index].points += 1
|
|
|
|
r.hset("rooms", room.code, room.json())
|
|
r.publish(code, Message(msgtype=MessageType.ROOM,
|
|
data=PubRoom(**room.dict())).json())
|
|
|
|
next_round(code)
|
|
else:
|
|
raise HTTPException(400, "That's an illegal (message type)!")
|
|
|
|
else:
|
|
await ws.close()
|
|
|
|
|
|
def next_round(code: str):
|
|
get_r = r.hget("rooms", code)
|
|
|
|
# Room should exist if we want to start it
|
|
if not get_r:
|
|
return False
|
|
|
|
room = Room(**json.loads(get_r))
|
|
room.answers = []
|
|
cardid = random.randrange(0, len(cards["black"]))
|
|
while cardid in room.played_cards:
|
|
cardid = random.randrange(0, len(cards["black"]))
|
|
room.played_cards.append(cardid)
|
|
room.czar = (room.czar + 1) % len(room.players)
|
|
|
|
r.hset("rooms", room.code, room.json())
|
|
|
|
r.publish(code, Message(
|
|
msgtype=MessageType.START,
|
|
data=RoundStart(czar=room.czar, card=cards["black"][cardid])).json())
|
|
r.publish(code, Message(msgtype=MessageType.ROOM,
|
|
data=PubRoom(**room.dict())).json())
|
|
return True
|
|
|
|
|
|
@app.get("/")
|
|
async def memes():
|
|
return cards
|
|
|
|
|
|
@app.post("/room", response_model=Room)
|
|
async def create_room():
|
|
n = r.incr("RoomCounter")
|
|
room = Room(number=n, code=hashes.encode(n))
|
|
r.hset("rooms", room.code, room.json())
|
|
|
|
return room
|
|
|
|
|
|
@app.get("/room/{code}", response_model=PubRoom)
|
|
async def get_room_by_id(code: str):
|
|
try:
|
|
return Room(**json.loads(r.hget("rooms", code)))
|
|
except:
|
|
raise HTTPException(404, "Room not found!")
|
|
|
|
|
|
@app.get("/rooms", response_model=Dict[str, PubRoom])
|
|
async def dump_redis():
|
|
return {k: Room(**json.loads(v)) for k, v in r.hgetall("rooms").items()}
|