discord login

This commit is contained in:
2024-05-07 23:09:52 +02:00
parent 082e07c48b
commit ade051890e
15 changed files with 317 additions and 145 deletions
+36
View File
@@ -0,0 +1,36 @@
import requests
import os
def discord_process_code(code: str) -> dict | None:
response = requests.post(
url="https://discord.com/api/oauth2/token",
headers={
"Content-Type": "application/x-www-form-urlencoded",
},
data={
"client_id": os.environ["DISCORD_CLIENTID"],
"client_secret": os.environ["DISCORD_CLIENTSECRET"],
"code": code,
"grant_type": "authorization_code",
"redirect_uri": os.environ["FRONTEND_ENDPOINT"] + "/login",
"scope": "identify",
},
timeout=10,
)
json_data = response.json()
if "error" in json_data:
print(json_data)
return None
token_type = json_data["token_type"]
access_token = json_data["access_token"]
response = requests.get(
url="https://discord.com/api/users/@me",
headers={
"authorization": token_type + " " + access_token,
},
timeout=10,
)
return response.json()
+134 -76
View File
@@ -4,11 +4,14 @@ from typing import Callable, Any, TYPE_CHECKING
from pydantic import ValidationError
from websockets.server import WebSocketServerProtocol
from websockets.exceptions import ConnectionClosedOK
from netcode.models import Message, LoginMessage
from netcode.models import Message, LoginMessage, MessageType
from model import Player
from .auth import discord_process_code
if TYPE_CHECKING:
from controller import GameController
@@ -55,7 +58,7 @@ class ClientController:
"""Hooks the client to the correct listen callbacks"""
await self.send(
Message(
type="context",
type=MessageType.CONTEXT,
data_type="game_context_id",
data="login",
)
@@ -68,15 +71,18 @@ class ClientController:
async def send(self, message: Message) -> None:
"""Send a Message object to the connected client"""
await self.websocket.send(message.model_dump_json())
try:
await self.websocket.send(message.model_dump_json())
except ConnectionClosedOK:
print("Connection Closed")
async def send_error(self, error: str) -> None:
"""Send an error string to the connected client"""
await self.send(Message(type="error", data_type="error", data=error))
await self.send(Message(type=MessageType.ERROR, data_type="error", data=error))
async def send_announce_dict(
self,
notification_type: str,
notification_type: MessageType,
data: dict,
player_filter: Callable[[Player], Any] = lambda x: True,
):
@@ -89,65 +95,15 @@ class ClientController:
Message(type=notification_type, data_type="object", data=data)
)
@vibe_check(Message)
async def game_context(self, message: Message) -> None:
"""Handles all messages related to when the current client is logged in
and connected to a running game"""
if message.type == "temp_action":
if message.data_type == "set_health":
self.player.team.health = message.data
return await self.game_controller.game.notify_controller(
"update", self.player.team.serialize_guest()
)
if self.player.team != self.game_controller.game.current_turn:
return await self.send_error("it is not your turn to play!")
if message.type == "action":
# TODO : pydantic type check for message.data
match message.data_type:
case "play_card":
return await self.player.play_card(message.data)
case "discard":
return await self.player.turn.discard_card(message.data)
case "lock_card":
return await self.player.turn.lock_card(message.data)
case "use_effect":
return await self.player.turn.use_effect_with_check(
message.data.get("effect_id"), message.data.get("target")
)
case "buy":
return await self.player.turn.buy_card(message.data)
case "heal":
return await self.player.turn.heal(message.data)
case "damage_team":
return await self.player.turn.damage_team(message.data)
case "damage_champion":
return await self.player.turn.damage_champion(message.data)
case "end_turn":
return await self.player.turn.end_turn()
return await self.send_error(
"Couldn't process action with data_type : " + message.data_type
)
@vibe_check(LoginMessage)
async def login_context(self, message: LoginMessage) -> None:
"""Handles all messages related to when the current client isn't yet logged in"""
username = message.data
if self.game_controller.game.started:
return await self.send_error(
"you cannot interact with a game that has already started"
)
if message.type == "register":
if message.type == MessageType.REGISTER:
if self.game_controller.game.started:
return await self.send_error(
"you cannot interact with a game that has already started"
)
if len(username) < 3:
return await self.send_error(
"username must be longer than 3 characters"
@@ -157,36 +113,81 @@ class ClientController:
return await self.send_error("username already exists")
player = await self.game_controller.game.create_player(username)
elif message.type == "login":
elif message.type == MessageType.LOGIN:
player2 = self.game_controller.game.get_player(username)
if player2 is None:
return await self.send_error("player doesn't exists")
player = player2
elif message.type == MessageType.DISCORD_LOGIN:
user = discord_process_code(message.data)
if user is None:
await self.send_error("discord login not successful")
return
username = user["global_name"]
player = next(
(
p
for p in self.game_controller.game.players
if p.discord_id == user["id"]
),
None,
)
if player is None:
if self.game_controller.game.started:
return await self.send_error(
"you cannot interact with a game that has already started"
)
player = await self.game_controller.game.create_player(username)
player.discord_id = user["id"]
player.image = (
"https://cdn.discordapp.com/avatars/"
+ user["id"]
+ "/"
+ user["avatar"]
+ ".webp"
)
else:
return await self.send_error("invalid message type for context")
self.player = player
self.player.team.listeners.append(self.send_announce_dict)
self.on_message = self.pregame_context
if self.game_controller.game.started:
self.on_message = self.game_context
await self.send(
Message(
type=MessageType.CONTEXT, data_type="game_context_id", data="game"
)
)
for p in self.game_controller.game.players:
if p.team == player.team:
await self.send(
Message(
type=MessageType.UPDATE,
data_type="object",
data=player.serialize_team(),
)
)
else:
self.on_message = self.pregame_context
await self.send(
Message(
type=MessageType.CONTEXT,
data_type="game_context_id",
data="pregame",
)
)
print("user logged in : " + username)
await self.send(
Message(
type="set",
type=MessageType.SET,
data_type="self",
data=self.player.uuid,
)
)
await self.send(
Message(
type="context",
data_type="game_context_id",
data="pregame",
)
)
@vibe_check(Message)
async def pregame_context(self, message: Message) -> None:
@@ -197,9 +198,66 @@ class ClientController:
if all(p.ready for p in self.game_controller.game.players):
await self.game_controller.start_game()
elif message.type == "temp_action":
if message.data_type == "set_health":
self.player.team.health = message.data
await self.game_controller.game.notify_controller(
"update", self.player.team.serialize_guest()
)
@vibe_check(Message)
async def game_context(self, message: Message) -> None:
"""Handles all messages related to when the current client is logged in
and connected to a running game"""
# if message.type == "temp_action":
# if message.data_type == "set_health":
# self.player.team.health = message.data
# return await self.game_controller.game.notify_controller(
# "update", self.player.team.serialize_guest()
# )
if self.player.team != self.game_controller.game.current_turn:
return await self.send_error("it is not your turn to play!")
if message.type == "action":
# TODO : pydantic type check for message.data
match message.data_type:
case "play_card":
if not isinstance(message.data, str):
return
return await self.player.play_card(message.data)
case "discard":
if not isinstance(message.data, str):
return
return await self.player.turn.discard_card(message.data)
case "lock_card":
if not isinstance(message.data, str):
return
return await self.player.turn.lock_card(message.data)
case "use_effect":
return await self.player.turn.use_effect_with_check(
message.data.get("effect_id"), message.data.get("target")
)
case "buy":
if not isinstance(message.data, str):
return
return await self.player.turn.buy_card(message.data)
case "heal":
if not isinstance(message.data, int):
return
return await self.player.turn.heal(message.data)
case "damage_team":
if not isinstance(message.data, str):
return
return await self.player.turn.damage_team(message.data)
case "damage_champion":
if not isinstance(message.data, str):
return
return await self.player.turn.damage_champion(message.data)
case "end_turn":
return await self.player.turn.end_turn()
return await self.send_error(
"Couldn't process action with data_type : " + message.data_type
)
+15 -11
View File
@@ -1,8 +1,9 @@
import asyncio
from typing import Callable, List, Any
from websockets.exceptions import ConnectionClosedOK
from netcode import WSServer
from netcode.ws_server import WebSocketServerProtocol
from netcode.models import Message
from netcode.models import Message, MessageType
from model import Game, Player
from controller import (
ClientController,
@@ -31,14 +32,17 @@ class GameController:
self.clients.remove(client)
async def send(self, message: Message, websocket: WebSocketServerProtocol):
await websocket.send(message.model_dump_json())
try:
await websocket.send(message.model_dump_json())
except ConnectionClosedOK:
print("Connection Closed")
async def broadcast(self, message: Message):
await self.server.broadcast(message.model_dump_json())
async def broadcast_announce_dict(
self,
notification_type: str,
notification_type: MessageType,
data: dict,
player_filter: Callable[[Player], Any],
):
@@ -58,7 +62,7 @@ class GameController:
async def announce_dict(
self,
notification_type: str,
notification_type: MessageType,
data: dict,
websocket: WebSocketServerProtocol,
):
@@ -74,39 +78,39 @@ class GameController:
async def announce_game(self, websocket: WebSocketServerProtocol):
for effect in self.game.effects:
await self.announce_dict(
"create",
MessageType.CREATE,
effect.serialize(),
websocket,
)
for card in self.game.cards:
await self.announce_dict(
"create",
MessageType.CREATE,
card.serialize(),
websocket,
)
for team in self.game.teams:
await self.announce_dict(
"create",
MessageType.CREATE,
team.serialize(),
websocket,
)
for player in self.game.players:
await self.announce_dict(
"create",
MessageType.CREATE,
player.turn.serialize(),
websocket,
)
await self.announce_dict(
"create",
MessageType.CREATE,
player.serialize_guest(),
websocket,
)
await self.announce_dict(
"create",
MessageType.CREATE,
self.game.serialize_guest(),
websocket,
)
@@ -119,5 +123,5 @@ class GameController:
for c in self.clients:
c.on_message = c.game_context
await self.broadcast(
Message(type="context", data_type="game_context_id", data="game")
Message(type=MessageType.CONTEXT, data_type="game_context_id", data="game")
)