Amrutha P
Amrutha P

Reputation: 11

How many users are there in the chat session (django-channels)?

Basically I have created the chat application but i don't know how to show that how many users has been joined the chat group.Briefly i want to show name of the user and they are online/offline. I have tried import Group but then i came to know that it has been deprecated and then tried django-channel-presence but now able to understand. Kindly Help !

# chat/consumers.py
# Sorry   πŸ˜…πŸ˜…for my code

import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer, AsyncJsonWebsocketConsumer
from django.contrib.auth import get_user_model
from .models import Message
from django.db.models.signals import post_save
from django.dispatch import receiver

# import channels
# from channels.auth import channel_session_user, channel_session_user_from_http

User = get_user_model()

class ChatConsumer(WebsocketConsumer):

    def new_message(self, data):
        author = data['from']
        author_user = User.objects.filter(username=author)[0]
        message = Message.objects.create(
            author=author_user,
            content=data['message'])
        content = {
            'command': 'new_message',
            'message': self.message_to_json(message)
        }

        return self.send_chat_message(content)

    # def messages_to_json(self, messages):
    #     result = []
    #     for message in messages:
    #         result.append(self.message_to_json(message))
    #     return result

    def message_to_json(self, message):
        return {
            'id': message.id,
            'author': message.author.username,
            'content': message.content,
            'timestamp': str(message.timestamp)
        }

    commands = {
        'new_message': new_message
    }

    # PREDEFINED
# ***************************************************************************************************************************
    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        print("self.scope['url_route']['kwargs']['room_name'] : "+self.scope['url_route']['kwargs']['room_name'])

        self.room_group_name = 'chat_%s' % self.room_name
        print("self.room_group_name : " + self.room_group_name)

        print("self.channel_name, : " + self.channel_name)

        # Join room group
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )

        self.accept()

# ***************************************************************************************************************************
    def disconnect(self, close_code):
        # Leave room group
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )

    # ***************************************************************************************************************************
    # Receive message from WebSocket
    # def receive(self, text_data):
    #     data = json.loads(text_data)
    #     message = data['message']
    #     # Send message to room group
    #     async_to_sync(self.channel_layer.group_send)(
    #         self.room_group_name,
    #         {
    #             'type': 'chat_message',
    #             'message': message
    #         }
    #     )   # receives from chat/room.html


    def receive(self, text_data):
        data = json.loads(text_data)
        self.commands[data['command']](self, data)  # determining what command was sent

    def send_chat_message(self, message):
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

# ***************************************************************************************************************************
    # Receive message from room group    # receives from chat/room.html
    # def chat_message(self, event):
    #     message = event['message']
    #
    #     # Send message to WebSocket
    #     self.send(text_data=json.dumps({
    #         'message': message
    #     }))
    #

    def send_message(self, message):
        self.send(text_data=json.dumps(message))

    def chat_message(self, event):
        message = event['message']
        self.send(text_data=json.dumps(message))


My script where i am handling messages at frontend

    <script >
        <!------------------------------------------------------------------------------------------------------------------------------>
        <!------------------------------------------------------------------------------------------------------------------------------>

         const roomName = {{room_name}};
         const username = {{ username }};

        const user_count = [];

        <!--  e here represents an event  -->

        const chatSocket = new ReconnectingWebSocket(
            'ws://'
            + window.location.host
            + '/ws/chat/'
            + roomName
            + '/'
        );
        console.log('window location testing : '+window.location.host);

        chatSocket.onmessage = function(e)
        {
            const data = JSON.parse(e.data);
            var message = data['message'];
            var author = data['author'];

            var msgListTag = document.createElement('li');
            var pTag = document.createElement('p');
            var pAuth = document.createElement('p');
            pTag.setAttribute('style', 'white-space: pre;');
            pTag.textContent = message.author+"\r\n";
            pTag.textContent += message.content;

            if(message.author == username)
            {
                msgListTag.className = 'sent' ;
            }
            else
            {
                msgListTag.className = 'replies' ;
            }

            msgListTag.appendChild(pTag);

            document.querySelector('#chat-log').appendChild(msgListTag);

        };
        <!-- from consumers.py "message"  -->

        chatSocket.onclose = function(e) {
            console.error('Chat socket closed unexpectedly');
        };

        document.querySelector('#chat-message-input').onkeyup = function(e) {
            if (e.keyCode === 13) {  // enter, return
                document.querySelector('#chat-message-submit').click();
            }
        };

        <!--  important action  -->

        document.querySelector('#chat-message-submit').onclick = function(e) {
            const messageInputDom = document.querySelector('#chat-message-input');
            const message = messageInputDom.value;

            if(messageInputDom.value == '')
            {
                console.log('Enter a text');
            }
            else
            {
                chatSocket.send(JSON.stringify({
                    'command': 'new_message',
                    'message': message,
                    'from': username
                }));
            }
            messageInputDom.value = '';
        };

    </script>

Upvotes: 1

Views: 1296

Answers (1)

Husam Alhwadi
Husam Alhwadi

Reputation: 531

You can create a separate model to track the connected and disconnected users; user will be added to the model when they connect to room chat and will be deleted upon disconnect.

In models.py:

from django.db import models
from django.contrib.auth.models import User

class Connected(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="connected")
    room_name = models.CharField(max_length=100, null=False)
    channel_name = models.CharField(max_length=100, null=False)
    connect_date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.user

In consumer.py, create 2 functions (connect_user and disconnect_user):

@sync_to_async
def connect_user(room_name, user, channel_name):
    if user:
        Connected.objects.create(user=user room_name=room_name, channel_name=channel_name)
    else:
        pass
    return None


@sync_to_async
    def disconnect_user(room_name, user, channel_name):
    if user:
        try:
            get_object_or_404(Connected, Q(user=user), Q(room_name=room_name), Q(channel_name=channel_name))
        except:
            pass
        else:
            user = get_object_or_404(Connected, Q(user=user), Q(room_name=room_name), Q(channel_name=channel_name))
            user.delete()
    return None

Calling them from consumer.py:

Class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
    self.room_name = self.scope['url_route']['kwargs']['room_name']
    self.room_group_name = 'chat_%s' % self.room_name

    # Join room group
    await self.channel_layer.group_add(
        self.room_group_name,
        self.channel_name
    )
    await self.accept()
    # add user to Connected model
    await connect_user(room_name=self.room_name, user=self.scope['user'], channel_name=self.channel_name)

async def disconnect(self, close_code):
    # Leave room group

    await self.channel_layer.group_discard(
        self.room_group_name,
        self.channel_name
    )
    # Remove user from Connetced Model
    await disconnect_user(room_name=self.room_name, user=self.scope['user'], channel_name=self.channel_name)

From there, you can run queryset to check if a user is connected to a particular room_name or not (if a user exists, then it's connected otherwise it's not connected) and you can even check the number of connected users per room_name.

Upvotes: 1

Related Questions