问题
I have two main modules, Tornado WebSocket and Tweepy Streaming, and I'm trying to get them to talk to each other.
Under on_status
in the StdOutListener
Tweepy class below (marked with <--
), I'd like to call the WSHandler.on_message
Tornado class higher up, with data passed from on_status
.
I'm not able to do so however, as I get error-messages related to undefined instances etc. with the code below. Any help greatly appreciated!
(Also, the only non-blocking way I've managed to run both modules at the same time is with threading, as the IOLoop.add_callback
does not keep StdOutListener
from blocking. I'd love to know why or if this implementation is recommended. Thanks!)
import os.path
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import threading
import time
import datetime
# websocket
class FaviconHandler(tornado.web.RequestHandler):
def get(self):
self.redirect('/static/favicon.ico')
class WebHandler(tornado.web.RequestHandler):
def get(self):
self.render("websockets.html")
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
cb = tornado.ioloop.PeriodicCallback(self.spew, 1000, io_loop=main_loop)
cb.start()
print 'new connection'
self.write_message("Hi, client: connection is made ...")
def on_message(self, message):
print 'message received: \"%s\"' % message
self.write_message("Echo: \"" + message + "\"")
if (message == "green"):
self.write_message("green!")
def on_close(self):
print 'connection closed'
def spew(self):
msg = 'spew!'
print(msg)
self.on_message(msg)
handlers = [
(r"/favicon.ico", FaviconHandler),
(r'/static/(.*)', tornado.web.StaticFileHandler, {'path': 'static'}),
(r'/', WebHandler),
(r'/ws', WSHandler),
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "static"),
)
application = tornado.web.Application(handlers, **settings)
# tweepy
from tweepy.streaming import StreamListener
from tweepy import OAuthHandler
from tweepy import Stream
import simplejson as json
# new stream listener
class StdOutListener(StreamListener, WSHandler):
""" A listener handles tweets are the received from the stream.
This is a basic listener that just prints received tweets to stdout.
"""
# tweet handling
def on_status(self, status):
print('@%s: %s' % (status.user.screen_name, status.text))
WSHandler.on_message(status.text) # <--- THIS is where i want to send a msg to WSHandler.on_message
# limit handling
def on_limit(self, track):
return
# error handling
def on_error(self, status):
print status
def OpenStream():
consumer_key="[redacted]"
consumer_secret="[redacted]"
access_token="[redacted]"
access_token_secret="[redacted]"
keyword = 'whatever'
l = StdOutListener()
auth = OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
stream = Stream(auth, l, gzip=True)
stream.filter(track=[keyword])
if __name__ == "__main__":
threading.Thread(target=OpenStream).start()
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
main_loop = tornado.ioloop.IOLoop.instance()
# main_loop.add_callback(OpenStream)
main_loop.start()
回答1:
on_message
is an instance method, not a class method. You need to call it on an instance, like this:
handler = WSHandler()
handler.on_message('hello world')
However, you can't just do that as instances need to be created by a browser connection in order to actually send and receive messages.
What you probably want is to keep a list of open connections (the Tornado websocket demo is a good example of this):
class WSHandler(tornado.websocket.WebSocketHandler):
connections = []
def open(self):
self.connections.append(self)
....
def on_close(self):
self.connections.remove(self)
then, in StdOutListener.on_status
, you can do something like:
for connection in WSHandler.connections:
connection.write_message(status.text)
来源:https://stackoverflow.com/questions/12481670/passing-data-between-classes-in-tweepy-and-tornado-websocket