I have a basic Tornado websocket test:
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
print 'new connection'
self.write_message("Hello World")
def on_message(self, message):
print 'message received %s' % message
def on_close(self):
print 'connection closed'
application = tornado.web.Application([
(r'/ws', WSHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
I want to be able to handle multiple connections (which it seems to do already) but also to be able to reference other connections. I don't see a way to identify and keep track of individual connections, just to be able to handle events on connection open, receipt of messages, and connection close.
[Edit]
Thought of creating a dict where the key is the Sec-websocket-key and and the value is the WSHandler object... thoughts? I'm not sure how dependable Sec-websocket-key is to be unique.
The simplest method is just to keep a list or dict of WSHandler instances:
class WSHandler(tornado.websocket.WebSocketHandler):
clients = []
def open(self):
self.clients.append(self)
print 'new connection'
self.write_message("Hello World")
def on_message(self, message):
print 'message received %s' % message
def on_close(self):
self.clients.remove(self)
print 'closed connection'
If you want to identify connections, e.g. by user, you'll probably have to send that information over the socket.
Cole Maclean asnwer is good as simple solution, when you just need list of all connections.
However, if you want something more complex, that can be monitored outside of WSHandler
instance - be brave do it like this:
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
self.id = uuid.uuid4()
external_storage[self.id] = {'id':self.id}
print 'new connection'
self.write_message("Hello World")
def on_message(self, message):
#Some message parsing here
if message.type == 'set_group':
external_storage[self.id]['group'] = message.group
print 'message received %s' % message
def on_close(self):
external_storage.remove(self.id)
print 'closed connection'
If your users have an access token, this can be appended to your websocket endpoint, say, and fetched in initialising your socket even before it's opened (but please work over SSL).
If an access token is not available, either because the user hasn't supplied one or the token they supplied has expired, the user is not authenticated and you will kill the socket at the earliest opportunity.
However you do this, the access token should be associated to a user who will have an identifier and that identifier can then be tied to the socket even before it has been opened. The identifier can serve as a dictionary key whose value is a set of sockets tied to this user.
I have solved this issue by checking the origin of the conexion. So, overrriding the method def check_origin(self, origin)
may help. For example:
clients = {}
class WSHandler(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
clients[origin] = self
print(clients)
return True