How to emit SocketIO event on the serverside
Asked Answered
N

2

20

I'm running a gevent-socketio Django application.

I have something similar to this class

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

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

However, if I receive the events from the javascript client, everything works and for instance send event is processed correctly

I'm a little bit lost if I want to emit some event on the server side. I can do it inside the class with socket.send_packet

But now I want to link some event to post_save signal, so I'd like to send_packet from outside this namespace class, one way of doing this would be

ConnectNamespaceInstance.on_third_event('someeventname')

I just can't figure out how can I get the instance of ConnectNamespaceInstance

To sum it up, I just want to send an event to javascript client after I receive post_save signal

Nebulose answered 20/3, 2013 at 22:4 Comment(6)
#13504820Scottie
i got the same issue,and cannot solved... Any idea?Ostrowski
I'm sorry but I don't think suggested duplicate answers my questionNebulose
do you want to communicate with a dedicated client or broadcast events?Nagano
once I have the instance of the class, I could do both I guess, I'd just need to use BroadcastMixin's methods to send it to everybodyNebulose
what is the context of where the signal handler is executed?Launcher
H
7

What you probably want to do is add a module variable to track connections, say _connections, like so:

_connections = {}

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

and then add initialize and disconnect methods that use some happy identifier you can reference later:

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)

When you need to generate an event, you can then just look up the right connection in the _connections variable, and fire off the event with emit.

(Didn't test any of this, but I've used a similar pattern in many other languages: don't see any reason why this wouldn't work in Python as well).

Herrah answered 29/5, 2013 at 17:25 Comment(3)
I was wondering whether there is some build-in tool for doing this in the framework, but this is a really nice workaround I should have thought of! +1 :) thank youNebulose
any example for broadcasting to channel with this solution?Lamellirostral
This helped me to send messages on post_save signal in Django. Really nice solution.Spitsbergen
S
0

Other then Femi's answer, which I think certainly works. Using Redis would probably give you a bit more flexibility and using greenlet from gevent may qualify this approach as a bit more "in the framework", since you are already using 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))

And in your post_save, you can do

red = redis.StrictRedis(REDIS_HOST)
red.publish(channel_label, message_data)
Scratchboard answered 9/1, 2015 at 11:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.