1
votes

I am working on a chat app that has Rooms. Each room has two users. A user can be in multiple rooms i.e, a user has multiple rooms. And now he is chatting in one room. But he receives a message in another room. I would like to notify about the message from other room to the user. How should I implement this?

Currently a websocket connection is established as: ws://localhost:8000/chat/int<room_id>/

And the group_name is named as "room"+room_id. and So far I have:

async def connect(self):
    room_id = self.scope['url_route']['kwargs']['room_id']
    await self.channel_layer.group_add(
            "room"+room_id,
            self.channel_name
        )
    await self.accept()

async def receive(self, text_data):
    await self.channel_layer.group_send(
        self.room_name,
        {
            'type': 'chat_message',
            'message': json.loads(text_data)
        }
    )
async def chat_message(self, event):
    await self.send(text_data=json.dumps({
        'message': event['message']
    }))

Django 2.x django-channels 2.x python 3.6

3

3 Answers

1
votes

You need at least two models Message, MessageThread. When the user connects to the socket the channel is added to each thread group that the user is included in. You also have to add the channel_name to the user session.

messaging/models.py

class MessageThread(models.Model):
    title = models.CharField()
    clients = models.ManyToManyField(User, blank=True)

class Message(models.Model):
    date = models.DateField()
    text = models.CharField()
    thread = models.ForeignKey('messaging.MessageThread', on_delete=models.CASCADE)
    sender = models.ForeignKey(User, on_delete=models.SET_NULL)

chat/consumers.py

class ChatConsumer(WebSocketConsumer):
    def connect(self):
        if self.scope['user'].is_authenticated:
            self.accept()
            # add connection to existing groups
            for thread in MessageThread.objects.filter(clients=self.scope['user']).values('id'):
                async_to_sync(self.channel_layer.group_add)(thread.id, self.channel_name)
            # store client channel name in the user session
            self.scope['session']['channel_name'] = self.channel_name
            self.scope['session'].save()

    def disconnect(self, close_code):
        # remove channel name from session
        if self.scope['user'].is_authenticated:
            if 'channel_name' in self.scope['session']:
                del self.scope['session']['channel_name']
                self.scope['session'].save()
            async_to_sync(self.channel_layer.group_discard)(self.scope['user'].id, self.channel_name)
0
votes

I do something similar, you can try something like this:

connect(message):
    // however you get your chatroom value from the socket
    Group("%s" % chatroom).add(message.reply_channel)

message(message):
    message = json.loads(message.content['text'])
    chatroom = message['chatroom']  
    Group("%s" % chatroom).send({
            "text": json.dumps({
                "id": "newuser",
                "username": message['username'],
                "message": message['message']
            })
        })

I might have misread your question. Maybe something more like:

Create a unique id for each user and use that value as the 'chatroom', then send each message with a chatroom number and the user number that it should go to. Django can interpret the user id and sent the message to the right channel, then have the Javascript interpret it the message and roomnumber to bring them to the right page?

That is an interesting idea

0
votes

(idea:)I opened two sockets:

  1. one for current room which user is texting in
  2. the second for chat rooms list (a hidden base chatroom created as well; better to say: a channel layer that belongs to chat rooms list),

then on every message received from any user in the first explained channel(above), I will send proper reply to both of the sockets.

example at here: chatroom.subtionary.com (just click on one chatroom and enter with email) it also reorder the chat rooms list and pulse the element and also write the last message of each chatroom under its element, also enjoy reply and delete options!!

(I know this is the laziest way, but works well)