【问题标题】:Is it possible to list channels stored in a Group?是否可以列出存储在组中的频道?
【发布时间】:2016-09-12 01:00:37
【问题描述】:

是否可以使用 django-channels 访问添加到组中的频道列表?

def consumer(message):
    Group("group_name").add(message.reply_channel)
    channel_list = Group("group_name").???

编辑:

我试图实现的是访问所有频道的会话,例如连接用户列表。

到目前为止,我使用了一个基于数据库的系统来列出连接。但是如果服务器在没有执行我的 ws_disconnect 消费者的情况下关闭,这些连接对象将保留在数据库中,我不希望这样。

编辑 2:

为了列出已连接的用户,我找到了django-channels-presence。我会测试一下。

【问题讨论】:

    标签: django django-channels django-channels-presence


    【解决方案1】:

    您可以选择将连接在房间中的用户保存在数据库中。创建房间,连接时添加用户,断开连接时删除用户。

    from django.db import models
    from django.contrib.auth import get_user_model
    from asgiref.sync import sync_to_async
    
    
    # ./models
    class Room(models.Model):
        room_name = models.CharField(max_length=150, unique=True)
        users = models.ManyToManyField(get_user_model(), related_name='rooms')
    
        @classmethod
        @sync_to_async
        def add(cls, room_name, user):
            room, created = cls.objects.get_or_create(room_name=room_name)
            room.users.add(user)
            return created # sockets => join or create
    
    
    
        @classmethod
        @sync_to_async
        def users_count(cls, room_name):
            rooms = cls.objects.filter(room_name=room_name)
            if rooms.exists():
                return rooms.first().users.count()
            return 0
    
        @classmethod
        @sync_to_async
        def remove_user(cls, user, room_name):
            room = cls.objects.filter(room_name=room_name)
            if room.exists():
                room.users.remove(user)
    
    
    # ./consumer.py
    class YourConsumer(AsyncWebsocketConsumer):
    
        async def connect(self):
            self.room_name = self.scope['url_route']['kwargs']['room_name']
            self.room_group_name = 'video_%s' % self.room_name
            self.group_users = {self.scope.get('user').id: 1}
    
            if self.scope.get('user').is_authenticated:
                room = await Room.add(self.room_name, self.scope.get('user'))
    
            await self.channel_layer.group_add(
                self.room_name,
                self.channel_name
            )
    
            await self.accept()
    
        async def disconnect(self, code):
            # Leave room group
            await self.channel_layer.group_discard(
                self.room_group_name,
                self.channel_name
            )
            if self.scope.get('user').is_authenticated:
                await Room.remove_user(self.room_name, self.scope.get('user'))
    
        async def websocket_receive(self, message):
            count = await Room.users_count(room_name=self.room_name)
            await self.send(json.dumps({
                'type': 'websocket.send',
                'text': 'pong',
                'group': self.room_group_name,
                'room': self.room_name,
                'connections': count
            }))
    
    

    【讨论】:

      【解决方案2】:

      我发现上面提到的channel_layer.group_channels('<your group name>') 在通道 2 上不起作用。所以,我决定将我需要的信息保存在 channel_layer 中,它可以工作。

      版本信息

      • 频道==2.1.5
      • aioredis==1.2.0
      • channels-redis==2.3.2

      在我的情况下,我需要知道组中的频道号,因为我在后台启动 celery beat 以不断将数据推送到频道,但是当组中的最后一个频道断开连接时,我想停止 celery 节拍.

      我通过存储在 channel_layer 中来计算组中的频道。

      连接时

      count = getattr(self.channel_layer, self.group_name, 0)
      if not count:
          setattr(self.channel_layer, self.group_name, 1)
      else:
          setattr(self.channel_layer, self.group_name, count + 1)
      

      断开连接

      count = getattr(self.channel_layer, self.group_name, 0)
      setattr(self.channel_layer, self.group_name, count - 1)
      if count == 1:
          delattr(self.channel_layer, self.group_name)
      
          # stop my celery beat
      
      

      【讨论】:

      • 这很危险。异步消费者可能会导致竞争状况,并且没有您可以依赖的断开连接事件/方法。
      【解决方案3】:

      是的,这是可能的。简单的破解方法是......

      # Get channel_layer function
      from channels.asgi import get_channel_layer
      
      # passing group_channel takes channel name
      channel_layer = get_channel_layer()
      ch_group_list = channel_layer.group_channels('<your group name>')
      

      【讨论】:

      • 不错!是否也可以访问相关会话/用户等信息? :)
      • 频道附带 @channel_session_user_from_http 装饰器,在消费者功能中,您可以从 message.user 获取用户,这就是您想要的
      • 我知道,但它不只适用于当前message消费者的参数吗?我使用get_channel_layer(),group_channels() 函数得到的是将字符串与浮点数相关联的字典:({'websocket.send!dLCNWvEM': 1473714104.796983})。如何访问每个频道的失败?例如列出连接的用户?
      • @ShreeRangaRaju 嗯,让我检查一下,然后回复你...
      【解决方案4】:

      我已经测试了django-channels-presence,并且通过创建Room(处理Group 管理/创建、channel 添加/删除...)轻松成功地列出了Group 的连接用户并提供了一个get_users() 方法,让我可以实现我正在搜索的内容。

      它还提供了一种方法来清除在服务器崩溃时不会删除的添加通道(这不会触发用于从组中删除这些通道的 ws_disconnect 使用者)。它提供了清理过期频道的prune_presenceprune_room 任务。

      【讨论】:

      • 没有任何sn-p答案是没有用的
      • 这个插件添加了多个新的数据库表,对于你需要的东西可能有点过分了
      猜你喜欢
      • 2018-07-28
      • 1970-01-01
      • 2018-04-02
      • 1970-01-01
      • 2017-12-11
      • 2012-07-07
      • 2018-07-19
      • 2020-11-26
      • 1970-01-01
      相关资源
      最近更新 更多