Hate Me Chase Me
Hate Me Chase Me

Reputation: 131

No handler for message type websocket.group_send, how to fix?

i switch from one user websocket connection to make chat room, that 2 people can connect each other, but on switch, in recieve method, need now group_send, and after that it stoped work, how to fix?

Full Traceback

> Exception inside application: No handler for message type
> websocket.group_send   File
> "D:\Dev\Web\Chaty\lib\site-packages\channels\sessions.py", line 183,
> in __call__
>     return await self.inner(receive, self.send)   File "D:\Dev\Web\Chaty\lib\site-packages\channels\middleware.py", line 41,
> in coroutine_call
>     await inner_instance(receive, send)   File "D:\Dev\Web\Chaty\lib\site-packages\channels\consumer.py", line 59, in
> __call__
>     [receive, self.channel_receive], self.dispatch   File "D:\Dev\Web\Chaty\lib\site-packages\channels\utils.py", line 52, in
> await_many_dispatch
>     await dispatch(result)   File "D:\Dev\Web\Chaty\lib\site-packages\channels\consumer.py", line 75, in
> dispatch
>     raise ValueError("No handler for message type %s" % message["type"])   No handler for message type websocket.group_send
> WebSocket DISCONNECT /messages/dildo/ [127.0.0.1:58910]

Consumer

import asyncio
import json
from django.contrib.auth import get_user_model
from channels.consumer import AsyncConsumer
from channels.db import database_sync_to_async

from .models import Thread, ChatMessage



class ChatConsumer(AsyncConsumer):

    async def websocket_connect(self, event):
        print('Connected', event)
        other_user = self.scope['url_route']['kwargs']['username']
        me = self.scope['user']
        thread_obj = await self.get_thread(me, other_user)
        chat_room = f"thread_{thread_obj.id}"
        self.chat_room = chat_room
        await self.channel_layer.group_add(
            chat_room,
            self.channel_name
        )

        await self.send({
            'type':'websocket.accept'
        })

    async def websocket_receive(self, event):
        print('Recive', event)

        front_response = event.get('text', None)

        if front_response is not None:
            compiled_response_data = json.loads(front_response)

            if 'FormData' in compiled_response_data:
                pass
        author = str(self.scope['user'])

        Response_ = {
            'Message': compiled_response_data['FormData']['message'],
            'Author': author
        } 

        new_event = {
            'type':'websocket.send',
            'text': json.dumps(Response_)

        }
        print(new_event)
        await self.channel_layer.group_send(
            self.chat_room,
            new_event
        )
    async def websocket_disconnect(self, event):
        print('Disconnected', event)

    @database_sync_to_async
    def get_thread(self, user, other_username):
        return Thread.objects.get_or_new(user, other_username)[0]

my html template

{% extends "base.html" %}

{% block content %}
<h3>Thread for {% if user != object.first %}{{ object.first }}{% else %}{{ object.second }}{% endif %}</h3>
<ul id='chat-items'>
{% for chat in object.chatmessage_set.all %}

<li>{{ chat.message }} via {{ chat.user }}</li>

{% endfor %}
</ul>

<form id='form' method='POST'> {% csrf_token %}
{{form }}
<input type="text" name='porn'>
<input type="text" name='pov'>
<button type='submit' class='btn btn-primary'>Submit</button>
</form>

{% endblock %}

{% block script %}

<script>
    const from_user = '{{ object.first }}',
        to_user = '{{ object.second }}';
// websocket scripts
    let loc = window.location,
        path_first_part = 'ws://',
        path_second_part = loc.host + loc.pathname,
        endpoint = '',
        FormItself = $('#form'),
        FormData = $('#form input'),
        DataHolder = {},
        ChatItself = $("#chat-items");
    if (loc.protocol == 'https:'){
        path_first_part = 'wss://'
    }else{
        path_first_part = 'ws://'
    }
    endpoint = path_first_part + path_second_part
    let socket = new WebSocket(endpoint);

    socket.onmessage = function(e){
        console.log('Message', e);
        let parset_data = JSON.parse(e.data),
            Chat_MSG =  parset_data.Message,
            Chat_AUTHOR =  parset_data.Author;

        ChatItself.append('<li>' + Chat_MSG + ' <= via => ' + Chat_AUTHOR + '</li>');

    };
    socket.onopen = function(e){
        console.log('Open', e)
        FormItself.submit(function(event){
            event.preventDefault();
            DataHolder['FormData'] = {};
            FormData.each(function(key, value){
                DataHolder['FormData'][value.name] = value.value;
                value.value = '';
            })
            socket.send(JSON.stringify(DataHolder));
        })
        console.log(DataHolder)
    };
    socket.onerror = function(e){
        console.log('Error', e)
    };
    socket.onclose = function(e){
        console.log('Close', e)
    };

</script>
{% endblock %}

It looks like your post is mostly code; please add some more details.

Upvotes: 5

Views: 8444

Answers (2)

SHORT ANSWER:

Сheck if you have other consumers with the same group name that do not have the required handler. There must be a unique group name for each consumer-class, unless you specifically want to do otherwise.

LONG ANSWER:

I ran into a similar issue. I had consumer connecting to group "user_1". When sending a message to group "user_1", I got exception "Exception inside application: No handler for message type new.message" and the connection was closed.

class MyFirstConsumer(JsonWebsocketConsumer):
    def connect(self):
        user = self.scope['user']
        if not user:
            self.close()
        else:
            async_to_sync(self.channel_layer.group_add)(f'user_{user.id}', self.channel_name)
            self.accept()

    def new_message(self, event):
        data = {
            'msg_type': 'new_message',
            'data': event['data']
        }
        self.send_json(data)

After digging into the code, I found that I have 2 different consumers that connect to the same group.

class MySecondConsumer(JsonWebsocketConsumer):
    def connect(self):
        user = self.scope['user']
        if not user:
            self.close()
        else:
            async_to_sync(self.channel_layer.group_add)(f'user_{user.id}', self.channel_name)
            self.accept()

    # no handler here "new_message"

    def some_another_handler(self, event):
        data = {
            'msg_type': 'new_message',
            'data': event['data']
        }
        self.send_json(data)

When sending a message through

await channel_layers.group_send(
    'user_1',
    {
        'type': 'new.message',
        'data': {
            'text': 'some_text'
        }
    }
)

both consumers receive messages. The first consumer, which I thought was the problem, processed it without errors, but the second consumer did not have the right handler. Therefore, a leading error occurred in the second consumer. I changed the group names for different consumers and everything worked as it should.

class MyFirstConsumer(JsonWebsocketConsumer):
    def connect(self):
        user = self.scope['user']
        if not user:
            self.close()
        else:
            async_to_sync(self.channel_layer.group_add)(f'user_first_consumer_{user.id}', self.channel_name)
            self.accept()

    def new_message(self, event):
        data = {
            'msg_type': 'new_message',
            'data': event['data']
        }
        self.send_json(data)

class MySecondConsumer(JsonWebsocketConsumer):
    def connect(self):
        user = self.scope['user']
        if not user:
            self.close()
        else:
            async_to_sync(self.channel_layer.group_add)(f'user_second_consumer_{user.id}', self.channel_name)
            self.accept()

    # no handler here "new_message"

    def some_another_handler(self, event):
        data = {
            'msg_type': 'new_message',
            'data': event['data']
        }
        self.send_json(data)

Do not forget to change the name of the group in the place of sending

await channel_layers.group_send(
    'user_first_consumer_1',
    {
        'type': 'new.message',
        'data': {
            'text': 'some_text'
        }
    }
)

Upvotes: 1

Hate Me Chase Me
Hate Me Chase Me

Reputation: 131

Brother, I’m glad to help you, I myself came across one as soon as you create a group, then you need to send messages to the group, that is, to type: 'websocket.send' in websocket_receive you need to put a callback function, and there you can already use sending a message to websocket.

new_event = {
            'type':'chat_message',
            'text': json.dumps(Response_)

        }

next create that chat_message callback func

async def chat_message(self, event):
    print('\n',event)
    front_response = event.get('text', None)
    if front_response is not None:
        compiled_response_data = json.loads(front_response)
    Response_ = {
        'Message': compiled_response_data['Message'],
        'Author': compiled_response_data['Author']
    } 

    # Send message to WebSocket
    await self.send({
        'type':'websocket.send',
        'text': json.dumps(Response_)
    })

so finally your consumer will be looks like this.

import asyncio
import json
from django.contrib.auth import get_user_model
from channels.consumer import AsyncConsumer
from channels.db import database_sync_to_async

from .models import Thread, ChatMessage



class ChatConsumer(AsyncConsumer):

    async def websocket_connect(self, event):
        print('Connected', event)
        other_user = self.scope['url_route']['kwargs']['username']
        me = self.scope['user']
        thread_obj = await self.get_thread(me, other_user)
        chat_room = f"thread_{thread_obj.id}"
        self.chat_room = chat_room
        await self.channel_layer.group_add(
            chat_room,
            self.channel_name
        )

        await self.send({
            'type':'websocket.accept'
        })

    async def websocket_receive(self, event):
        print('Recive', event)

        front_response = event.get('text', None)

        if front_response is not None:
            compiled_response_data = json.loads(front_response)

            if 'FormData' in compiled_response_data:
                pass
        author = str(self.scope['user'])

        Response_ = {
            'Message': compiled_response_data['FormData']['message'],
            'Author': author
        } 

        new_event = {
            'type':'chat_message',
            'text': json.dumps(Response_)

        }
        await self.channel_layer.group_send(
            self.chat_room,
            new_event
        )
    async def websocket_disconnect(self, event):
        print('Disconnected', event)

    # Receive message from room group
    async def chat_message(self, event):
        print('\n',event)
        front_response = event.get('text', None)
        if front_response is not None:
            compiled_response_data = json.loads(front_response)
        author = str(self.scope['user'])
        Response_ = {
            'Message': compiled_response_data['Message'],
            'Author': author
        } 
        message = event['text']

        # Send message to WebSocket

        await self.send({
            'type':'websocket.send',
            'text': json.dumps(Response_)
        })

    @database_sync_to_async
    def get_thread(self, user, other_username):
        return Thread.objects.get_or_new(user, other_username)[0]

    #saving to db
    @database_sync_to_async
    def create_chat_message(self, author, msg):
        thread_obj = self.thread_obj
        return ChatMessage.objects.create(thread=thread_obj, user=author, message=msg)

Upvotes: 8

Related Questions