Reputation: 131
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
Reputation: 11
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
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