WebSocket connection handler for ASGI applications. Uses callback-based data feeding instead of StreamReader for efficiency. Data is fed via feed_data() from the parent protocol's data_received().
| 40 | |
| 41 | |
| 42 | class WebSocketProtocol: |
| 43 | """WebSocket connection handler for ASGI applications. |
| 44 | |
| 45 | Uses callback-based data feeding instead of StreamReader for efficiency. |
| 46 | Data is fed via feed_data() from the parent protocol's data_received(). |
| 47 | """ |
| 48 | |
| 49 | def __init__(self, transport, scope, app, log): |
| 50 | """Initialize WebSocket protocol handler. |
| 51 | |
| 52 | Args: |
| 53 | transport: asyncio transport for writing |
| 54 | scope: ASGI WebSocket scope dict |
| 55 | app: ASGI application callable |
| 56 | log: Logger instance |
| 57 | """ |
| 58 | self.transport = transport |
| 59 | self.scope = scope |
| 60 | self.app = app |
| 61 | self.log = log |
| 62 | |
| 63 | self.accepted = False |
| 64 | self.closed = False |
| 65 | self.close_code = None |
| 66 | self.close_reason = "" |
| 67 | |
| 68 | # Close handshake state (RFC 6455 Section 7.1.1) |
| 69 | self._close_sent = False |
| 70 | self._close_received = False |
| 71 | self._close_event = asyncio.Event() |
| 72 | |
| 73 | # Message reassembly state |
| 74 | self._fragments = [] |
| 75 | self._fragment_opcode = None |
| 76 | |
| 77 | # Receive queue for incoming messages |
| 78 | self._receive_queue = asyncio.Queue() |
| 79 | |
| 80 | # Callback-based data reception (replaces StreamReader) |
| 81 | self._buffer = bytearray() |
| 82 | self._data_event = asyncio.Event() |
| 83 | self._eof = False |
| 84 | |
| 85 | def feed_data(self, data): |
| 86 | """Feed incoming data from the parent protocol's data_received(). |
| 87 | |
| 88 | Args: |
| 89 | data: bytes received on the connection |
| 90 | """ |
| 91 | if data: |
| 92 | self._buffer.extend(data) |
| 93 | self._data_event.set() |
| 94 | |
| 95 | def feed_eof(self): |
| 96 | """Signal that the connection has been closed.""" |
| 97 | self._eof = True |
| 98 | self._data_event.set() |
| 99 |
no outgoing calls