我正在尝试实现一种向特定于用户的用户发送消息的方法。我看过文档,他们建议将channel_name存储在数据库中并在断开连接时将其删除,但我认为这将成为数据库的负担,因为只要用户连接到消费者,channel_name就会不断变化。所以我在接受期间尝试了以下方法,其中我尝试将用户的 user_name 分配为唯一的频道名称
消费者
class ChatGenericAsyncConsumer(AsyncWebsocketConsumer):
"""this is an async consumer"""
async def connect(self):
self.user = self.scope["user"]
if self.user.is_authenticated:
print(
f"authentication successful connection accepted for {self.user.user_name}"
)
self.username = f"{self.user.user_name}"
self.channel_name = f"{self.user.user_name}"
await self.accept()
else:
print("authentication unsuccessful connection closed")
await self.close(code=4123)
async def receive(self, text_data=None, bytes_data=None):
pass
async def disconnect(self, code):
await self.close(code=4123)
# this is the event handler of 'chat.message'
async def chat_message(self, event):
"""
this method handles the sending of message
to the group.
this is same as chat.message
"""
# sending message to the group
print(event["data"])
await self.send(text_data=event["data"])
然后尝试从消费者外部发送消息,我尝试模拟一种情况,由于某种原因管理员想要向特定用户发送用户特定的消息或通知。所以我编写了下面的 api 并使用 channel_layer.send() 将消息发送到特定的通道名称
API
@api_view(["POST"])
@permission_classes([AllowAny])
def send_message_from_admin(request, group_name):
try:
message = request.data.get("message")
username = request.data.get("username")
channel_layer = get_channel_layer()
send_data = {"user": "Admin", "message": message}
async_to_sync(channel_layer.send)(
username, {"type": "chat.message", "data": json.dumps(send_data)}
)
return Response(
{"message": "sent message"}, status=status.HTTP_200_OK
)
except Exception as e:
print(f"An exception occurred {e}")
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
这里的username与连接时设置的channel_name相同。但不知何故,这不起作用,并且不会调用事件处理程序来将消息发送到特定的频道名称,并且用户不会收到消息。
请建议我代码是否有问题或者我对发送用户特定消息或通知的理解是否有问题
问题:
我不认为你可以自己设置
channel_name
;它是自动设置的。因此 self.channel_name = f"{self.user.user_name}"
可能会设置 self.channel_name
,但不会改变实际使用的通道。
可能有用:
我从来没有尝试过这个,但你也许可以通过简单地获取
channel_name
,然后用它替换 username
来做到这一点:
async_to_sync(channel_layer.send)(
channel_layer.channel_name, {"type": "chat.message", "data": json.dumps(send_data)}
)
问题是我不知道
channel_layer.channel_name
是否有效。
应该可以工作
您可以尝试使用
group_send
代替。这个想法是将用户添加到一个唯一的组中(在这里,您可以使用用户名作为组名)。这是违反直觉的,但现在您可以发送到这个只有一个用户的组。当用户断开连接时,您可以将该用户从组中删除。
async def connect(self):
self.user = self.scope["user"]
if self.user.is_authenticated:
print(
f"authentication successful connection accepted for {self.user.user_name}"
)
self.username = f"{self.user.user_name}"
# Remove this since you can get, but not set the channel_name
# self.channel_name = f"{self.user.user_name}"
# ADD THE USER TO HIS OWN UNIQUE "GROUP"
# NOTE: Here I'm using self.channel_name to GET the channel_name of the
# client, NOT setting it to a chosen value
async_to_sync(self.channel_layer.group_add)(self.user.user_name, self.channel_name)
await self.accept()
else:
print("authentication unsuccessful connection closed")
await self.close(code=4123)
async def receive(self, text_data=None, bytes_data=None):
pass
async def disconnect(self, code):
# REMOVE THE USER FROM HIS UNIQUE GROUP
async_to_sync(self.channel_layer.group_discard)(self.user.user_name, self.channel_name)
# NOT SURE YOU NEED THIS ANYMORE?
await self.close(code=4123)
现在发送日期:
# Change this:
# async_to_sync(channel_layer.send)(
username, {"type": "chat.message", "data": json.dumps(send_data)}
)
# to this:
async_to_sync(channel_layer.group_send)(
username, {"type": "chat.message", "data": json.dumps(send_data)}
)