(uri: str)
| 102 | |
| 103 | |
| 104 | async def interactive_client(uri: str) -> None: |
| 105 | try: |
| 106 | websocket = await connect(uri) |
| 107 | except Exception as exc: |
| 108 | print(f"Failed to connect to {uri}: {exc}.") |
| 109 | sys.exit(1) |
| 110 | else: |
| 111 | print(f"Connected to {uri}.") |
| 112 | |
| 113 | loop = asyncio.get_running_loop() |
| 114 | transport, protocol = await loop.connect_read_pipe(ReadLines, sys.stdin) |
| 115 | incoming = asyncio.create_task( |
| 116 | print_incoming_messages(websocket), |
| 117 | ) |
| 118 | outgoing = asyncio.create_task( |
| 119 | send_outgoing_messages(websocket, protocol.messages), |
| 120 | ) |
| 121 | try: |
| 122 | await asyncio.wait( |
| 123 | [incoming, outgoing], |
| 124 | # Clean up and exit when the server closes the connection |
| 125 | # or the user enters EOT (^D), whichever happens first. |
| 126 | return_when=asyncio.FIRST_COMPLETED, |
| 127 | ) |
| 128 | # asyncio.run() cancels the main task when the user triggers SIGINT (^C). |
| 129 | # https://docs.python.org/3/library/asyncio-runner.html#handling-keyboard-interruption |
| 130 | # Clean up and exit without re-raising CancelledError to prevent Python |
| 131 | # from raising KeyboardInterrupt and displaying a stack track. |
| 132 | except asyncio.CancelledError: # pragma: no cover |
| 133 | pass |
| 134 | finally: |
| 135 | incoming.cancel() |
| 136 | outgoing.cancel() |
| 137 | transport.close() |
| 138 | |
| 139 | await websocket.close() |
| 140 | assert websocket.close_code is not None and websocket.close_reason is not None |
| 141 | close_status = Close(websocket.close_code, websocket.close_reason) |
| 142 | print_over_input(f"Connection closed: {close_status}.") |
| 143 | |
| 144 | |
| 145 | def main(argv: list[str] | None = None) -> None: |
no test coverage detected
searching dependent graphs…