Django / gevent socket.IO con redis pubsub. ¿Dónde pongo las cosas?
Tengo una secuencia de comandos de Python aislada que simplemente captura datos de la API de transmisión de Twitter y luego, al recibir cada mensaje, usando redis pubsub que publica en el canal "tweets". Aquí está ese script:
def main():
username = "username"
password = "password"
track_list = ["apple", "microsoft", "google"]
with tweetstream.FilterStream(username, password, track=track_list) as stream:
for tweet in stream:
text = tweet["text"]
user = tweet["user"]["screen_name"]
message = {"text": text, "user": user}
db.publish("tweets", message)
if __name__ == '__main__':
try:
print "Started..."
main()
except KeyboardInterrupt:
print '\nGoodbye!'
La implementación de socket.io en mi servidor se realiza utilizando django-socketio (basado en gevent-socketio)https: //github.com/stephenmcd/django-socketi que simplemente proporciona algunos decoradores auxiliares, así como un método broadcast_channel. Como está hecho en django, simplemente puse este código en views.py simplemente para que se importen. Mi código views.py:
def index(request):
return render_to_response("twitter_app/index.html", {
}, context_instance=RequestContext(request))
def _listen(socket):
db = redis.Redis(host="localhost", port=6379, db=0)
client = db.pubsub()
client.subscribe("tweets")
tweets = client.listen()
while True:
tweet = tweets.next()
tweet_data = ast.literal_eval(tweet["data"])
message = {"text": tweet_data["text"], "user": tweet_data["user"], "type": "tweet"}
socket.broadcast_channel(message)
@on_subscribe(channel="livestream")
def subscribe(request, socket, context, channel):
g = Greenlet.spawn(_listen, socket)
El lado del cliente socket.io JavaScript simplemente se conecta y se suscribe al canal "transmisión en vivo" y captura cualquier mensaje recibido a ese canal:
var socket = new io.Socket();
socket.connect();
socket.on('connect', function() {
socket.subscribe("livestream");
});
socket.on('message', function(data) {
console.log(data);
});
El problema obvio con este código es que cada vez que se abre un nuevo usuario o ventana del navegador en la página, se genera un nuevo método _listen y los tweets se suscriben y transmiten para cada usuario, lo que da como resultado que se reciban mensajes duplicados en el cliente. Mi pregunta es, ¿dónde sería el lugar adecuado para colocar el método _listen para que solo se cree una vez, independientemente del número de clientes? Además, teniendo en cuenta que el método broadcast_channel es un método de una instancia de socket.