summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools/third_party/websockets/docs/howto/patterns.rst
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/tools/third_party/websockets/docs/howto/patterns.rst')
-rw-r--r--testing/web-platform/tests/tools/third_party/websockets/docs/howto/patterns.rst110
1 files changed, 110 insertions, 0 deletions
diff --git a/testing/web-platform/tests/tools/third_party/websockets/docs/howto/patterns.rst b/testing/web-platform/tests/tools/third_party/websockets/docs/howto/patterns.rst
new file mode 100644
index 0000000000..c6f325d213
--- /dev/null
+++ b/testing/web-platform/tests/tools/third_party/websockets/docs/howto/patterns.rst
@@ -0,0 +1,110 @@
+Patterns
+========
+
+.. currentmodule:: websockets
+
+Here are typical patterns for processing messages in a WebSocket server or
+client. You will certainly implement some of them in your application.
+
+This page gives examples of connection handlers for a server. However, they're
+also applicable to a client, simply by assuming that ``websocket`` is a
+connection created with :func:`~client.connect`.
+
+WebSocket connections are long-lived. You will usually write a loop to process
+several messages during the lifetime of a connection.
+
+Consumer
+--------
+
+To receive messages from the WebSocket connection::
+
+ async def consumer_handler(websocket):
+ async for message in websocket:
+ await consumer(message)
+
+In this example, ``consumer()`` is a coroutine implementing your business
+logic for processing a message received on the WebSocket connection. Each
+message may be :class:`str` or :class:`bytes`.
+
+Iteration terminates when the client disconnects.
+
+Producer
+--------
+
+To send messages to the WebSocket connection::
+
+ async def producer_handler(websocket):
+ while True:
+ message = await producer()
+ await websocket.send(message)
+
+In this example, ``producer()`` is a coroutine implementing your business
+logic for generating the next message to send on the WebSocket connection.
+Each message must be :class:`str` or :class:`bytes`.
+
+Iteration terminates when the client disconnects
+because :meth:`~server.WebSocketServerProtocol.send` raises a
+:exc:`~exceptions.ConnectionClosed` exception,
+which breaks out of the ``while True`` loop.
+
+Consumer and producer
+---------------------
+
+You can receive and send messages on the same WebSocket connection by
+combining the consumer and producer patterns. This requires running two tasks
+in parallel::
+
+ async def handler(websocket):
+ await asyncio.gather(
+ consumer_handler(websocket),
+ producer_handler(websocket),
+ )
+
+If a task terminates, :func:`~asyncio.gather` doesn't cancel the other task.
+This can result in a situation where the producer keeps running after the
+consumer finished, which may leak resources.
+
+Here's a way to exit and close the WebSocket connection as soon as a task
+terminates, after canceling the other task::
+
+ async def handler(websocket):
+ consumer_task = asyncio.create_task(consumer_handler(websocket))
+ producer_task = asyncio.create_task(producer_handler(websocket))
+ done, pending = await asyncio.wait(
+ [consumer_task, producer_task],
+ return_when=asyncio.FIRST_COMPLETED,
+ )
+ for task in pending:
+ task.cancel()
+
+Registration
+------------
+
+To keep track of currently connected clients, you can register them when they
+connect and unregister them when they disconnect::
+
+ connected = set()
+
+ async def handler(websocket):
+ # Register.
+ connected.add(websocket)
+ try:
+ # Broadcast a message to all connected clients.
+ websockets.broadcast(connected, "Hello!")
+ await asyncio.sleep(10)
+ finally:
+ # Unregister.
+ connected.remove(websocket)
+
+This example maintains the set of connected clients in memory. This works as
+long as you run a single process. It doesn't scale to multiple processes.
+
+Publish–subscribe
+-----------------
+
+If you plan to run multiple processes and you want to communicate updates
+between processes, then you must deploy a messaging system. You may find
+publish-subscribe functionality useful.
+
+A complete implementation of this idea with Redis is described in
+the :doc:`Django integration guide <../howto/django>`.