如何发送到当前频道房间和对端频道房间并在两端显示消息?

问题描述 投票:0回答:0

我正在考虑创建一个模型来处理保存和创建组,如下所示:


# Something like this perhaps...
class OneOnOneRoom(models.Model):
    room_name = models.CharField(max_length = 100, unique=True)
    sender = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
    receiver = models.ForeignKey(User, null=True, on_delete=models.CASCADE)

    def __str__(self):
        return f'Group {self.room_name} initiated by {self.sender} for {self.receiver}'

然后在我的消费者的连接方法中,我需要以某种方式创建两个房间,这样我就可以广播来自用户 A 或用户 B 的所有消息以发送到两个房间,以便两个用户都可以看到彼此的消息。

因此,如果用户 A 为

http://localhost:8000:chat/B
并且用户 B 为
http://localhost:8000:chat/A
;用户A应该向自己的通道和B的通道发送数据;用户 B 应该将数据发送到自己的通道和 B 的通道。

这是一个很好的解决方案吗?我现在想不出任何更好的解决方案——无论哪种方式,我都找不到在频道中一次实际发送到多个频道的方法。有什么建议吗?

我一直在尝试和思考:

#asgi.py
application = ProtocolTypeRouter({
    "http": django_asgi_app,

    "websocket": AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                re_path(r"ws/chat/(?P<room_name>\w+)/$", ChatConsumer.as_asgi()),
            ])
        )
    ),
})

#urls.py
urlpatterns = [
    path('<str:room_name>/', room),
]

#views.py
def room(request, room_name):
    return render(request, 'chat/room.html', {'room_name': room_name})

#chat/room.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>Chat Room</title>
  </head>
  <body>
    <div id="chat-log">
      <!-- Messages will be displayed here -->
    </div>

    <form id="chat-form">
      <input id="chat-message-input" type="text" size="100" autocomplete="off">
      <input id="chat-message-submit" type="submit" value="Send">
    </form>

    {{ room_name|json_script:"room-name" }}
    <script>
    const roomName = JSON.parse(document.getElementById('room-name').textContent);

    const chatSocket = new WebSocket(
      'ws://' + window.location.host + '/ws/chat/' + roomName + '/'
    );

    console.log(chatSocket)

    document.querySelector('#chat-form').onsubmit = (e) => {
      e.preventDefault(); 
      const messageInputDom = document.querySelector('#chat-message-input');
      const message = messageInputDom.value;
      chatSocket.send(JSON.stringify({
        'message': message
      }));
      messageInputDom.value = '';
    };

    chatSocket.onmessage = (e) => {
      const data = JSON.parse(e.data);
      const chatLog = document.getElementById('chat-log');
      const messageDiv = document.createElement('div');
      messageDiv.textContent = `${data.user}: ${data.message} | Posted : ${data.date}`;
      chatLog.appendChild(messageDiv);
    };

    chatSocket.onclose = (e) => {
      console.error('Chat socket closed unexpectedly');
    };
    </script>
  </body>
</html>

#consumers.py
class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        current_user = self.scope['user']
        other_user = self.scope['url_route']['kwargs']['room_name']
        # Should send to both of these,
        # self.room_group_name = f'group_{current_user}_{other_user}'
        # self.room_group_name = f'group_{other_user}_{current_user}'
        # But the room_group_name should change based on who is logged in. 
        # If user A then f'group_{current_user}_{other_user}' example and then the opposite user B

        if not await self.check_room_exists(room_name=self.room_group_name):
            await self.create_one_on_one_room(sender=current_user, receiver=other_user, room_name=self.room_group_name)

        await self.channel_layer.group_add(self.room_group_name, self.channel_name)

        await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(self.room_group_name, self.channel_name)

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json["message"]
        # Data from client side comes here but it only sends to one of the defined room_group_name[s]
        await self.channel_layer.group_send(
            self.room_group_name, {"type": "chat_message", "message" : message})

    async def chat_message(self, event):
        user = self.scope["user"]
        message = event["message"]
        date = str(datetime.now().strftime("%c"))

        await self.send(text_data=json.dumps({"user": user.username,"date": date, "message": message}))

    @database_sync_to_async
    def get_user(self, username):
        return User.objects.get(username=username)

    @database_sync_to_async
    def check_room_exists(self, room_name):
        return OneOnOneRoom.objects.filter(room_name=room_name).exists()

    @database_sync_to_async
    def create_one_on_one_room(self, current_user, other_user, room_name):
        return OneOnOneRoom.objects.create(sender=current_user, receiver=other_user, room_name=room_name)

    @database_sync_to_async
    def get_one_on_one_room(self, room_name):
        return OneOnOneRoom.objects.get(room_name=room_name)

编辑: 除非有更好的方法来创建一对一聊天,然后告诉我。

python django websocket django-channels
© www.soinside.com 2019 - 2024. All rights reserved.