diff --git a/docs/index.rst b/docs/index.rst index 3fa79b11..eddcf057 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -44,6 +44,7 @@ OpenWISP architecture. user/radius_monitoring user/management_commands.rst user/rest-api.rst + user/websocket-api.rst user/settings.rst .. toctree:: diff --git a/docs/user/generating_users.rst b/docs/user/generating_users.rst index 59bd7410..bd6c1898 100644 --- a/docs/user/generating_users.rst +++ b/docs/user/generating_users.rst @@ -84,3 +84,16 @@ REST API: Batch user creation See API documentation: :ref:`Batch user creation `. + +Real-time batch status via WebSocket +------------------------------------ + +When the number of users to generate meets or exceeds +:ref:`OPENWISP_RADIUS_BATCH_ASYNC_THRESHOLD +`, the operation runs +asynchronously via Celery and the batch status is delivered to connected +clients in real time. + +See :ref:`WebSocket API Reference: Batch User Creation Status +` for the endpoint URL, message format, and +integration example. diff --git a/docs/user/importing_users.rst b/docs/user/importing_users.rst index 748cb7ab..de168314 100644 --- a/docs/user/importing_users.rst +++ b/docs/user/importing_users.rst @@ -116,3 +116,16 @@ REST API: Batch user creation See :ref:`API documentation: Batch user creation `. + +Real-time batch status via WebSocket +------------------------------------ + +When the number of users to import meets or exceeds +:ref:`OPENWISP_RADIUS_BATCH_ASYNC_THRESHOLD +`, the operation runs +asynchronously via Celery and the batch status is delivered to connected +clients in real time. + +See :ref:`WebSocket API Reference: Batch User Creation Status +` for the endpoint URL, message format, and +integration example. diff --git a/docs/user/settings.rst b/docs/user/settings.rst index ebbe8d64..67091e91 100644 --- a/docs/user/settings.rst +++ b/docs/user/settings.rst @@ -111,6 +111,8 @@ The default encryption format for storing radius check values. A list of disabled encryption formats, by default all formats are enabled in order to keep backward compatibility with legacy systems. +.. _openwisp_radius_batch_async_threshold: + ``OPENWISP_RADIUS_BATCH_ASYNC_THRESHOLD`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -123,6 +125,12 @@ keeps the user interface responsive when creating a large number of users. For batches smaller than the threshold, users will be created immediately (synchronously). +.. note:: + + When batch processing runs asynchronously, the final batch status + (``"completed"`` or ``"failed"``) is delivered to connected clients in + real time via the :ref:`WebSocket API `. + ``OPENWISP_RADIUS_BATCH_DEFAULT_PASSWORD_LENGTH`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/user/websocket-api.rst b/docs/user/websocket-api.rst new file mode 100644 index 00000000..f22ee54a --- /dev/null +++ b/docs/user/websocket-api.rst @@ -0,0 +1,171 @@ +.. _radius_websocket_api: + +WebSocket API Reference +======================= + +.. contents:: **Table of contents**: + :depth: 2 + :local: + +Overview +-------- + +The WebSocket API provides real-time status updates for batch user +creation operations. + +When a batch is processed asynchronously (i.e., the number of users to +generate or import meets or exceeds +:ref:`OPENWISP_RADIUS_BATCH_ASYNC_THRESHOLD +`), the Django admin interface +automatically connects to the relevant endpoint to receive live status +updates without polling. + +All endpoints: + +- Use JSON-encoded messages on the wire. +- Require an authenticated staff user via session-based authentication. +- Push real-time updates after the connection is established. +- Do not accept client messages: any data sent from the client is ignored. + +Authentication and Authorization +-------------------------------- + +All WebSocket endpoints require an authenticated user. + +A connection is accepted only if the user is authorized to access the +requested resource. The connection is closed immediately if authorization +fails. + +Authentication uses the Django session cookie via ``AuthMiddlewareStack`` +(from ``channels.auth``). DRF token authentication is not supported for +WebSocket connections. + +The ``Origin`` header is validated against ``ALLOWED_HOSTS`` via +``AllowedHostsOriginValidator``. Cross-origin connections from untrusted +hosts are rejected. + +A user is authorized only if authenticated and marked as staff, and one of +the following conditions is true: + +- The user is a superuser, OR +- The user is an organization manager for the organization that owns the + requested batch. + +If any check fails, the server closes the connection without sending any +message. + +Connection Endpoints +-------------------- + +1. Batch User Creation Status +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This endpoint delivers real-time status updates for a single batch user +creation operation. + +Connection URL +++++++++++++++ + +:: + + wss:///ws/radius/batch// + +- ````: the hostname and port of the OpenWISP instance. +- ````: the UUID of the ``RadiusBatch`` object to monitor. + +.. note:: + + Use ``wss://`` for HTTPS deployments and ``ws://`` for plain HTTP + (development only). Never use ``ws://`` in production. + +Scope ++++++ + +A single batch user creation operation identified by its UUID. + +Client Message +++++++++++++++ + +The endpoint does not expose a request/response message for retrieving the +current state on demand. Messages are delivered when batch processing +finishes. + +.. warning:: + + Any message sent by the client is ignored. + +Real-time Updates ++++++++++++++++++ + +After the connection is established, the client does not need to send any +messages. The server pushes exactly **one** message when batch processing +finishes (either successfully or with an error). + +.. code-block:: javascript + + { + "status": "" + } + +The ``status`` field contains one of the following values: + +.. list-table:: + :header-rows: 1 + + - - Value + - Description + - - ``"pending"`` + - The batch has been created but processing has not yet started. + This value is not sent via WebSocket; it is visible only through + the REST API or admin interface. + - - ``"processing"`` + - The batch is currently being processed. This value is not sent via + WebSocket; it is the status visible when the admin page is opened + and the WebSocket connection is established. + - - ``"completed"`` + - Batch processing finished successfully. This is a terminal status. + - - ``"failed"`` + - Batch processing encountered an error. This is a terminal status. + +.. note:: + + The server sends exactly one message per connection, always with a + terminal status (``"completed"`` or ``"failed"``). The client should + close the connection after receiving it. + +Connection Lifecycle +++++++++++++++++++++ + +1. The client connects to the endpoint with the batch UUID in the URL. +2. If the user is authorized, the connection is accepted and the client is + added to the channel group ``radius_batch_``. +3. When batch processing finishes, the server sends one JSON message + containing the terminal status. +4. The client should close the connection upon receiving ``"completed"`` + or ``"failed"``. +5. On disconnect, the client is removed from the channel group. + +Example Client (JavaScript) ++++++++++++++++++++++++++++ + +Example based on the admin interface implementation: + +.. code-block:: javascript + + const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; + const wsUrl = protocol + "//" + window.location.host + + "/ws/radius/batch//"; + const socket = new WebSocket(wsUrl); + + socket.onmessage = function (event) { + const data = JSON.parse(event.data); + if (data.status === "completed" || data.status === "failed") { + socket.close(); + } + }; + + socket.onclose = function (event) { + console.log("RadiusBatch status socket closed."); + }; + +Replace ```` with the UUID of the batch object.