несколько экземпляров websocket для приложения чата

#django #websocket

Вопрос:

Я создаю приложение для чата на Django-Vue, я уже создал основную функциональность приложения.

При подключении компонента боковой панели выполняется HTTP-запрос для получения всех комнат, участником которых является пользователь, при нажатии на какую-либо комнату в компоненте Чата создается экземпляр WebSocket.

Я сомневаюсь, что если я отправлю сообщение в эту комнату, но другие пользователи не подключены в той же комнате (при условии, что они подключены в другой комнате), они не получат сообщение, верно? Итак, как я отправлю ему уведомление о новом сообщении? например, уведомления на боковой панели Whatsapp.

Я думал о создании двух подключений к WebSocket, одно на боковой панели, которое будет конечной точкой пользователя ( ws:127.0.0.1:8000/chat/$Username ), а другое для реальной комнаты чата ( ws:127.0.0.1:8000/chat/$ChatId ), это хороший подход?

Мои модели django =>

 from django.db import models
from account.models import CustomUser

class Message(models.Model):
    sender = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='messages')
    message = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'message from {self.sender.username}'

class Chat(models.Model):
    name = models.CharField(max_length=24)
    participants = models.ManyToManyField(CustomUser, blank=True)
    messages = models.ManyToManyField(Message, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name
 

Ответ №1:

Вы можете использовать WSS в качестве транспортного уровня, но реализовать свой собственный логический протокол.

Конечно, вы можете использовать несколько подключений, но это избыточно. Давайте использовать что-то вроде «события». Например, для пользователя, подключенного к комнате чата, вы можете отправить событие «подключение» :

 {
    "event": "connection",
    "user": {
        "id": 1,
        "username": "Foo",
        ...
    }
}
 

Вы можете справиться с таким событием с помощью простого подхода:

 if event == "connection":
    ...
elif event == "exit":
elif event == "message":
...

 

И тот же подход, но на стороне клиента с кодом JS.

Таким образом, вы можете обрабатывать только одно соединение как для приложения Vue, так и для Django.

Комментарии:

1. В решении, которое вы разместите, каждый пользователь будет подключен к конечной точке websocket? chat/$USERNAME ? Должен ли я дублировать self.channel_layer.group_send для отправки свое имя пользователя и целевое имя пользователя? Я действительно потерял поток.

2. Конечно, вы можете создать пул соединений для хранения состояния соединения с каждым пользователем. Лично я не использую Django для создания серверов WS в своих проектах. Есть 2 причины: Django (с DRF) крут как API, мощный ORM и администратор; в качестве асинхронной платформы я использую Starlette.io, он имеет встроенную поддержку WS и асинхронность по дизайну starlette.io/websockets и вы можете легко запустить его через ту же инфраструктуру (с некоторыми дополнениями). Итак, вы можете создать 2 сервиса: API с БД и ORM на Django; сервис WS. Дополнительные плюсы — в вашем стеке у вас будет второй инструмент для истинной асинхронности.

3. Каналы не могут делать то, что делает Старлетт? должен ли я переодеться? Все данные на сайте обрабатываются с помощью DRF.

4. Конечно, вы можете использовать структуру каналов, но если вы хотите использовать подход микросервиса, будет удобно создать автономную службу WS. Вам необходимо использовать DRF API через HTTP. Таким образом, DRF будет использоваться в обоих подходах. Starlette намного проще, чем слои каналов, и это добавит дополнительную структуру в ваш стек для простых сервисов.