@@ -101,6 +101,7 @@ call its APIs in the websockets server.
101101Now here's how to implement authentication.
102102
103103.. literalinclude :: ../../example/django/authentication.py 
104+  :caption:  authentication.py
104105
105106Let's unpack this code.
106107
@@ -113,23 +114,25 @@ your settings module.
113114
114115The connection handler reads the first message received from the client, which
115116is expected to contain a django-sesame token. Then it authenticates the user
116- with `` get_user()  `` , the API for ` authentication outside a view `_. If 
117- authentication fails, it closes the connection and exits .
117+ with :func: ` ~sesame.utils. get_user` , the API provided by django-sesame for 
118+ ` authentication outside a view  `_ .
118119
119120.. _authentication outside a view : https://django-sesame.readthedocs.io/en/stable/howto.html#outside-a-view 
120121
121- When we call an API that makes a database query such as ``get_user() ``, we
122- wrap the call in :func: `~asyncio.to_thread `. Indeed, the Django ORM doesn't
123- support asynchronous I/O. It would block the event loop if it didn't run in a
124- separate thread.
122+ If authentication fails, it closes the connection and exits.
123+ 
124+ When we call an API that makes a database query such as
125+ :func: `~sesame.utils.get_user `, we wrap the call in :func: `~asyncio.to_thread `.
126+ Indeed, the Django ORM doesn't support asynchronous I/O. It would block the
127+ event loop if it didn't run in a separate thread.
125128
126129Finally, we start a server with :func: `~websockets.asyncio.server.serve `.
127130
128131We're ready to test!
129132
130- Save this code to a file called `` authentication.py ``, make sure the 
131- ``DJANGO_SETTINGS_MODULE `` environment variable is set properly, and start the 
132- websockets server:
133+ Download  :download: ` authentication.py   < ../../example/django/authentication.py >`, 
134+ make sure the  ``DJANGO_SETTINGS_MODULE `` environment variable is set properly,
135+ and start the  websockets server:
133136
134137.. code-block :: console 
135138
@@ -169,7 +172,7 @@ following code in the JavaScript console of the browser:
169172 websocket .onmessage  =  (event ) =>  console .log (event .data ); 
170173
171174
172- server, you can build  a separate  Django project with ``django.contrib.auth ``,
175+ server, you can create  a simpler  Django project with ``django.contrib.auth ``,
173176``django-sesame ``, a suitable ``User `` model, and a subset of the settings of
174177the main project.
175178
@@ -184,11 +187,11 @@ action was made. This may be used for showing notifications to other users.
184187
185188Many use cases for WebSocket with Django follow a similar pattern.
186189
187- Set up event bus 
188- ................ 
190+ Set up event stream 
191+ ...................  
189192
190- We need a  event bus  to enable communications between Django and websockets.
191- Both sides connect permanently to the bus . Then Django writes events and
193+ We need an  event stream  to enable communications between Django and websockets.
194+ Both sides connect permanently to the stream . Then Django writes events and
192195websockets reads them. For the sake of simplicity, we'll rely on `Redis 
193196Pub/Sub `_.
194197
@@ -219,14 +222,15 @@ change ``get_redis_connection("default")`` in the code below to the same name.
219222Publish events
220223.............. 
221224
222- Now let's write events to the bus .
225+ Now let's write events to the stream .
223226
224227Add the following code to a module that is imported when your Django project
225- starts. Typically, you would put it in a ``signals.py `` module, which you
226- would import in the ``AppConfig.ready() `` method of one of your apps:
228+ starts. Typically, you would put it in a :download: `signals.py 
229+ <../../example/django/signals.py>` module, which you would import in the
230+ ``AppConfig.ready() `` method of one of your apps:
227231
228232.. literalinclude :: ../../example/django/signals.py 
229- 
233+   :caption:  signals.py 
230234This code runs every time the admin saves a ``LogEntry `` object to keep track
231235of a change. It extracts interesting data, serializes it to JSON, and writes
232236an event to Redis.
@@ -256,13 +260,13 @@ We need to add several features:
256260
257261* Keep track of connected clients so we can broadcast messages.
258262* Tell which content types the user has permission to view or to change.
259- * Connect to the message bus  and read events.
263+ * Connect to the message stream  and read events.
260264* Broadcast these events to users who have corresponding permissions.
261265
262266Here's a complete implementation.
263267
264268.. literalinclude :: ../../example/django/notifications.py 
265- 
269+   :caption:  notifications.py 
266270Since the ``get_content_types() `` function makes a database query, it is
267271wrapped inside :func: `asyncio.to_thread() `. It runs once when each WebSocket
268272connection is open; then its result is cached for the lifetime of the
@@ -273,13 +277,10 @@ The connection handler merely registers the connection in a global variable,
273277associated to the list of content types for which events should be sent to
274278that connection, and waits until the client disconnects.
275279
276- The ``process_events() `` function reads events from Redis and broadcasts them
277- to all connections that should receive them. We don't care much if a sending a
278- notification fails — this happens when a connection drops between the moment
279- we iterate on connections and the moment the corresponding message is sent —
280- so we start a task with for each message and forget about it. Also, this means
281- we're immediately ready to process the next event, even if it takes time to
282- send a message to a slow client.
280+ The ``process_events() `` function reads events from Redis and broadcasts them to
281+ all connections that should receive them. We don't care much if a sending a
282+ notification fails. This happens when a connection drops between the moment we
283+ iterate on connections and the moment the corresponding message is sent.
283284
284285Since Redis can publish a message to multiple subscribers, multiple instances
285286of this server can safely run in parallel.
@@ -290,4 +291,4 @@ Does it scale?
290291In theory, given enough servers, this design can scale to a hundred million
291292clients, since Redis can handle ten thousand servers and each server can
292293handle ten thousand clients. In practice, you would need a more scalable
293- message bus  before reaching that scale, due to the volume of messages.
294+ message stream  before reaching that scale, due to the volume of messages.
0 commit comments