Handle the lifecycle of a WebSocket connection. Since this method doesn't have a caller that can handle exceptions, it attempts to log relevant ones. It guarantees that the TCP connection is closed before exiting.
(self, connection: ServerConnection)
| 341 | self.logger.info("server listening on %s", name) |
| 342 | |
| 343 | async def conn_handler(self, connection: ServerConnection) -> None: |
| 344 | """ |
| 345 | Handle the lifecycle of a WebSocket connection. |
| 346 | |
| 347 | Since this method doesn't have a caller that can handle exceptions, |
| 348 | it attempts to log relevant ones. |
| 349 | |
| 350 | It guarantees that the TCP connection is closed before exiting. |
| 351 | |
| 352 | """ |
| 353 | try: |
| 354 | async with asyncio_timeout(self.open_timeout): |
| 355 | try: |
| 356 | await connection.handshake( |
| 357 | self.process_request, |
| 358 | self.process_response, |
| 359 | self.server_header, |
| 360 | ) |
| 361 | except asyncio.CancelledError: |
| 362 | connection.transport.abort() |
| 363 | raise |
| 364 | except Exception: |
| 365 | connection.logger.error("opening handshake failed", exc_info=True) |
| 366 | connection.transport.abort() |
| 367 | return |
| 368 | |
| 369 | if connection.protocol.state is not OPEN: |
| 370 | # process_request or process_response rejected the handshake. |
| 371 | connection.transport.abort() |
| 372 | return |
| 373 | |
| 374 | try: |
| 375 | connection.start_keepalive() |
| 376 | await self.handler(connection) |
| 377 | except Exception: |
| 378 | connection.logger.error("connection handler failed", exc_info=True) |
| 379 | await connection.close(CloseCode.INTERNAL_ERROR) |
| 380 | else: |
| 381 | await connection.close() |
| 382 | |
| 383 | except TimeoutError: |
| 384 | # When the opening handshake times out, there's nothing to log. |
| 385 | pass |
| 386 | |
| 387 | except Exception: # pragma: no cover |
| 388 | # Don't leak connections on unexpected errors. |
| 389 | connection.transport.abort() |
| 390 | |
| 391 | finally: |
| 392 | # Registration is tied to the lifecycle of conn_handler() because |
| 393 | # the server waits for connection handlers to terminate, even if |
| 394 | # all connections are already closed. |
| 395 | del self.handlers[connection] |
| 396 | |
| 397 | def start_connection_handler(self, connection: ServerConnection) -> None: |
| 398 | """ |
no test coverage detected