+-
使用来自外部Consumer类的Django Channels发送消息

我正在构建一个在线游戏,它使用Django频道2.1.5作为websockets。

我能够在客户端和服务器之间建立连接,并且只能在消费者类中发送它们之间的数据:

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)
...

现在,我想做的是从另一个模块调用函数render,它位于使用者类中

我试过这个:

from .. import consumer

def sendDeployments(owner, armies):
    type = "renderDeployments"
    message = owner + " has " + str(armies) + " to deploy"
    dummyConsumer = consumer.GameConsumer()
    consumer.GameConsumer.render(type, message)

但失败了因为我无法使用课外的“自我”参数。

任何人都可以想办法实现我的目标吗?

Ps:我不关心此时的同步。

提前致谢。

1
投票

首先,您需要您的消费者实例订阅一个组。

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)。