使用来自外部消费者的 Django 通道发送消息 class
Send message using Django Channels from outside Consumer class
我正在构建一个在线游戏,它使用 Django channels 2.1.5 for websockets。
我能够在客户端和服务器之间建立连接,也能够仅在消费者内部在它们之间发送数据 class:
from channels.generic.websocket import WebsocketConsumer
import json
from . import controller
class GameConsumer(WebsocketConsumer):
def connect(self):
self.accept()
print("Wohooo .. Connected to client!")
self.render()
controller.startTurn()
def render(self, type="render", message=None):
self.send(controller.renderMap(type, message))
def disconnect(self, close_code):
print("WebSocket connection is lost...")
def receive(self, text_data):
text_data_json = json.loads(text_data)
controller.handleRecieved(text_data)
...
现在,我想做的是从另一个模块
我试过这个:
from .. import consumer
def sendDeployments(owner, armies):
type = "renderDeployments"
message = owner + " has " + str(armies) + " to deploy"
dummyConsumer = consumer.GameConsumer()
consumer.GameConsumer.render(type, message)
但失败了,因为我无法使用 class 之外的 "self" 参数。
有人能想出办法实现我的目标吗?
Ps:这个场合我不关心同步。
首先你需要你的消费者实例来订阅一个组。
from asgiref.sync import async_to_sync
class GameConsumer(WebsocketConsumer):
def connect(self):
self.accept()
self.render()
async_to_sync(self.add_group)('render_updates_group')
controller.startTurn()
...
然后,如果您不在您的消费者中,您将需要向该组发送一条消息,以便所有注册到该组的消费者都能收到消息。
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
def sendDeployments(owner, armies):
type = "renderDeployments"
message = owner + " has " + str(armies) + " to deploy"
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
'render_updates_group',
{'type': 'render', 'message': message}
)
但是,您还需要记住在断开连接时将您的消费者从组中移除。
class GameConsumer(WebsocketConsumer):
....
def disconnect(self, close_code):
async_to_sync(self.group_name)('render_updates_group')
如果您想限制哪些打开的连接获得此渲染消息,您需要相应地建立您的组名。
例如,如果您正在考虑一些在线游戏,那么您可以在群组名称中包含一个 MATCH-ID
,该群组名称由同一场比赛的所有连接共享。
一个很好的参考是 channels Layers documentation 但请记住,当 运行 在生产环境中使用时,您将需要设置消息传递层(通常是 Redis)。
断开连接功能(使用通道 2.3.0)的正确代码是:
class GameConsumer(WebsocketConsumer):
....
def disconnect(self, close_code):
self.channel_layer.group_discard(self.channel_name, 'render_updates_group')
首先为您的 Consumer 做一点改变,例如
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
import json
class EventConsumer(WebsocketConsumer):
def connect(self):
# self.room_name = self.scope['url_route']['kwargs']['room_name']
# self.room_group_name = 'chat_%s' % self.room_name
self.room_name = 'event'
self.room_group_name = self.room_name+"_sharif"
async_to_sync(self.channel_layer.group_add)(
self.room_group_name,
self.channel_name
)
print(self.room_group_name)
self.accept()
print("#######CONNECTED############")
def disconnect(self, code):
async_to_sync(self.channel_layer.group_discard)(
self.room_group_name,
self.channel_name
)
print("DISCONNECED CODE: ",code)
def receive(self, text_data=None, bytes_data=None):
print(" MESSAGE RECEIVED")
data = json.loads(text_data)
message = data['message']
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,{
"type": 'send_message_to_frontend',
"message": message
}
)
def send_message_to_frontend(self,event):
print("EVENT TRIGERED")
# Receive message from room group
message = event['message']
# Send message to WebSocket
self.send(text_data=json.dumps({
'message': message
}))
然后从您的应用中调用函数 outside/anywhere,例如
def event_triger():
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
'event_sharif',
{
'type': 'send_message_to_frontend',
'message': "event_trigered_from_views"
}
)
# here 'event_sharif' is your room_group_name as i defined before in consumer
# 'type' is like a command, for which method you wants to trigger in your consumer
我正在构建一个在线游戏,它使用 Django channels 2.1.5 for websockets。
我能够在客户端和服务器之间建立连接,也能够仅在消费者内部在它们之间发送数据 class:
from channels.generic.websocket import WebsocketConsumer
import json
from . import controller
class GameConsumer(WebsocketConsumer):
def connect(self):
self.accept()
print("Wohooo .. Connected to client!")
self.render()
controller.startTurn()
def render(self, type="render", message=None):
self.send(controller.renderMap(type, message))
def disconnect(self, close_code):
print("WebSocket connection is lost...")
def receive(self, text_data):
text_data_json = json.loads(text_data)
controller.handleRecieved(text_data)
...
现在,我想做的是从另一个模块
我试过这个:
from .. import consumer
def sendDeployments(owner, armies):
type = "renderDeployments"
message = owner + " has " + str(armies) + " to deploy"
dummyConsumer = consumer.GameConsumer()
consumer.GameConsumer.render(type, message)
但失败了,因为我无法使用 class 之外的 "self" 参数。
有人能想出办法实现我的目标吗?
Ps:这个场合我不关心同步。
首先你需要你的消费者实例来订阅一个组。
from asgiref.sync import async_to_sync
class GameConsumer(WebsocketConsumer):
def connect(self):
self.accept()
self.render()
async_to_sync(self.add_group)('render_updates_group')
controller.startTurn()
...
然后,如果您不在您的消费者中,您将需要向该组发送一条消息,以便所有注册到该组的消费者都能收到消息。
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
def sendDeployments(owner, armies):
type = "renderDeployments"
message = owner + " has " + str(armies) + " to deploy"
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
'render_updates_group',
{'type': 'render', 'message': message}
)
但是,您还需要记住在断开连接时将您的消费者从组中移除。
class GameConsumer(WebsocketConsumer):
....
def disconnect(self, close_code):
async_to_sync(self.group_name)('render_updates_group')
如果您想限制哪些打开的连接获得此渲染消息,您需要相应地建立您的组名。
例如,如果您正在考虑一些在线游戏,那么您可以在群组名称中包含一个 MATCH-ID
,该群组名称由同一场比赛的所有连接共享。
一个很好的参考是 channels Layers documentation 但请记住,当 运行 在生产环境中使用时,您将需要设置消息传递层(通常是 Redis)。
断开连接功能(使用通道 2.3.0)的正确代码是:
class GameConsumer(WebsocketConsumer):
....
def disconnect(self, close_code):
self.channel_layer.group_discard(self.channel_name, 'render_updates_group')
首先为您的 Consumer 做一点改变,例如
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
import json
class EventConsumer(WebsocketConsumer):
def connect(self):
# self.room_name = self.scope['url_route']['kwargs']['room_name']
# self.room_group_name = 'chat_%s' % self.room_name
self.room_name = 'event'
self.room_group_name = self.room_name+"_sharif"
async_to_sync(self.channel_layer.group_add)(
self.room_group_name,
self.channel_name
)
print(self.room_group_name)
self.accept()
print("#######CONNECTED############")
def disconnect(self, code):
async_to_sync(self.channel_layer.group_discard)(
self.room_group_name,
self.channel_name
)
print("DISCONNECED CODE: ",code)
def receive(self, text_data=None, bytes_data=None):
print(" MESSAGE RECEIVED")
data = json.loads(text_data)
message = data['message']
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,{
"type": 'send_message_to_frontend',
"message": message
}
)
def send_message_to_frontend(self,event):
print("EVENT TRIGERED")
# Receive message from room group
message = event['message']
# Send message to WebSocket
self.send(text_data=json.dumps({
'message': message
}))
然后从您的应用中调用函数 outside/anywhere,例如
def event_triger():
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
'event_sharif',
{
'type': 'send_message_to_frontend',
'message': "event_trigered_from_views"
}
)
# here 'event_sharif' is your room_group_name as i defined before in consumer
# 'type' is like a command, for which method you wants to trigger in your consumer