framework.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import tornado.websocket
  2. import time, json
  3. from collections import defaultdict
  4. from tornado.gen import coroutine, sleep
  5. import random, string
  6. from contextlib import contextmanager
  7. class Future:
  8. def __iter__(self):
  9. result = yield
  10. return result
  11. __await__ = __iter__ # make compatible with 'await' expression
  12. class Task:
  13. @contextmanager
  14. def ws_context(self):
  15. """
  16. >>> with ws_context():
  17. ... res = self.coros[-1].send(data)
  18. """
  19. Global.active_ws = self.ws
  20. Global.active_coro_id = self.coro_id
  21. try:
  22. yield
  23. finally:
  24. Global.active_ws = None
  25. Global.active_coro_id = None
  26. @staticmethod
  27. def gen_coro_id(coro=None):
  28. name = 'coro'
  29. if hasattr(coro, '__name__'):
  30. name = coro.__name__
  31. random_str = ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(10))
  32. return '%s-%s' % (name, random_str)
  33. def __init__(self, coro, ws):
  34. print('into Task __init__ `', coro, ws)
  35. self.ws = ws
  36. self.coro = coro
  37. self.coro_id = None
  38. self.result = None
  39. self.task_finished = False # 协程完毕
  40. self.coro_id = self.gen_coro_id(self.coro)
  41. # todo issue: 激活协程后,写成的返回值可能是tornado coro,需要执行
  42. with self.ws_context():
  43. res = self.coro.send(None) # 激活协程
  44. if res is not None: # todo 执行完,还需要获取结果,coro.send(res)
  45. self.ws.tornado_coro_instances.append(res)
  46. def step(self, result):
  47. try:
  48. with self.ws_context():
  49. res = self.coro.send(result)
  50. return res
  51. except StopIteration as e:
  52. if len(e.args) == 1:
  53. self.result = e.args[0]
  54. self.task_finished = Task
  55. # raise
  56. class Msg:
  57. mid2callback = defaultdict(list)
  58. @staticmethod
  59. def gen_msg_id():
  60. mid = '%s-%s' % (Global.active_ws.sid, int(time.time()))
  61. return mid
  62. @classmethod
  63. def add_callback(cls, msg_id, callback):
  64. cls.mid2callback[msg_id].append(callback)
  65. @classmethod
  66. def get_callbacks(cls, msg_id):
  67. return cls.mid2callback[msg_id]
  68. @classmethod
  69. def get_callbacks(cls, msg_id):
  70. return cls.mid2callback[msg_id]
  71. @classmethod
  72. def unregister_msg(cls, msg_id):
  73. del cls.mid2callback[msg_id]
  74. class Global:
  75. # todo issue: with 语句可能发生嵌套,导致内层with退出时,将属性置空
  76. active_ws: "EchoWebSocket" = None
  77. active_coro_id = None