25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

137 lines
3.5 KiB

  1. import asyncio
  2. cdef class Server:
  3. def __cinit__(self, Loop loop):
  4. self._loop = loop
  5. self._servers = []
  6. self._waiters = []
  7. self._active_count = 0
  8. self._serving_forever_fut = None
  9. cdef _add_server(self, UVStreamServer srv):
  10. self._servers.append(srv)
  11. cdef _start_serving(self):
  12. if self._serving:
  13. return
  14. self._serving = 1
  15. for server in self._servers:
  16. (<UVStreamServer>server).listen()
  17. cdef _wakeup(self):
  18. cdef list waiters
  19. waiters = self._waiters
  20. self._waiters = None
  21. for waiter in waiters:
  22. if not waiter.done():
  23. waiter.set_result(waiter)
  24. cdef _attach(self):
  25. assert self._servers is not None
  26. self._active_count += 1
  27. cdef _detach(self):
  28. assert self._active_count > 0
  29. self._active_count -= 1
  30. if self._active_count == 0 and self._servers is None:
  31. self._wakeup()
  32. cdef _ref(self):
  33. # Keep the server object alive while it's not explicitly closed.
  34. self._loop._servers.add(self)
  35. cdef _unref(self):
  36. self._loop._servers.discard(self)
  37. # Public API
  38. @cython.iterable_coroutine
  39. async def __aenter__(self):
  40. return self
  41. @cython.iterable_coroutine
  42. async def __aexit__(self, *exc):
  43. self.close()
  44. await self.wait_closed()
  45. def __repr__(self):
  46. return '<%s sockets=%r>' % (self.__class__.__name__, self.sockets)
  47. def get_loop(self):
  48. return self._loop
  49. @cython.iterable_coroutine
  50. async def wait_closed(self):
  51. # Do not remove `self._servers is None` below
  52. # because close() method only closes server sockets
  53. # and existing client connections are left open.
  54. if self._servers is None or self._waiters is None:
  55. return
  56. waiter = self._loop._new_future()
  57. self._waiters.append(waiter)
  58. await waiter
  59. def close(self):
  60. cdef list servers
  61. if self._servers is None:
  62. return
  63. try:
  64. servers = self._servers
  65. self._servers = None
  66. self._serving = 0
  67. for server in servers:
  68. (<UVStreamServer>server)._close()
  69. if self._active_count == 0:
  70. self._wakeup()
  71. finally:
  72. self._unref()
  73. def is_serving(self):
  74. return self._serving
  75. @cython.iterable_coroutine
  76. async def start_serving(self):
  77. self._start_serving()
  78. @cython.iterable_coroutine
  79. async def serve_forever(self):
  80. if self._serving_forever_fut is not None:
  81. raise RuntimeError(
  82. f'server {self!r} is already being awaited on serve_forever()')
  83. if self._servers is None:
  84. raise RuntimeError(f'server {self!r} is closed')
  85. self._start_serving()
  86. self._serving_forever_fut = self._loop.create_future()
  87. try:
  88. await self._serving_forever_fut
  89. except asyncio.CancelledError:
  90. try:
  91. self.close()
  92. await self.wait_closed()
  93. finally:
  94. raise
  95. finally:
  96. self._serving_forever_fut = None
  97. property sockets:
  98. def __get__(self):
  99. cdef list sockets = []
  100. # Guard against `self._servers is None`
  101. if self._servers:
  102. for server in self._servers:
  103. sockets.append(
  104. (<UVStreamServer>server)._get_socket()
  105. )
  106. return sockets