PageRenderTime 74ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/demos/websocket/chatdemo.py

http://github.com/facebook/tornado
Python | 102 lines | 62 code | 20 blank | 20 comment | 4 complexity | e6f0dc37b48a251a0561ced95ded94b9 MD5 | raw file
Possible License(s): Apache-2.0
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2009 Facebook
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  6. # not use this file except in compliance with the License. You may obtain
  7. # a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. # License for the specific language governing permissions and limitations
  15. # under the License.
  16. """Simplified chat demo for websockets.
  17. Authentication, error handling, etc are left as an exercise for the reader :)
  18. """
  19. import logging
  20. import tornado.escape
  21. import tornado.ioloop
  22. import tornado.options
  23. import tornado.web
  24. import tornado.websocket
  25. import os.path
  26. import uuid
  27. from tornado.options import define, options
  28. define("port", default=8888, help="run on the given port", type=int)
  29. class Application(tornado.web.Application):
  30. def __init__(self):
  31. handlers = [(r"/", MainHandler), (r"/chatsocket", ChatSocketHandler)]
  32. settings = dict(
  33. cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
  34. template_path=os.path.join(os.path.dirname(__file__), "templates"),
  35. static_path=os.path.join(os.path.dirname(__file__), "static"),
  36. xsrf_cookies=True,
  37. )
  38. super(Application, self).__init__(handlers, **settings)
  39. class MainHandler(tornado.web.RequestHandler):
  40. def get(self):
  41. self.render("index.html", messages=ChatSocketHandler.cache)
  42. class ChatSocketHandler(tornado.websocket.WebSocketHandler):
  43. waiters = set()
  44. cache = []
  45. cache_size = 200
  46. def get_compression_options(self):
  47. # Non-None enables compression with default options.
  48. return {}
  49. def open(self):
  50. ChatSocketHandler.waiters.add(self)
  51. def on_close(self):
  52. ChatSocketHandler.waiters.remove(self)
  53. @classmethod
  54. def update_cache(cls, chat):
  55. cls.cache.append(chat)
  56. if len(cls.cache) > cls.cache_size:
  57. cls.cache = cls.cache[-cls.cache_size :]
  58. @classmethod
  59. def send_updates(cls, chat):
  60. logging.info("sending message to %d waiters", len(cls.waiters))
  61. for waiter in cls.waiters:
  62. try:
  63. waiter.write_message(chat)
  64. except:
  65. logging.error("Error sending message", exc_info=True)
  66. def on_message(self, message):
  67. logging.info("got message %r", message)
  68. parsed = tornado.escape.json_decode(message)
  69. chat = {"id": str(uuid.uuid4()), "body": parsed["body"]}
  70. chat["html"] = tornado.escape.to_basestring(
  71. self.render_string("message.html", message=chat)
  72. )
  73. ChatSocketHandler.update_cache(chat)
  74. ChatSocketHandler.send_updates(chat)
  75. def main():
  76. tornado.options.parse_command_line()
  77. app = Application()
  78. app.listen(options.port)
  79. tornado.ioloop.IOLoop.current().start()
  80. if __name__ == "__main__":
  81. main()