Reputation: 3457
Now I'm building a website using django and angular, And I want to add websocket communication between client and server. I followed the instructions of django channel documentation.( https://channels.readthedocs.io/ ) I want to send any event from any place of django server code. But when multiple users connect via socket, the data sent from server always goes to the last connected user. And here's what I did. First in consumers.py, I defined my ChatConsumer class as follows and added a new handler named "tweet_send" function
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
...
# here's what I added a new tweet send handler
async def tweet_send(self, event):
content = event['content']
content["group_name"] = self.room_group_name
# Send message to WebSocket
await self.send(text_data=json.dumps({
"type": "MESSAGE",
"data": content
}))
And somewhere of django server side(in serializers.py), when a new tweet is created, I send a new tweet data to all users using django.channel_layer
...
def create(self, validated_data):
...
new_tweet.save()
# send message via channels
channel_layer = get_channel_layer()
all_users = list(Member.objects.filter(is_active = True).values_list('id', flat = True))
for user_id in all_users:
async_to_sync(channel_layer.group_send)(
"chat_{}".format(user_id), # this is the group name of group name of individual users.
{ "type": "chat_message", "message": "tweet created" }
)
And in Angular websocket service
init(userID: number): void{
if(this.ws){
this.ws.close();
}
this.ws = new WebSocket(`${environment.WEBSOCKET_URL}/chat/${userID}/`);
this.ws.onopen = () => {
this.currentWebSocketSubject.subscribe(data => {
if (data) {
this.ws?.send(JSON.stringify(data));
}
});
};
this.ws.onmessage = (event) => {
console.log("message arrived");
console.log(event);
if (event.data) {
const tempData: WS = JSON.parse(event.data) as WS;
switch (tempData.type) {
case 'MESSAGE':
console.log("message arrived");
console.log(tempData);
if (tempData.data) {
this.unreadMessages++;
this.messageSubject.next(tempData);
}
break;
}
}
};
}
When I test those codes, I used two clients, two clients logged in, and connected to the django server via websockets successfully. When I create a tweet, django server sends event to every channel using channel_layer.group_send function, and in ChatConsumer class the added "tweet_send" function sends the event to the user. And these events are meant to different users respectively. But they are all sent to lastly websocket-connected user. I don't know why. Please help me.
Upvotes: 5
Views: 4570
Reputation: 316
I can see this question has been here for a long time. There is one problem with your code, and that problem is that the tweet send handler in your consumer (tweet_send) is not matching the message type you're sending to the group from your serializers.py.
So to fix this problem, you have to rename your tweet send handler method to match the message type you're sending to the group, which in this case is chat_message. So your tweet send handler becomes:
# tweet send handler
async def chat_message(self, event):
content = event['content']
content["group_name"] = self.room_group_name
# Send message to WebSocket
await self.send(text_data=json.dumps({
"type": "MESSAGE",
"data": content
}))
I hope this help.
Upvotes: 0
Reputation: 26
I think you must be using channels 3.0.0 and this error occurs. I suggest you should upgrade channels version to 3.0.1 or 3.0.2. Then the error will disappear.
Upvotes: 1