ioloop.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import json
  2. import logging
  3. from collections import OrderedDict
  4. from os.path import abspath, dirname
  5. import tornado.websocket
  6. from tornado.gen import coroutine
  7. from tornado.log import gen_log
  8. from tornado.web import StaticFileHandler
  9. from .framework import Task
  10. project_dir = dirname(abspath(__file__))
  11. def ws_handler(coro_func):
  12. class WSHandler(tornado.websocket.WebSocketHandler):
  13. def check_origin(self, origin):
  14. return True
  15. def get_compression_options(self):
  16. # Non-None enables compression with default options.
  17. return {}
  18. @coroutine
  19. def open(self):
  20. print("WebSocket opened")
  21. self.set_nodelay(True)
  22. ############
  23. self.coros = {} # coro_id -> coro
  24. self.callbacks = OrderedDict() # UI元素时的回调, key -> callback, mark_id
  25. self.mark2id = {} # mark_name -> mark_id
  26. self._closed = False
  27. self.inactive_coro_instances = [] # 待激活的协程实例列表
  28. self.main_task = Task(coro_func(), ws=self)
  29. self.coros[self.main_task.coro_id] = self.main_task
  30. self.step_task(self.main_task)
  31. def step_task(self, task, result=None):
  32. task.step(result)
  33. if task.task_finished:
  34. gen_log.debug('del self.coros[%s]', task.coro_id)
  35. del self.coros[task.coro_id]
  36. while self.inactive_coro_instances:
  37. coro = self.inactive_coro_instances.pop()
  38. task = Task(coro, ws=self)
  39. self.coros[task.coro_id] = task
  40. task.step()
  41. if self.coros[task.coro_id].task_finished:
  42. gen_log.debug('del self.coros[%s]', task.coro_id)
  43. del self.coros[task.coro_id]
  44. if self.main_task.task_finished:
  45. for t in self.coros:
  46. t.cancel()
  47. self.close()
  48. def on_message(self, message):
  49. # print('on_message', message)
  50. data = json.loads(message)
  51. coro_id = data['coro_id']
  52. coro = self.coros.get(coro_id)
  53. if not coro_id:
  54. gen_log.error('coro not found, coro_id:%s', coro_id)
  55. return
  56. self.step_task(coro, data)
  57. def on_close(self):
  58. self._closed = True
  59. print("WebSocket closed")
  60. def closed(self):
  61. return self._closed
  62. return WSHandler
  63. def start_ioloop(coro_func, port=8080, debug=True, tornado_app_args=None):
  64. handlers = [(r"/test", ws_handler(coro_func)),
  65. (r"/(.*)", StaticFileHandler, {"path": '%s/html/' % project_dir,
  66. 'default_filename': 'index.html'})]
  67. gen_log.setLevel(logging.DEBUG)
  68. tornado_app_args = tornado_app_args or {}
  69. app = tornado.web.Application(handlers=handlers, debug=debug, **tornado_app_args)
  70. http_server = tornado.httpserver.HTTPServer(app)
  71. http_server.listen(port)
  72. print('Open http://localhost:%s/ in Web browser' % port)
  73. tornado.ioloop.IOLoop.instance().start()