У меня есть изолированный скрипт на python, который просто собирает данные из потокового API Twitter, а затем при получении каждого сообщения, используя redis pubsub, который публикует на канале «твиты».Вот этот скрипт:
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!'
Моя реализация socket.io на стороне сервера выполняется с использованием django-socketio (на основе gevent-socketio) https://github.com/stephenmcd/django-socketio, который просто предоставляет несколько вспомогательных декораторов, а такжекак метод broadcast_channel.Поскольку это сделано в django, я просто поместил этот код в views.py просто для того, чтобы он был импортирован.Мой код 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)
JavaScript на стороне клиента socket.io JavaScript просто подключается и подписывается на канал "прямой эфир" и перехватывает все полученные сообщения на этот канал:
var socket = new io.Socket();
socket.connect();
socket.on('connect', function() {
socket.subscribe("livestream");
});
socket.on('message', function(data) {
console.log(data);
});
Очевидная проблема с этим кодом заключается в том, что каждый раз, когда на странице открывается новое окно пользователя или браузера, создается новый метод _listen, а твиты подписываются и транслируются для каждого пользователя, что приводит к получению дубликатов сообщений на клиенте.Мой вопрос: где было бы правильное место для размещения метода _listen, чтобы он создавался только один раз, независимо от количества клиентов?Также следует помнить, что метод broadcast_channel является методом экземпляра сокета.