/wwqLyParse/common/connection_server.py

https://github.com/wwqgtxx/wwqLyParse · Python · 72 lines · 60 code · 8 blank · 4 comment · 15 complexity · 3a12d761aaae375738c935f5d50bf480 MD5 · raw file

  1. #!/usr/bin/env python3.5
  2. # -*- coding: utf-8 -*-
  3. # author wwqgtxx <wwqgtxx@gmail.com>
  4. import multiprocessing.connection
  5. from . import asyncio
  6. from .async_pool import *
  7. from .async_pipe_connection import *
  8. import itertools
  9. import logging
  10. from typing import Dict, Tuple, List, Callable
  11. CONN_LRU_TIMEOUT = 60 * 60 # 1 hour
  12. class ConnectionServer(object):
  13. _counter = itertools.count().__next__
  14. def __init__(self,
  15. address: str,
  16. handle,
  17. authkey: bytes = None,
  18. wrap_ssl=False,
  19. logger=logging.root):
  20. self.address = address
  21. self.handle = handle
  22. self.authkey = authkey
  23. self.wrap_ssl = wrap_ssl
  24. self.logger = logger
  25. async def _handle(self, conn: AsyncPipeConnection):
  26. try:
  27. if self.authkey:
  28. await conn.do_auth(self.authkey)
  29. while True:
  30. data = await asyncio.wait_for(conn.recv_bytes(), CONN_LRU_TIMEOUT)
  31. if not data:
  32. raise EOFError
  33. self.logger.debug("parse conn %s" % conn)
  34. # self.logger.debug(data)
  35. try:
  36. result = await asyncio.async_run_func_or_co(self.handle, data)
  37. except Exception:
  38. self.logger.exception("handle error")
  39. else:
  40. if result is not None:
  41. await asyncio.wait_for(conn.send_bytes(result), CONN_LRU_TIMEOUT)
  42. except asyncio.TimeoutError:
  43. self.logger.debug("conn %s was timeout" % conn)
  44. conn.close()
  45. except OSError:
  46. self.logger.debug("conn %s was closed" % conn)
  47. conn.close()
  48. except EOFError:
  49. self.logger.debug("conn %s was eof" % conn)
  50. conn.close()
  51. except BrokenPipeError:
  52. self.logger.debug("conn %s was broken" % conn)
  53. conn.close()
  54. async def run(self):
  55. handle_pool = AsyncPool(thread_name_prefix="HandlePool-%d" % self._counter())
  56. async with AsyncPipeListener(self.address, wrap_ssl=self.wrap_ssl) as listener:
  57. while True:
  58. try:
  59. conn = await listener.accept()
  60. self.logger.debug("get a new conn %s" % conn)
  61. handle_pool.spawn(self._handle(conn))
  62. except:
  63. self.logger.exception("error")
  64. __all__ = ["ConnectionServer", "CONN_LRU_TIMEOUT"]