是否可以列出存储在组中的频道?
Is it possible to list channels stored in a Group?
是否可以使用 django-channels 访问添加到组中的频道列表?
def consumer(message):
Group("group_name").add(message.reply_channel)
channel_list = Group("group_name").???
编辑:
我试图实现的是访问所有频道的会话,例如已连接用户的列表。
到目前为止,我使用了一个基于数据库的系统来列出连接。但是如果服务器没有执行我的 ws_disconnect 消费者就关闭了,这些连接对象将保留在数据库中,我不希望这样。
编辑 2:
为了列出已连接的用户,我找到了 django-channels-presence
。我会测试它。
是的,这是可能的。简单的破解方法是...
# 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>')
我已经测试了 django-channels-presence
,我通过创建 Room
(处理 Group
management/creation, channel
adding/removing...) 并且它提供了一个 get_users()
方法,使我能够实现我正在寻找的东西。
它还提供了一种方法来清除在服务器崩溃时未删除的已添加频道(这不会触发用于从组中删除这些频道的 ws_disconnect 消费者)。它提供了 prune_presence
和 prune_room
清理过期频道的任务。
我发现上面提到的 channel_layer.group_channels('<your group name>')
在通道 2 上不起作用。所以,我决定将我需要的信息保存在 channel_layer 中,它起作用了。
版本信息
- 频道==2.1.5
- aioredis==1.2.0
- channels-redis==2.3.2
在我的例子中,我需要知道一个组中的频道号,因为我在后台启动了一个 celery beat 以继续将数据推送到频道,但是当组中的最后一个频道断开连接时,我想停止芹菜节拍。
我通过将其存储在 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
您可以选择将某个房间中连接的用户保存在数据库中。创建房间,连接时添加用户,断开连接时删除用户。
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
}))
是否可以使用 django-channels 访问添加到组中的频道列表?
def consumer(message):
Group("group_name").add(message.reply_channel)
channel_list = Group("group_name").???
编辑:
我试图实现的是访问所有频道的会话,例如已连接用户的列表。
到目前为止,我使用了一个基于数据库的系统来列出连接。但是如果服务器没有执行我的 ws_disconnect 消费者就关闭了,这些连接对象将保留在数据库中,我不希望这样。
编辑 2:
为了列出已连接的用户,我找到了 django-channels-presence
。我会测试它。
是的,这是可能的。简单的破解方法是...
# 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>')
我已经测试了 django-channels-presence
,我通过创建 Room
(处理 Group
management/creation, channel
adding/removing...) 并且它提供了一个 get_users()
方法,使我能够实现我正在寻找的东西。
它还提供了一种方法来清除在服务器崩溃时未删除的已添加频道(这不会触发用于从组中删除这些频道的 ws_disconnect 消费者)。它提供了 prune_presence
和 prune_room
清理过期频道的任务。
我发现上面提到的 channel_layer.group_channels('<your group name>')
在通道 2 上不起作用。所以,我决定将我需要的信息保存在 channel_layer 中,它起作用了。
版本信息
- 频道==2.1.5
- aioredis==1.2.0
- channels-redis==2.3.2
在我的例子中,我需要知道一个组中的频道号,因为我在后台启动了一个 celery beat 以继续将数据推送到频道,但是当组中的最后一个频道断开连接时,我想停止芹菜节拍。
我通过将其存储在 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
您可以选择将某个房间中连接的用户保存在数据库中。创建房间,连接时添加用户,断开连接时删除用户。
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
}))