0
votes

How to determine to message to particular set of listeners?

For example, I have Luke,Jason and Bruce in ChatRoom A. Lisa in Chatroom B.And each member has a message list screen which only display the last message of group chat room.

I have a socket connection placed on every chatroom to listen incoming messages. Group messages from particular chatroom will have an room identifier along with message. The question is that how websocket to determine to send out messages only to those people who has subscribed to this chatroom?

This websocket conncetion will receive msgs from diffrent room but it needs only to send msgs out to those who belongs to that particular group chat room.

Do I need add some identifier in somewhere when I establish connection from client side so that serverside could know if it needs to send msgs to me?

Here is my connect function:

class GroupMessageListConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.userId = str(self.scope['query_string'])[2:-1].split("=")[1]

        # self.eventId = self.scope['url_route']['kwargs']['eventId']

        print('GroupMessageListConsumer connected self.userId:{}'.format(self.userId))

        # print('GroupMessageListConsumer connected self.userId:{}'.format(self.userId))
        # print('GroupMessageListConsumer connected self.eventId:{}'.format(self.eventId))

        # Join room group
        await self.channel_layer.group_add(
            self.userId,
            self.channel_name
        )

        await self.accept()


    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(
            self.userId,
            self.channel_name
        )
1
You need to pass along the room identifier along with the message. {"room": 123, "message": "hi"}. Then within your consumer's receive method check for appropriate room and pass on. - whitehat
Can I set an identifier to websocket when it get establish? For example, pass an user.id to connect function. Therefore, I can check it later when I received message from receive function to determine if I need to send out message for this particular user - HE xinhao
Yes, you can do that. Within the connect method, you need to check and add the user to their respective rooms. - whitehat
Do you know how can I pass some data to connect function when websocket get eastablished? I shall pass data as url parameters or in somewhere else? - HE xinhao

1 Answers

0
votes

Create a separate Model Room

class Room(models.model):
    users = models.ManyToManyField(
        "User",
        related_name='rooms',
        blank=True,
        symmetrical=False)

Before getting to consumer.py, Make sure your payload consists of these three:

event_type: What caused this event? a user is sending a message? you are sending a notification to a user? Is this an alert?

data: What data is sent along?

errors: Are there any errors?

Example payloads:

{ "event_type": "send_message", "data": { "message": "Hi", "room": 143, }, "errors": None }

{ "event_type": "send_notif", "data": { "message": "You received a friend request from xxx", "type": "friend_request", }, "errors": None }

Consumer.py

class GroupMessageListConsumer(AsyncWebsocketConsumer):
    user = None
    async def connect(self):
        self.user = self.scope["user"] #authenticated user either passed in through session or by token authentication

        print("connection request received.")

        await self.accept()
        print("connection accepted")

        #channel/channel_name is the current open socket connection between your browser and the server

        # Join channel or user to his rooms
        for room in self.user.rooms:
            await self.channel_layer.group_add(
                room.id,
                self.channel_name
            )

    async def disconnect(self, close_code):
        #remove current channel from listening to messages as it is closed or disconnected
        # Leave channel from all rooms
        for room in self.user.rooms:
            await self.channel_layer.group_discard(
                room.id,
                self.channel_name
            )
        print("channel disconnected.")
        raise StopConsumer()


    async def receive(self,text_data):
        print("message received.")
        text_data_json = json.loads(text_data)
        #always maintain payload with three main fields: "event_type", "data", "errors"
        event_type = text_data_json['event_type']
        data = text_data_json['data']
        if event_type=="send_message":
            #check whether user is allowed to send messages to room 143

            #Then send the message to that room.
            await self.channel_layer.group_send(
                data["room"],
                {
                    'type': "send_message", #call the respective event "async def send_message(self, event)" see below
                    'message': {
                        'event_type': event_type,
                        'data': {"message": data["message"], "user": self.user.id},
                        'errors': None
                    }
                }
            )
        else:
            print("event_type unknown")

    async def send_message(self, event):
        message =  event['message']
        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            'message': message
        }))