Trio WebSocket

0.12.2 · maintenance · verified Sat Mar 28

Trio WebSocket is a Python library that provides a WebSocket implementation for the Trio asynchronous I/O framework. It offers both client and server functionalities, built on the `wsproto` sans-IO state machine, emphasizing safety, correctness, and ergonomics. The current stable version is 0.12.2. While mature and stable, the project is currently in 'life-support maintenance', with contributions welcomed.

Warnings

Install

Imports

Quickstart

This quickstart demonstrates a minimal `trio-websocket` client and server. The server, `echo_server_handler`, binds to `127.0.0.1:8000` and reverses any text messages it receives before sending them back. The client, `client_task`, connects to this server, sends a test message, and asserts that it receives the reversed message back. Both are run concurrently within a Trio nursery.

import trio
import logging
from trio_websocket import serve_websocket, open_websocket_url, ConnectionClosed, WebSocketRequest

logging.basicConfig(level=logging.INFO)

async def echo_server_handler(request: WebSocketRequest) -> None:
    """Reverses incoming websocket messages and sends them back."""
    logging.info('Server: Handler starting on path "%s"', request.path)
    ws = await request.accept()
    try:
        while True:
            message = await ws.get_message()
            logging.info('Server: Received message: %s', message)
            await ws.send_message(message[::-1]) # Echo reversed message
    except ConnectionClosed:
        logging.info('Server: Connection closed.')
    except Exception as e:
        logging.error('Server: Error in handler: %s', e)
    finally:
        logging.info('Server: Handler exiting.')

async def client_task(port: int) -> None:
    """Connects to the server, sends a message, and waits for a response."""
    uri = f'ws://127.0.0.1:{port}/echo'
    logging.info('Client: Connecting to %s', uri)
    try:
        async with open_websocket_url(uri) as ws:
            test_message = 'hello trio-websocket'
            logging.info('Client: Sending: "%s"', test_message)
            await ws.send_message(test_message)

            received_message = await ws.get_message()
            expected_message = test_message[::-1] # Reversed
            logging.info('Client: Received: "%s"', received_message)

            assert received_message == expected_message
            logging.info('Client: Message echoed and reversed successfully!')
    except OSError as ose:
        logging.error('Client: Connection attempt failed: %s', ose)
    except Exception as e:
        logging.error('Client: Error in client task: %s', e)
    finally:
        logging.info('Client: Task finished.')

async def main():
    server_port = 8000
    async with trio.open_nursery() as nursery:
        logging.info(f'Main: Spawning server on 127.0.0.1:{server_port}')
        nursery.start_soon(serve_websocket, echo_server_handler, '127.0.0.1', server_port, None)
        
        # Give the server a moment to start up
        await trio.sleep(0.1)
        
        logging.info('Main: Spawning client task.')
        nursery.start_soon(client_task, server_port)

if __name__ == '__main__':
    try:
        trio.run(main)
    except KeyboardInterrupt:
        logging.info('Program interrupted by user.')

view raw JSON →