problem in real time match-making and lobby implementation

43 Views Asked by At

I want to implement a real time match making using web sockets for a 2 playered game .

I checked if there any waiting player by querying the data base (if channel_name``_2 = null). if yes connect incoming channel with waiting channel in database . However this fails in real time .for example consider two clients wanted to connect and there is single waiting player in db .Both get connected .here is my implementation.

consumers.py

import json
import random
from channels.generic.websocket import AsyncWebsocketConsumer
from django.db import IntegrityError 
from asgiref.sync import sync_to_async
from channels.db import database_sync_to_async
from .models import Game
from .generator import Generator

class LobbyConsumer(AsyncWebsocketConsumer): 
   
    @database_sync_to_async
    def anyWaitingPlayer(self):
        return Game.objects.filter(channel_name_2=None).count() > 0

    @database_sync_to_async
    def addPlayerToLobby(self , id  , channel_name_1):
        try:
            Game.objects.create(gameid=id  , channel_name_1 =channel_name_1).save()
        except IntegrityError as e:
            print(f"IntegrityError: {e}")
    @database_sync_to_async
    def waitingPlayerRoom(self , channel_name_2):
        waiting_games = Game.objects.filter(channel_name_2=None)
        earliest_game = waiting_games.earliest('time')
        id = earliest_game.gameid
        updated_record = Game.objects.get(gameid = id )
        updated_record.channel_name_2 = channel_name_2
        updated_record.save()
        return id 
    @database_sync_to_async
    def getGroupId(self , channel_name):
        if Game.objects.get(channel_name_1 = channel_name).gameid == None :
            return Game.objects.get(channel_name_2 = channel_name).gameid

    async def connect(self):
        # Get the unique channel name

        # if Any waiting player ,  pair new player with waiting player
        if await self.anyWaitingPlayer():
            id =await  self.waitingPlayerRoom(self.channel_name)

            await self.channel_layer.group_add(
                id,  
                self.channel_name
            )
            await self.send_group(id , id) 

        else :
            # id = "".join([chr(random.randint(65,91)) for c in range(10)])
            id  = Generator.generate_valid_group_name()
            await self.addPlayerToLobby(id , self.channel_name)
            await self.channel_layer.group_add(
                id,  
                self.channel_name
            )

        await self.accept()

    async def disconnect(self, close_code):
        # Remove the consumer from the group when disconnected
        id  = await self.getGroupId(self.channel_name) 
        await self.channel_layer.group_discard(
            id,  # Specify the group name
            self.channel_name
        )

    async def receive(self, text_data):
        # Receive and process the incoming message

        # Broadcast the message to all clients in the group
        await self.send_group(text_data, group='some_group')

    async def send_group(self, message, group):
        # Send message to a specific group
        await self.channel_layer.group_send(
            group,
            {
                'type': 'chat.message',
                'message': message
            }
        )

    async def chat_message(self, event):
        # Receive message from group
        message = event['message']

        # Send message to WebSocket
        await self.send(text_data=message)

models.py

from django.db import models

# Create your models here.
class Game(models.Model):
    channel_name_1 = models.CharField(max_length=255, unique=True)
    channel_name_2 = models.CharField(max_length=255, unique=True , null=True)
    gameid = models.CharField(max_length=255 , primary_key=True) 
    time  = models.TimeField(auto_now_add=True)

    def __str__(self):
        return f"Channel: {self.channel_name_1}, Group: {self.gameid}, Created At: {self.time}"

please improve this implementation to handle race conditions or suggest me standard way to implement matchmaking and lobby using web sockets .

0

There are 0 best solutions below