Sending messages to all user's devices with django channels
I have been developing project. It uses django channels for websockets. And I meet a problem with sending ws messages to all device of the same account that is logged in. It is not a rare situation when many users use same accounts while project is under developing. So when one user is logged in and the other user is logged in and then he is logged out the first user does not receive messages.
I tried to count devices but that method changes nothing.
My consumer is:
class NotificationConsumer(AsyncWebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(args, kwargs)
self.user = None
self.pool_name = None
async def connect(self):
self.user = self.scope["user"]
self.pool_name = f"user_id_{self.scope['url_route']['kwargs']['user_id']}"
await self.accept()
# Join pool
created = await self.add_online_user()
if created:
await self.channel_layer.group_add(
self.pool_name,
self.channel_name,
)
async def disconnect(self, close_code):
# Leave room group
removed = await self.remove_online_user()
if removed:
await self.channel_layer.group_discard(self.pool_name, self.channel_name)
# Receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json["message"]
# Send message to room group
await self.channel_layer.group_send(self.pool_name, {"type": "read_message", "message": message})
# Receive message from room group
async def notification_message(self, event):
message = event["message"]
await self.send(text_data=json.dumps({"message": [message]}, ensure_ascii=False))
@database_sync_to_async
def add_online_user(self):
online_user = OnlineUser.objects.filter(user=self.user).first()
if not online_user:
OnlineUser.objects.create(user=self.user, counter=1)
return True
else:
if online_user.counter:
online_user.counter += 1
else:
online_user.counter = 2
online_user.save()
return False
@database_sync_to_async
def remove_online_user(self):
online_user = OnlineUser.objects.filter(user=self.user).first()
if online_user:
if online_user.counter:
if online_user.counter == 1 or online_user.counter is None:
online_user.delete()
return True
else:
online_user.counter -= 1
online_user.save()
return False
else:
online_user.delete()
return True
OnlineUser model:
class OnlineUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="online_user")
counter = models.IntegerField(null=True, blank=True)
And send message method
def send_messages(notifications):
channel_layer = get_channel_layer()
mark_as_send = []
for notification in notifications:
online_user = User.objects.filter(online_user__user=notification.to_user)
if online_user.exists():
message = NotificationSerializer(notification).data
data = {"type": "notification_message", "message": message}
async_to_sync(channel_layer.group_send)(f"user_id_{notification.to_user.id}", data)
mark_as_send.append(notification.id)
Finally I got that message is marked as send but it is not received. And it is not a problem with frontend because i do not receive message in Postman too.
only a single reader should get each written message. -- in docs So it is not supported by django channels. Am I right?