Django / gevent socket.IO com redis pubsub. Onde coloco as coisas?
Tenho um script python isolado que simplesmente captura dados da API de streaming do Twitter e, após o recebimento de cada mensagem, usando o redis pubsub que ele publica no canal "tweets". Aqui está o 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!'
implementação socket.io do meu servidor é feita usando django-socketio (baseado no gevent-socketihttps: //github.com/stephenmcd/django-socketi, que simplesmente fornece alguns decoradores auxiliares, bem como um método broadcast_channel. Como é feito no django, eu simplesmente coloquei esse código no views.py simplesmente para que eles sejam importados. Meu 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)
O JavaScript socket.io do lado do cliente simplesmente conecta e assina o canal "livestream" e captura todas as mensagens recebidas nesse canal:
var socket = new io.Socket();
socket.connect();
socket.on('connect', function() {
socket.subscribe("livestream");
});
socket.on('message', function(data) {
console.log(data);
});
O problema óbvio desse código é que, sempre que uma nova janela de usuário ou navegador é aberta na página, um novo método _listen é gerado e os tweets são inscritos e transmitidos para cada usuário, resultando em mensagens duplicadas sendo recebidas no cliente. Minha pergunta é: onde seria o local adequado para colocar o método _listen para que ele seja criado apenas uma vez, independentemente do número de clientes? Além disso, lembre-se de que o método broadcast_channel é um método de uma instância de soquet