0

我试图修改 Ted Roden 的“构建实时用户体验”中的一个示例,以将实时 Twitter 数据发送到服务器推送的客户端。

我的应用程序有一个类,它通过 tweepy 调用 Twitter 流 API,并通过用户在浏览器中输入的关键字过滤结果。其目的是为了根据过滤结果将 twitter 流发送回客户端。

我一直遇到的问题是我无法向客户端显示实时数据,将来我想修改它以便我可以实时向客户端发送任何类型的数据。

我对此很陌生,我真的很挣扎......因为我认为对示例代码进行一些更改会奏效。这是我的代码:

执行器模块:

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
import os.path, logging
from Tweeter import StreamerRt
import Queue
import threading
import simplejson as json
import uuid

queue = Queue.Queue(0)

define("port", default=8000, help='run on the given port', type=int)

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('templates/index.html')

class Tweet(object):
    waiters = []
    cache = []
    cache_size = 200
    def wait_for_messages(self, callback, cursor=None):
        cls = Tweet
        if cursor:
            index = 0
            for i in xrange(len(cls.cache)):
                index = len(cls.cache) - i - 1
                if cls.cache[index]["id"] == cursor: break
            recent = cls.cache[index + 1:]
            logging.info("%r recent tweets", len(recent))
            if recent:
                    callback(recent)
                    return
        cls.waiters.append(callback)

    def new_tweets(self, messages):
        cls = Tweet
        for callback in cls.waiters:
            try:
                callback(messages)
            except:
                logging.error("Error in waiter callback", exc_info=True)
        cls.waiters = []
        cls.cache.extend(messages)
        if len(cls.cache) > self.cache_size:
            cls.cache = cls.cache[-self.cache_size:]


class TweetsEventsHandler(tornado.web.RequestHandler, Tweet):
    @tornado.web.asynchronous
    def post(self):
        cursor = self.get_argument("cursor", None)
        self.wait_for_messages(self.async_callback(self.on_new_tweets),
                           cursor=cursor)
        self.render('templates/results.html')

    def on_new_tweets(self, tweets): 
        if not self.request.connection.stream.closed():
            self.finish(dict(tweets=tweets))


class TweetExtractor(threading.Thread):
    def run(self):

        while True:
            tweet = queue.get()
            if tweet:

                try:
                    message = {
                        "id": str(uuid.uuid4()),
                        "tweet": tweet
                        }
                    message["html"] = "<div class=\"message\" id=\"m" + message["id"] +     "\"><strong>" + ['author']['author_id'] + ": </strong>" + ['source'] + "</div>"
                    Tweet().new_tweets([message])

                except Exception, e:
                    pass

class TweetFinder(threading.Thread):
    def run(self):
        results = StreamerRt().filter(track=[self.get_argument('event')])        
        for tweets in results:
            if len(tweets)>2:
                queue.put(tweets)

local_static_path = os.path.join(os.path.dirname(__file__), "static") 

app = tornado.web.Application([
            (r"/", IndexHandler),
            (r"/results", TweetsEventsHandler),
    ],
    static_path=local_static_path)    


if __name__ == "__main__":
    print 'Listening on http://localhost:8000'
    tornado.options.parse_command_line()

    # setup the twitter threads
    threads = []
    threads.append(TweetExtractor())
    threads.append(TweetFinder())

    # for each thread, set daemon mode to true and start them up
    for t in threads:
        t.daemon = True
        t.start()

    http_server=tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port) 
    tornado.ioloop.IOLoop.instance().start()

js文件是这样的:

// -*- indent-tabs-mode: nil -*-
google.load("jquery", "1");

google.setOnLoadCallback(
    function() {
        $(document).ready(function() { T.init(); T.poll(); });
    }
);

var T = {
    cursor: false,
    types: ['hashtags', 'retweets', 'ats', 'links']
};

T.init = function() {
    $('input[type=checkbox]').click(T.click);
};

T.click = function(ev) {
    if(ev.target.id == 'all') {
        for(i in T.types)
            $('#' + T.types[i]).attr('checked', $('#all').attr('checked'));
        }
        else
            $('#all').attr('checked', false);
};


T.poll = function () {
    var args = {};
    if(T.cursor) args.cursor = T.cursor;
    $.ajax({
               url: "/results.html",
               type: "POST",
               dataType: "json",
               data: $.param(args),
               success: T.new_tweets
           });
};

T.new_tweets = function(response) {
    if(!T.cursor)
         $('#waiting').remove();

    T.cursor = response.tweets[response.tweets.length - 1].id;

    for(var i = 0; i < response.tweets.length; ++i) {
        if(T.should_show_tweet(response.tweets[i])) {
            var html = response.tweets[i].html;
            var regexp = /(http\:\/\/[^\ |\<]+)/g;
            if((result = regexp.exec(html))) {
                console.log(result);
                for (var n = 1; n < result.length; ++n)
                    html = html.replace(result[n], '<a target=blank href="' + result[n]       + '">' + result[n] + '</a>');

            }

            var d = $(html);
            d.css('display', 'none');
            $('#content').prepend(d);
            d.slideDown();
        }
    }

    // clean up the DOM
    var limit = 100;
    var messages = $('.message');
    for(var x = messages.length-1; x > limit; --x)
        $(messages[x]).remove();

    T.poll();
};

T.should_show_tweet = function(tweet) {
    show_tweet = false;

    $('#all-count').text(parseInt($('#all-count').text())+1);

     for(x in T.types) {
        var type = T.types[x];

        // does the tweet have the specified type?
        if(tweet.stats[type].length) {
            var count_div = $('#' + type + '-count');
            count_div.text(parseInt(count_div.text())+1);

            // does the user want to see it?
            if($("#" + type).attr('checked'))
                show_tweet = true;
        }
    }
    return show_tweet;
};


T.click = function(ev) {
    if(ev.target.id == 'all') {
        for(i in T.types)
            $('#' + T.types[i]).attr('checked', $('#all').attr('checked'));
    }
    else
        $('#all').attr('checked', false);
};

我是 js 的新手。

谢谢

4

0 回答 0