如何在服务器端发出SocketIO事件

20

我在运行一个使用gevent-socketio的Django应用程序。

我有一个类似于以下代码:

@namespace('/connect')
class ConnectNamespace(BaseNamespace):

    def on_send(self, data):
        # ...

然而,如果我从 JavaScript 客户端接收事件,一切都可以正常工作,例如处理 send 事件。

如果我想在服务器端触发某些事件,我有点迷茫。我可以在类内部使用 socket.send_packet 来实现。

但是现在我想将某些事件与 post_save 信号关联起来,所以我希望能够从这个命名空间类的外部进行 send_packet,一种做法是

ConnectNamespaceInstance.on_third_event('someeventname')

我只是想不明白如何获取ConnectNamespaceInstance的实例

总之,我想在收到“post_save”信号后向JavaScript客户端发送事件


https://dev59.com/0GYr5IYBdhLWcg3wpbyQ - catherine
2
我遇到了相同的问题,而且无法解决...有什么想法吗? - lumingjing
抱歉,但我认为建议的重复答案并不能回答我的问题。 - Jan Vorcak
你想要与专用客户端通信还是广播事件? - Thomas Fenzl
一旦我拥有了该类的实例,我想我可以做两件事,只需要使用BroadcastMixin的方法将其发送给所有人。 - Jan Vorcak
信号处理程序执行的上下文是什么? - mderk
2个回答

7
你可能想做的是添加一个模块变量来跟踪连接,比如 _connections,代码如下:
_connections = {}

@namespace('/connect')
class ConnectNamespace(BaseNamespace):

接着添加 initializedisconnect 方法,使用一些便于后续引用的标识符:

def initialize(self, *args, **kwargs):
    _connections[id(self)] = self
    super(ConnectNamespace, self).initialize(*args, **kwargs)

def disconnect(self, *args, **kwargs):
    del _connections[id(self)]
    super(ConnectNamespace, self).disconnect(*args, **kwargs)

当需要生成事件时,您可以在_connections变量中查找正确的连接,并使用emit触发事件。

(尚未测试任何内容,但我在许多其他语言中使用了类似的模式:没有理由认为这在Python中不起作用)。


1
我在想这个框架中是否有一些内置工具可以做到这一点,但这是一个非常好的解决方法,我应该想到它!+1 :) 谢谢 - Jan Vorcak
这个解决方案有没有广播到频道的示例? - Mirza Delic
1
这个解决方案帮助我在Django的post_save信号上发送消息。真是一个很好的解决方案。 - kpacn

0

除了Femi的答案之外,我认为肯定有效。使用Redis可能会给您更多的灵活性,并且使用gevent中的greenlet可以使这种方法更符合“框架”,因为您已经在使用gevent-socketio :D

REDIS_HOST = getattr(settings, 'REDIS_HOST', '127.0.0.1')


class YourNamespace(BaseNamespace):

    def _listener(self, channel_label_you_later_call_in_post_save):
        pubsub = redis.StrictRedis(REDIS_HOST).pubsub()
        pubsub.subscribe(chan)
        while True:
            for i in pubsub.listen():
                self.send({'message_data': i}, json=True) 

    def recv_message(self, message):
        if is_message_to_subscribe(message):
            self.spawn(self.listener, get_your_channel_label(message))

而在你的post_save中,你可以这样做

red = redis.StrictRedis(REDIS_HOST)
red.publish(channel_label, message_data)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接