async def test_simple(): task = asyncio_utils.create_task(ttask(), name="ttask", client=("127.0.0.1", 42313)) assert asyncio_utils.task_repr(task) == "127.0.0.1:42313: ttask (age: 0s)" await asyncio.sleep(0) assert "newname" in asyncio_utils.task_repr(task) asyncio_utils.cancel_task(task, "bye") await asyncio.sleep(0) assert task.cancelled()
async def drain_writers(self): """ Drain all writers to create some backpressure. We won't continue reading until there's space available in our write buffers, so if we cannot write fast enough our own read buffers run full and the TCP recv stream is throttled. """ async with self._drain_lock: for transport in self.transports.values(): if transport.writer is not None: try: await transport.writer.drain() except OSError as e: if transport.handler is not None: asyncio_utils.cancel_task(transport.handler, f"Error sending data: {e}")
async def handle_client(self) -> None: watch = asyncio_utils.create_task( self.timeout_watchdog.watch(), name="timeout watchdog", client=self.client.peername, ) if not watch: return # this should not be needed, see asyncio_utils.create_task self.log("client connect") await self.handle_hook(server_hooks.ClientConnectedHook(self.client)) if self.client.error: self.log("client kill connection") writer = self.transports.pop(self.client).writer assert writer writer.close() else: handler = asyncio_utils.create_task( self.handle_connection(self.client), name=f"client connection handler", client=self.client.peername, ) if not handler: return # this should not be needed, see asyncio_utils.create_task self.transports[self.client].handler = handler self.server_event(events.Start()) await asyncio.wait([handler]) watch.cancel() self.log("client disconnect") self.client.timestamp_end = time.time() await self.handle_hook(server_hooks.ClientDisconnectedHook(self.client) ) if self.transports: self.log("closing transports...", "debug") for io in self.transports.values(): if io.handler: asyncio_utils.cancel_task(io.handler, "client disconnected") await asyncio.wait( [x.handler for x in self.transports.values() if x.handler]) self.log("transports closed!", "debug")
def close_connection(self, connection: Connection, half_close: bool = False) -> None: if half_close: if not connection.state & ConnectionState.CAN_WRITE: return self.log(f"half-closing {connection}", "debug") try: writer = self.transports[connection].writer assert writer writer.write_eof() except OSError: # if we can't write to the socket anymore we presume it completely dead. connection.state = ConnectionState.CLOSED else: connection.state &= ~ConnectionState.CAN_WRITE else: connection.state = ConnectionState.CLOSED if connection.state is ConnectionState.CLOSED: handler = self.transports[connection].handler assert handler asyncio_utils.cancel_task(handler, "closed by command")
async def on_timeout(self) -> None: self.log(f"Closing connection due to inactivity: {self.client}") handler = self.transports[self.client].handler assert handler asyncio_utils.cancel_task(handler, "timeout")