add tournament request to server(not complete)

This commit is contained in:
2024-10-05 02:40:15 +02:00
parent 0200a360e9
commit 4e3ba36416
16 changed files with 238 additions and 45 deletions

View File

@ -12,7 +12,7 @@ RUN apt install -y python3.12 postgresql-client
RUN curl https://bootstrap.pypa.io/get-pip.py -o /root/get-pip.py RUN curl https://bootstrap.pypa.io/get-pip.py -o /root/get-pip.py
RUN python3.12 /root/get-pip.py RUN python3.12 /root/get-pip.py
RUN pip3 install requests django psycopg "channels[daphne]" RUN pip3 install requests django psycopg "channels[daphne]" multimethod
ARG DB_HOST ARG DB_HOST
ARG DB_NAME ARG DB_NAME

View File

@ -0,0 +1,78 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# Tournament.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/04 17:17:07 by tomoron #+# #+# #
# Updated: 2024/10/05 02:35:50 by tomoron ### ########.fr #
# #
# **************************************************************************** #
import string
import asyncio
from .utils import genString
class Tournament:
currentTournamentsLock = False
currentTournaments = {}
playerLimit = 8
def __init__(self, socket):
self.messages = []
self.players = []
while(Tournament.currentTournamentsLock):
continue;
Tournament.currentTournamentsLock = True
self.genCode()
Tournament.currentTournaments[self.code] = self
Tournament.currentTournamentsLock = False
self.join(socket)
def genCode(self):
nbChar = 4
self.code = genString(nbChar, string.ascii_uppercase)
nbIter = 0
while(self.code in Tournament.currentTournaments):
if(nbIter == 100):
nbInter = 0
nbChar += 1
self.code = genString(nbChar, string.ascii_uppercase)
nbIter += 1
def broadcast(self, content):
for x in self.players:
x.sync_send("tournament",content)
def sendAllInfo(self, socket):
players = []
for x in self.players:
players.append({"id":socket.id,"username":socket.username, "pfp":socket.pfp})
socket.sync_send("tournament",{"action":5, "players":players, "messages" : self.messages})
def sendMessage(self, socket, message):
messages.append({"username":socket.username, "message":message})
if(len(messages) > 20):
messages.pop(0)
self.broadcast({"action":3, "username":socket.username, "message":socket.message})
def leave(self, socket):
if(socket not in self.players):
return;
index = self.players.index(socket)
self.players.pop(index)
socket.tournament = None
self.broadcast({"action":2,"id":socket.id})
def join(self, socket):
if(socket.tournament != None):
socket.sendError("already in a tournament", 9036)
return
if(len(self.players) == Tournament.playerLimit):
socket.sync_send("tournament",{"action":0, "isFull":True})
return
socket.tournament = self
self.players.append(socket)
socket.sync_send("tournament",{"action":0,"isFull":False, "isStarted":False,"exist":True, "code":self.code})
self.broadcast({"action":1, "id":socket.id, "username": socket.username,"pfp":socket.pfp})

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ # # By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ # # +#+#+#+#+#+ +#+ #
# Created: 2024/09/23 23:35:41 by edbernar #+# #+# # # Created: 2024/09/23 23:35:41 by edbernar #+# #+# #
# Updated: 2024/09/27 03:37:33 by tomoron ### ########.fr # # Updated: 2024/10/04 21:13:28 by tomoron ### ########.fr #
# # # #
# **************************************************************************** # # **************************************************************************** #
@ -23,9 +23,12 @@ def changePfp(socket, content):
generate_name = genString(50) generate_name = genString(50)
if (not User.objects.filter(pfp=f"/pfp/{generate_name}.jpg").exists()): if (not User.objects.filter(pfp=f"/pfp/{generate_name}.jpg").exists()):
break break
with open(f"/var/www/djangoserver/pfp/{generate_name}.jpg", "wb") as image_file:
image_file.write(base64.b64decode(content["img"]))
user = User.objects.get(id=socket.id) user = User.objects.get(id=socket.id)
user.pfp = f"/pfp/{generate_name}.jpg" user.pfp = f"/pfp/{generate_name}.jpg"
user.save() user.save()
with open(f"/var/www/djangoserver/pfp/{generate_name}.jpg", "wb") as image_file: socket.pfp = user.pfp
image_file.write(base64.b64decode(content["img"])) socket.scope["session"]["pfp"] = user.pfp
socket.scope["session"].save()
socket.sync_send(json.dumps({"type": "change_pfp", "content": {'pfp': user.pfp}})) socket.sync_send(json.dumps({"type": "change_pfp", "content": {'pfp': user.pfp}}))

View File

@ -6,7 +6,7 @@
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ # # By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ # # +#+#+#+#+#+ +#+ #
# Created: 2024/09/09 16:10:26 by tomoron #+# #+# # # Created: 2024/09/09 16:10:26 by tomoron #+# #+# #
# Updated: 2024/10/01 16:35:10 by tomoron ### ########.fr # # Updated: 2024/10/04 17:10:39 by tomoron ### ########.fr #
# # # #
# **************************************************************************** # # **************************************************************************** #
@ -73,6 +73,9 @@ from .gameActions.ping import ping
action_list = [start, ready, leave, move, ping] action_list = [start, ready, leave, move, ping]
async def gameRequest(socket, content): async def gameRequest(socket, content):
if("action" not in content):
socket.sendError("missing action parameter",9035)
return
action = content["action"] action = content["action"]
if(action < 0 or action > len(action_list)): if(action < 0 or action > len(action_list)):
socket.sendError("Action out of range", 9100) socket.sendError("Action out of range", 9100)

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ # # By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ # # +#+#+#+#+#+ +#+ #
# Created: 2024/08/03 08:10:38 by edbernar #+# #+# # # Created: 2024/08/03 08:10:38 by edbernar #+# #+# #
# Updated: 2024/09/30 19:43:54 by tomoron ### ########.fr # # Updated: 2024/10/04 23:35:03 by tomoron ### ########.fr #
# # # #
# **************************************************************************** # # **************************************************************************** #
@ -25,26 +25,29 @@ def userExists(mail, password):
if(not user.exists()): if(not user.exists()):
return({"found":False}) return({"found":False})
else: else:
return({"found":True, "id":user[0].id, "username":user[0].username, "mail_verified":user[0].mail_verified}) return({"found":True, "id":user[0].id, "username":user[0].username, "mail_verified":user[0].mail_verified, "pfp":user[0].pfp})
async def loginByPass(socket, content): async def loginByPass(socket, content):
u_info = await userExists(content["mail"],content["password"]) try:
if(u_info["found"]): u_info = await userExists(content["mail"],content["password"])
if(not u_info["mail_verified"]): if(u_info["found"]):
socket.sendError("Account not verified, please verify your account before logging in",9025) if(not u_info["mail_verified"]):
return socket.sendError("Account not verified, please verify your account before logging in",9025)
if(await socket.login(u_info["id"], u_info["username"])): return
await socket.setLastLogin() if(await socket.login(u_info["id"], u_info["username"], u_info["pfp"])):
socket.sync_send(json.dumps({"type":"logged_in", "content":{ await socket.setLastLogin()
"status":True, socket.sync_send(json.dumps({"type":"logged_in", "content":{
"username":u_info["username"], "status":True,
"id": u_info["id"], "username":u_info["username"],
"haveUnreadMessage": await getUnreadStatus(u_info["id"]) "id": u_info["id"],
}})) "haveUnreadMessage": await getUnreadStatus(u_info["id"])
}}))
else:
socket.sendError("An unknown error occured",9027)
else: else:
socket.sendError("An unknown error occured",9027) socket.sync_send(json.dumps({"type": "error", "content": "Invalid email or password", "code": 9007}))
else: except Exception as e:
socket.sync_send(json.dumps({"type": "error", "content": "Invalid email or password", "code": 9007})) socket.sendError("Invalid request", 9005, e)
async def login(socket, content): async def login(socket, content):
try: try:

View File

@ -0,0 +1,14 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# fetchAllData.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/05 02:08:12 by tomoron #+# #+# #
# Updated: 2024/10/05 02:08:52 by tomoron ### ########.fr #
# #
# **************************************************************************** #
async def fetchAllData(socket, content):
socket.tournament.sendAllInfo(socket)

View File

@ -0,0 +1,18 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# leave.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/04 18:05:07 by tomoron #+# #+# #
# Updated: 2024/10/05 02:28:42 by tomoron ### ########.fr #
# #
# **************************************************************************** #
async def tournamentLeave(socket, content):
print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" * 100)
if(socket.tournament == None):
socket.sendError("you're not in a tournament", 9037)
return;
socket.tournament.leave(socket)

View File

@ -0,0 +1,14 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# sendMessage.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/04 18:05:27 by tomoron #+# #+# #
# Updated: 2024/10/04 18:05:56 by tomoron ### ########.fr #
# #
# **************************************************************************** #
async def sendMessage(socket, content):
print("nope")

View File

@ -0,0 +1,22 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# start.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/04 17:16:02 by tomoron #+# #+# #
# Updated: 2024/10/05 02:28:50 by tomoron ### ########.fr #
# #
# **************************************************************************** #
from ...Tournament import Tournament
async def tournamentStart(socket, content):
if("code" in content and len(content["code"])):
if(content["code"] in Tournament.currentTournaments):
Tournament.currentTournaments[content["code"]].join(socket)
else:
socket.sync_send("tournament",{"action":0, "exist":False})
else:
Tournament(socket)

View File

@ -6,26 +6,31 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ # # By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ # # +#+#+#+#+#+ +#+ #
# Created: 2024/10/01 13:16:39 by edbernar #+# #+# # # Created: 2024/10/01 13:16:39 by edbernar #+# #+# #
# Updated: 2024/10/03 01:29:01 by edbernar ### ########.fr # # Updated: 2024/10/05 02:33:45 by tomoron ### ########.fr #
# # # #
# **************************************************************************** # # **************************************************************************** #
from .tournamentActions.start import tournamentStart
from .tournamentActions.leave import tournamentLeave
from .tournamentActions.sendMessage import sendMessage
from .tournamentActions.fetchAllData import fetchAllData
# tournament request format : {"type":"tournament", "content":{"action": 1, ...}} # tournament request format : {"type":"tournament", "content":{"action": 1, ...}}
#server actions (actions sent by the server): #server actions (actions sent by the server):
# 0 : start : tell the client if tournament is full or not exist. If not, tell the client can start the tournament # 0 : start : tell the client if tournament is full or not exist. If not, tell the client can start the tournament
# - exist : true/false # - exists : true/false
# - isFull : true/false # - isFull : true/false
# - started : true/false # - started : true/false
# - code : code of the tournament # - code : code of the tournament
# #
# 1 : someoneJoin : tell the client someone join the tournament (considering clients will place selon the order of the join) # 1 : someoneJoined : tell the client someone joined the tournament (considering clients will place depending on the order of the join)
# - id : id of the player # - id : id of the player
# - username : name of the player # - username : name of the player
# - pfp : pfp of the player # - pfp : pfp of the player
# #
# 2 : someoneLeave : tell the client someone leave the tournament (if game not started, players will be replaced in the order of the join) # 2 : someoneLeft : tell the client someone left the tournament (if game not started, players will be replaced in the order of the join)
# - id : id of the player who leave # - id : id of the player who left
# #
# 3 : message : send a message to the tournament chat # 3 : message : send a message to the tournament chat
# - username : name of the player who send the message # - username : name of the player who send the message
@ -35,11 +40,15 @@
# - id : id of the player # - id : id of the player
# - username : name of the player # - username : name of the player
# #
# 5 : allData : gives tournament data to the client
# - players : [{id, username, pfp}, ...]
# - messages : [{username, message}]
#client actions (actions sent by the client) : #client actions (actions sent by the client) :
# 0 : start : start a tournament. if code == "", create a new tournament, else join the tournament with the code # 0 : start : start a tournament. if code == "", create a new tournament, else join the tournament with the code
# - code : code of the tournament # - code : code of the tournament
#
# 1 : leave : leave the tournament # 1 : leave : leave the tournament
# #
# 2 : message tournament : send a message to the tournament chat # 2 : message tournament : send a message to the tournament chat
@ -48,4 +57,16 @@
# 3 : fetchAllData : fetch all data of the tournament # 3 : fetchAllData : fetch all data of the tournament
# --> server will send all the data of the tournament (players, messages, etc...) with his actions # --> server will send all the data of the tournament (players, messages, etc...) with his actions
actionList = [tournamentStart, tournamentLeave, sendMessage, fetchAllData]
async def tournamentRequest(socket, content):
if("action" not in content):
socket.sendError("missing action parameter",9035)
return
action = content["action"]
if(action < 0 or action > len(actionList)):
socket.sendError("Action out of range", 9100)
return;
if(action != 0 and socket.tournament == None):
socket.sendError("you're not in a tournament",9037)
return ;
await actionList[action](socket,content)

View File

@ -27,6 +27,7 @@ urlpatterns = [
path("profilPage", views.profilPage, name='profilPage'), path("profilPage", views.profilPage, name='profilPage'),
# path("game", views.game, name='game'), # path("game", views.game, name='game'),
path("wait_game", views.game, name='wait_game'), path("wait_game", views.game, name='wait_game'),
path("tournament", views.tournament, name='tournament'),
path("login42", views.login42, name='login42'), path("login42", views.login42, name='login42'),
path("logout", views.logout, name='logout'), path("logout", views.logout, name='logout'),
path("verify", views.verify, name='verify'), path("verify", views.verify, name='verify'),

View File

@ -6,12 +6,12 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ # # By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ # # +#+#+#+#+#+ +#+ #
# Created: 2024/09/27 03:36:08 by tomoron #+# #+# # # Created: 2024/09/27 03:36:08 by tomoron #+# #+# #
# Updated: 2024/09/27 11:23:51 by edbernar ### ########.fr # # Updated: 2024/10/04 18:59:25 by tomoron ### ########.fr #
# # # #
# **************************************************************************** # # **************************************************************************** #
import random import random
import string
def genString(length): def genString(length, letters=string.ascii_letters+string.digits):
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return(''.join(random.choice(letters) for i in range(length))) return(''.join(random.choice(letters) for i in range(length)))

View File

@ -122,6 +122,8 @@ def login42(request):
request.session["logged_in"] = True request.session["logged_in"] = True
request.session["username"] = db_user[0].username request.session["username"] = db_user[0].username
request.session["id"] = db_user[0].id request.session["id"] = db_user[0].id
request.session["pfp"] = db_user[0].pfp
request.session.save()
return redirect("/") return redirect("/")
def logout(request): def logout(request):
@ -165,3 +167,6 @@ def tournamentPage(request):
if(not request.session.get("logged_in", False)): if(not request.session.get("logged_in", False)):
return(HttpResponse("you are not logged in",status=403)) return(HttpResponse("you are not logged in",status=403))
return render(request, "tournamentPage.html", {}) return render(request, "tournamentPage.html", {})
def tournament(request):
return redirect("/lobby")

View File

@ -6,12 +6,13 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ # # By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ # # +#+#+#+#+#+ +#+ #
# Created: 2024/09/09 14:31:30 by tomoron #+# #+# # # Created: 2024/09/09 14:31:30 by tomoron #+# #+# #
# Updated: 2024/09/30 19:42:45 by tomoron ### ########.fr # # Updated: 2024/10/04 21:06:20 by tomoron ### ########.fr #
# # # #
# **************************************************************************** # # **************************************************************************** #
from channels.generic.websocket import AsyncWebsocketConsumer from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async from asgiref.sync import sync_to_async
from multimethod import multimethod
from typing import Union from typing import Union
import json import json
import asyncio import asyncio
@ -36,16 +37,17 @@ from .typeRequests.changePrivateInfo import changePrivateInfo
from .typeRequests.changePfp import changePfp from .typeRequests.changePfp import changePfp
from .typeRequests.statusMessage import statusMessage,getUnreadStatus from .typeRequests.statusMessage import statusMessage,getUnreadStatus
from .typeRequests.readMessage import readMessage from .typeRequests.readMessage import readMessage
from .typeRequests.tournamentRequest import tournamentRequest
typeRequest = ["login", "get_private_list_user", "get_private_list_message", typeRequest = ["login", "get_private_list_user", "get_private_list_message",
"send_private_message", "create_account", "get_all_list_user", "game", "send_private_message", "create_account", "get_all_list_user",
"search_user", "get_user_info", "change_pfp", "change_banner", "game", "search_user", "get_user_info", "change_pfp", "change_banner",
"get_private_info", "change_private_info","status_message", "read_message" "get_private_info", "change_private_info","status_message", "read_message", "tournament"
] ]
functionRequest = [login, getPrivateListUser, getPrivateListMessage, functionRequest = [login, getPrivateListUser, getPrivateListMessage,
sendPrivateMessage, createAccount, getAllListUser, gameRequest, sendPrivateMessage, createAccount, getAllListUser, gameRequest,
searchUser, getUserInfo, changePfp, changeBanner, searchUser, getUserInfo, changePfp, changeBanner,
getPrivateInfo, changePrivateInfo, statusMessage, readMessage getPrivateInfo, changePrivateInfo, statusMessage, readMessage, tournamentRequest
] ]
from random import randint from random import randint
@ -83,7 +85,7 @@ class WebsocketHandler(AsyncWebsocketConsumer):
print("\033[32monline : ", self.onlinePlayers) print("\033[32monline : ", self.onlinePlayers)
return(0) return(0)
async def login(self, uid: int, username: str) -> int: async def login(self, uid: int, username: str, pfp : str) -> int:
if(await self.session_get("logged_in", False)): if(await self.session_get("logged_in", False)):
print("already logged in") print("already logged in")
return(0) return(0)
@ -93,15 +95,18 @@ class WebsocketHandler(AsyncWebsocketConsumer):
await self.session_set("logged_in",True) await self.session_set("logged_in",True)
await self.session_set("id",uid) await self.session_set("id",uid)
await self.session_set("username",username) await self.session_set("username",username)
await self.session_set("pfp", pfp)
await self.session_save() await self.session_save()
self.logged_in = True self.logged_in = True
self.id = uid self.id = uid
self.username = username self.username = username
self.pfp = pfp
return(1) return(1)
async def connect(self): async def connect(self):
self.logged_in = False self.logged_in = False
self.game = None self.game = None
self.tournament = None
self.id = 0 self.id = 0
self.username = None self.username = None
self.online = True self.online = True
@ -114,6 +119,7 @@ class WebsocketHandler(AsyncWebsocketConsumer):
return; return;
self.id = await self.session_get("id",0) self.id = await self.session_get("id",0)
self.username = await self.session_get("username", None) self.username = await self.session_get("username", None)
self.pfp = await self.session_get("pfp",None)
self.logged_in = True self.logged_in = True
await self.send(text_data=json.dumps({"type":"logged_in", "content":{ await self.send(text_data=json.dumps({"type":"logged_in", "content":{
"status":await self.session_get("logged_in",False), "status":await self.session_get("logged_in",False),
@ -133,6 +139,8 @@ class WebsocketHandler(AsyncWebsocketConsumer):
del self.onlinePlayers[uid] del self.onlinePlayers[uid]
if(self.game !=None): if(self.game !=None):
self.game.leave(self) self.game.leave(self)
if(self.tournament !=None):
self.tournament.leave(self)
async def receive(self, text_data): async def receive(self, text_data):
try: try:
@ -154,6 +162,11 @@ class WebsocketHandler(AsyncWebsocketConsumer):
except Exception as e: except Exception as e:
self.sendError("Invalid request", 9005, e) self.sendError("Invalid request", 9005, e)
@multimethod
def sync_send(self, reqType : str, content:dict):
self.sync_send({"type":reqType,"content":content})
@multimethod
def sync_send(self, data: Union[dict,str]): def sync_send(self, data: Union[dict,str]):
if(not self.online): if(not self.online):
return return

View File

@ -172,11 +172,6 @@ function startTournmament()
{ {
const code = document.getElementById('tournamentCode').value; const code = document.getElementById('tournamentCode').value;
if (code.length != 6 && code.length != 0)
{
CN.new("Information", "The code must be 6 characters long or empty");
return ;
}
sendRequest("tournament", {action: 0, code: code}); sendRequest("tournament", {action: 0, code: code});
} }

View File

@ -36,6 +36,9 @@
- 9032 : Your opponent isn't online - 9032 : Your opponent isn't online
- 9033 : Skin id out of range - 9033 : Skin id out of range
- 9034 : missing field - 9034 : missing field
- 9035 : missing action parameter
- 9036 : already in a tournament
- 9037 : you're not in a tournament
- 9100 : Action out of range - 9100 : Action out of range
- 9101 : No game started - 9101 : No game started