base.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import user_agents
  2. from ..utils import ObjectDict
  3. class AbstractSession:
  4. """
  5. 会话对象,由Backend创建
  6. 属性:
  7. info 表示会话信息的对象
  8. 由Task在当前Session上下文中调用:
  9. get_current_session
  10. get_current_task_id
  11. send_task_command
  12. next_client_event
  13. on_task_exception
  14. register_callback
  15. defer_call
  16. 由Backend调用:
  17. send_client_event
  18. get_task_commands
  19. close
  20. Task和Backend都可调用:
  21. closed
  22. active_session_count
  23. Session是不同的后端Backend与协程交互的桥梁:
  24. 后端Backend在接收到用户浏览器的数据后,会通过调用 ``send_client_event`` 来通知会话,进而由Session驱动协程的运行。
  25. Task内在调用输入输出函数后,会调用 ``send_task_command`` 向会话发送输入输出消息指令, Session将其保存并留给后端Backend处理。
  26. """
  27. info = object()
  28. @staticmethod
  29. def active_session_count() -> int:
  30. raise NotImplementedError
  31. @staticmethod
  32. def get_current_session() -> "AbstractSession":
  33. raise NotImplementedError
  34. @staticmethod
  35. def get_current_task_id():
  36. raise NotImplementedError
  37. def __init__(self, target, session_info, on_task_command=None, on_session_close=None, **kwargs):
  38. """
  39. :param target:
  40. :param session_info: 会话信息。可以通过 Session.info 访问
  41. :param on_task_command: Backend向ession注册的处理函数,当 Session 收到task发送的command时调用
  42. :param on_session_close: Backend向Session注册的处理函数,当 Session task 执行结束时调用 *
  43. :param kwargs:
  44. .. note::
  45. 后端Backend在相应on_session_close时关闭连接时,需要保证会话内的所有消息都传送到了客户端
  46. """
  47. raise NotImplementedError
  48. def send_task_command(self, command):
  49. raise NotImplementedError
  50. def next_client_event(self) -> dict:
  51. """获取来自客户端的下一个事件。阻塞调用,若在等待过程中,会话被用户关闭,则抛出SessionClosedException异常"""
  52. raise NotImplementedError
  53. def send_client_event(self, event):
  54. raise NotImplementedError
  55. def get_task_commands(self) -> list:
  56. raise NotImplementedError
  57. def close(self):
  58. raise NotImplementedError
  59. def closed(self) -> bool:
  60. raise NotImplementedError
  61. def on_task_exception(self):
  62. raise NotImplementedError
  63. def register_callback(self, callback, **options):
  64. """ 向Session注册一个回调函数,返回回调id
  65. Session需要保证当收到前端发送的事件消息 ``{event: "callback",task_id: 回调id, data:...}`` 时,
  66. ``callback`` 回调函数被执行, 并传入事件消息中的 ``data`` 字段值作为参数
  67. """
  68. raise NotImplementedError
  69. def defer_call(self, func):
  70. """设置会话结束时调用的函数。可以用于资源清理。
  71. 在会话中可以多次调用 `defer_call()` ,会话结束后将会顺序执行设置的函数。
  72. :param func: 话结束时调用的函数
  73. """
  74. raise NotImplementedError
  75. def get_session_info_from_headers(headers):
  76. """从Http请求头中获取会话信息
  77. :param headers: 字典类型的Http请求头
  78. :return: 表示会话信息的对象,属性有:
  79. * ``user_agent`` : 用户浏览器信息。可用字段见 https://github.com/selwin/python-user-agents#usage
  80. * ``user_language`` : 用户操作系统使用的语言
  81. * ``server_host`` : 当前会话的服务器host,包含域名和端口,端口为80时可以被省略
  82. * ``origin`` : 当前用户的页面地址. 包含 协议、主机、端口 部分. 比如 ``'http://localhost:8080'`` .
  83. 只在当用户的页面地址不在当前服务器下(即 主机、端口部分和 ``server_host`` 不一致)时有值.
  84. """
  85. ua_str = headers.get('User-Agent', '')
  86. ua = user_agents.parse(ua_str)
  87. user_language = headers.get('Accept-Language', '').split(',', 1)[0].split(' ', 1)[0].split(';', 1)[0]
  88. server_host = headers.get('Host', '')
  89. origin = headers.get('Origin', '')
  90. session_info = ObjectDict(user_agent=ua, user_language=user_language,
  91. server_host=server_host, origin=origin)
  92. return session_info