fix: matchmaking support start stop, multi connection

This commit is contained in:
starnakin 2023-12-23 16:47:22 +01:00
parent 6c39a13aca
commit c02c49215d
5 changed files with 92 additions and 32 deletions

View File

@ -14,7 +14,7 @@ class MatchMaking
this.searching = false; this.searching = false;
} }
async start(func, mode) async start(receive_func, disconnect_func, mode)
{ {
if (!await this.client.isAuthentificate()) if (!await this.client.isAuthentificate())
return null; return null;
@ -25,10 +25,21 @@ class MatchMaking
this.searching = true; this.searching = true;
this.receive_func = receive_func;
this.disconnect_func = disconnect_func;
this._socket.onmessage = function (event) { this._socket.onmessage = function (event) {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
func(data.game_id) receive_func(data);
}; };
this._socket.onclose = this.onclose.bind(this);
}
onclose(event)
{
this.stop();
this.disconnect_func()
} }
async stop() async stop()

View File

@ -1,11 +1,7 @@
import { client, navigateTo } from "../index.js"; import { client, navigateTo } from "../index.js";
import { clear, fill_errors } from "../utils/formUtils.js";
import AbstractView from "./abstracts/AbstractView.js"; import AbstractView from "./abstracts/AbstractView.js";
function game_found(game_id)
{
navigateTo(`/games/${game_id}`)
}
export default class extends AbstractView { export default class extends AbstractView {
constructor(params) constructor(params)
{ {
@ -21,28 +17,36 @@ export default class extends AbstractView {
} }
else else
{ {
await this.matchmaking(); let nb_players = document.getElementById("nb_players-input").value
await client.matchmaking.start(this.display_data, this.ondisconnect, nb_players);
document.getElementById("button").value = "Stop matchmaking" document.getElementById("button").value = "Stop matchmaking"
} }
} }
async matchmaking() ondisconnect()
{ {
let nb_players = document.getElementById("nb_players-input").value document.getElementById("button").value = "Find a game"
}
client.matchmaking.start(game_found, nb_players); display_data(data)
{
clear("innerText", ["detail"]);
fill_errors(data, "innerText");
} }
async postInit() async postInit()
{ {
document.getElementById("button").onclick = this.matchmaking document.getElementById("button").onclick = this.press_button.bind(this)
} }
async getHtml() { async getHtml() {
return ` return `
<h1>Select mode<h1> <h1>Select mode</h1>
<input type="number" value="2" id="nb_players-input"> <input type="number" value="2" id="nb_players-input">
<input type="button" value="Find a game" id="button"> <input type="button" value="Find a game" id="button">
<span id="detail"></span>
`; `;
} }

View File

@ -39,4 +39,4 @@ class MatchMaking(WebsocketConsumer):
waiting_room: WaitingRoom = normal.get(self.mode) waiting_room: WaitingRoom = normal.get(self.mode)
waiter: Waiter = waiting_room.get_waiter_by_socket(self) waiter: Waiter = waiting_room.get_waiter_by_socket(self)
if (waiter is not None): if (waiter is not None):
waiting_room.remove(self.scope["user"].pk) waiting_room.remove(waiter)

View File

@ -10,17 +10,16 @@ class Waiter:
self.user_id: int = user_id self.user_id: int = user_id
self.socket: WebsocketConsumer = socket self.socket: WebsocketConsumer = socket
def send(self, data: dict): def send(self, detail: str, data: dict = {}):
self.socket.send(text_data=json.dumps(data)) raw_data: dict = {"detail": detail}
raw_data.update(data)
self.socket.send(text_data=json.dumps(raw_data))
def accept(self): def accept(self):
self.socket.accept() self.socket.accept()
def disconnect(self): def disconnect(self):
self.socket.disconnect() self.socket.disconnect(200)
def __eq__(self, obj):
return self.user_id == obj.user_id
class WaitingRoom: class WaitingRoom:
@ -29,10 +28,10 @@ class WaitingRoom:
self._mode: int = mode self._mode: int = mode
self._waiting_room_manager = waiting_room_manager self._waiting_room_manager = waiting_room_manager
def broadcast(self, data: dict): def broadcast(self, detail: str, data: dict = {}):
for waiter in self._waiter_list: for waiter in self._waiter_list:
waiter: Waiter waiter: Waiter
waiter.send(data) waiter.send(detail, data)
def clear(self): def clear(self):
self._waiter_list.clear() self._waiter_list.clear()
@ -44,20 +43,25 @@ class WaitingRoom:
return waiter return waiter
return None return None
def append(self, waiter: Waiter): def get_waiter_by_user_id(self, user_id: int):
for waiter in self._waiter_list:
waiter: Waiter
if (waiter.user_id == user_id):
return waiter
return None
self.remove(waiter)
def append(self, waiter: Waiter):
tmp: Waiter = self.get_waiter_by_user_id(waiter.user_id)
if (tmp is not None):
tmp.send("Connection close: Another connection open with the same user id.")
self.remove(tmp)
waiter.accept() waiter.accept()
self._waiter_list.append(waiter) self._waiter_list.append(waiter)
def remove(self, users_id): def remove(self, waiter: Waiter):
for waiter in self._waiter_list: self._waiter_list.remove(waiter)
waiter: Waiter = waiter waiter.disconnect()
if (waiter == users_id):
waiter.disconnect()
if (self.empty()):
self._waiting_room_manager.remove(self)
return
def empty(self): def empty(self):
for _ in self._waiter_list: for _ in self._waiter_list:

41
tournament/consumers.py Normal file
View File

@ -0,0 +1,41 @@
from channels.generic.websocket import WebsocketConsumer
from django.contrib.auth.models import User
from games.models import GameModel
import json
from .models import Waiter, WaitingRoom, WaitingRoomManager, normal
class TournamentWaitingRoom(WebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.channel_name = "tournament"
self.group_name = "tournament"
def connect(self):
user: User = self.scope["user"]
if (user.is_anonymous or not user.is_authenticated):
return
self.channel_layer.group_add(self.group_name, self.channel_name)
self.tournament_id = int(self.scope['url_route']['kwargs']['tournament_id'])
waiting_room: WaitingRoom = normal.get(self.mode)
waiting_room.append(Waiter(user.pk, self))
print(len(waiting_room), "/", self.mode, [len(waiting_room),self.mode])
if (len(waiting_room) == self.mode):
game_id: int = GameModel().create(waiting_room.get_users_id())
waiting_room.broadcast({"detail": "Game found !", "game_id": game_id})
waiting_room.clear()
def disconnect(self, close_code):
waiting_room: WaitingRoom = normal.get(self.mode)
waiter: Waiter = waiting_room.get_waiter_by_socket(self)
if (waiter is not None):
waiting_room.remove(self.scope["user"].pk)