How to use the same connection for two differents consummers in Django Channels?

Viewed 873

I use the last version of django channels(V3) and i have two consummers.

This is my routing.py

application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter([
            url(r"^ws/user/(?P<user_id>\d+)/$", consumers.UserConsumer),
            url(r"^ws/notification/(?P<room_name>\w+)/$", con.NotificationConsumer),

        ])
    ),
})

My first app.consummes.py

class UserConsumer(WebsocketConsumer):
    user_number = 0
    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['user_id']
        self.room_group_name = self.room_name
        print("connected", self.room_group_name)

        self.user_number+= 1
        print("user_number", self.user_number)
        # 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
        print("deconnected")

        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )

        # Receive message from WebSocket

    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        proposal_identifiant = text_data_json['proposal_identifiant']
        sender = text_data_json['sender']
        messages = text_data_json['messages']
        owner = text_data_json['owner']
        conversator = text_data_json['conversator']
        last_sender = text_data_json['last_sender']
        type_ad = text_data_json['type_ad']
        ad_id = text_data_json['ad_id']
        price = text_data_json['price']
        sending_by = text_data_json['sending_by']
        price_is_changed = text_data_json['price_is_changed']
        accepted = text_data_json['accepted']
        from_send_message = text_data_json['from_send_message']
        users_id = []
        users_id.append(owner)
        users_id.append(conversator)
        winner_or_looser = text_data_json['winner_or_looser']

        try:

            try:
                if proposal_identifiant and get_current_proposal(proposal_identifiant):
                    # we create message if proposal exist
                    if accepted == False:
                        update_proposal(proposal_identifiant, last_sender, price, price_is_changed, accepted)
                        create_new_message(proposal_identifiant, sender, messages)
                    else:

                        if from_send_message == True:
                            update_proposal(proposal_identifiant, last_sender, price, price_is_changed, accepted)
                            create_new_message(proposal_identifiant, sender, messages)
                        else:
                            try:
                                create_new_delivery(
                                    owner,
                                    conversator,
                                    proposal_identifiant,
                                    type_ad,
                                    ad_id,
                                    price,
                                    accepted,
                                )
                                create_new_message(proposal_identifiant, sender, messages)
                                winner_or_looser =  True
                            except IntegrityError:
                                print("error")
                                return self.send(text_data=json.dumps({
                                    'error': "IntergyError"
                                }))

                else:
                    # we create at first proposal and message
                    # print("new_proposal")
                    new_proposal = create_new_proposal(
                        owner,
                        conversator,
                        last_sender,
                        type_ad,
                        ad_id,
                        price
                    )
                    # print(new_proposal.id)
                    proposal_identifiant = new_proposal.id
                    # print(proposal_identifiant)
                    create_new_message(proposal_identifiant=new_proposal.id, sender=sender, messages=messages)

                for id in users_id:
                    self.room_group_name = str(id)
                    # Send message to room group
                    # print(self.room_group_name)
                    async_to_sync(self.channel_layer.group_send)(
                        self.room_group_name,
                        {
                            'type': 'chat_message',
                            'proposal_identifiant': proposal_identifiant,
                            'sender': sender,
                            'messages': messages,
                            'statut': True,
                            'read_or_not': False,
                            'owner': owner,
                            'conversator': conversator,
                            'last_sender': last_sender,
                            'type_ad': type_ad,
                            'ad_id': ad_id,
                            'price': price,
                            'sending_by': sending_by,
                            'price_is_changed': price_is_changed,
                            'accepted': accepted,
                            'from_send_message': from_send_message,
                            'winner_or_looser':winner_or_looser,


                        }
                    )

            except:
                raise

        except:
            raise

        # Receive message from room group

    def chat_message(self, event):
        proposal_identifiant = event['proposal_identifiant']
        sender = event['sender']
        messages = event['messages']
        owner = event['owner']
        conversator = event['conversator']
        last_sender = event['last_sender']
        type_ad = event['type_ad']
        ad_id = event['ad_id']
        price = event['price']
        sending_by = event['sending_by']
        price_is_changed = event['price_is_changed']
        accepted = event['accepted']
        from_send_message = event['from_send_message']
        winner_or_looser = event['winner_or_looser']

        # Send message to WebSocket
        self.send(text_data=json.dumps({
            'proposal_identifiant': proposal_identifiant,
            'sender': sender,
            'messages': messages,
            'owner': owner,
            'conversator': conversator,
            'last_sender': last_sender,
            'type_ad': type_ad,
            'ad_id': ad_id,
            'price': price,
            'sending_by': sending_by,
            'price_is_changed': price_is_changed,
            'accepted': accepted,
            'from_send_message': from_send_message,
            'winner_or_looser': winner_or_looser,
        }))

And my second app.consummer.py

class NotificationConsumer(WebsocketConsumer):
    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = self.room_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
        print("deconnected")

        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )

        # Receive message from WebSocket

    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        print("notif", text_data_json)
        message = text_data_json['message']
        from_user = text_data_json['from_user']
        to_user = text_data_json['to_user']
        users_id = []
        users_id.append(from_user)
        users_id.append(to_user)

        # Send message to room group
        for id in users_id:
            self.room_group_name = str(id)
            async_to_sync(self.channel_layer.group_send)(
                self.room_group_name,
                {
                    'type': 'chat_message',
                    'message': message,
                    'from_user': from_user,
                    'to_user': to_user,
                }
            )

        # Receive message from room group

    def chat_message(self, event):
        message = event['message']

        from_user = event['from_user']
        to_user = event['to_user']

        # Send message to WebSocket
        self.send(text_data=json.dumps({
            'message': message,
            'from_user': from_user,
            'to_user': to_user,
        }))

How to use the same connection for differents consummers? because two differents connections doesn't works. I got error.

I tried many way but no success

1 Answers

You cannot connect the same socket connection to two different consumers ie

Django-channels documentation says
Channels routers only work on the scope level, not on the level of individual events,
which means you can only have one consumer for any given connection.
Routing is to work out what single consumer to give a connection, not how to spread events
from one connection across multiple consumers.

In your browser console write[javascript] the following code and hit enter

var socket = new WebSocket('ws://localhost:8000/ws/user/(?P<user_id>\d+)/$'); 
var socket2 = new WebSocket('ws://localhost:8000/ws/notification/(?P<room_name>\w+)/$');  

and check if both of them connect to django-server; in my perspective both of them should connect since both the consumers are in different apps(ie my-first-app & my-second-app as you mentioned).

from my understanding what you want to do is connect a single socket which would handle user-related stuff on UserConsumer and notification on another NotificationConsumer.
For this you would have to create multiple event-handlers for(Notification alone in the same .consumers.py file) which would get trigger whenever a notification needs to be sent.
Or else you can use your existing implementation but variable "socket2" will handle notification.

Related