From 7990ac363161e76367ca07925a853ace118db19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20M=C3=A9taireau?= Date: Fri, 31 May 2024 11:16:37 +0200 Subject: [PATCH] settings: Make the websocket settings clearer. It is now using `WEBSOCKET_BACK_HOST`, `WEBSOCKET_BACK_PORT` and `WEBSOCKET_FRONT_URI`. We need to take in consideration that the "front" WebSocket address (that clients will connect to) might be different than the "back" ip and port which are bound in the host. This happens for instance for reverse proxies, or when running inside a container. We considered using a `WEBSOCKET_TLS` setting, to try guessing the "front" address based on `WEBSOCKET_HOST`, `WEBSOCKET_PORT` and `WEBSOCKET_TLS`, but as the back and front address can differ, this would need to introduce a `WEBSOCKET_URI` in any case, so we went with just using it, and not adding an extra `WEBSOCKET_TLS`. --- docs/config/settings.md | 41 ++++++++++++++++++++++++++++------------- umap/settings/base.py | 12 ++++++------ umap/tests/settings.py | 4 ++-- umap/views.py | 2 +- umap/ws.py | 19 ++++++++++++------- 5 files changed, 49 insertions(+), 29 deletions(-) diff --git a/docs/config/settings.md b/docs/config/settings.md index 481572198..7e867ab0a 100644 --- a/docs/config/settings.md +++ b/docs/config/settings.md @@ -271,12 +271,15 @@ Otherwise, use any valid [python-social-auth configuration](https://python-socia #### WEBSOCKET_ENABLED -A websocket server is packaged with uMap, and can be turned-on to activate "real-time collaboration". -In practice, you would need to run the websocket server and specify a set of settings. +A WebSocket server is packaged with uMap, and can be turned-on to activate +"real-time collaboration". In practice, in order to enable it, a few settings +are exposed. -Turning this setting to `True` **will make a switch available** on each map, to enable "real-time collaboration". +Setting `WEBSOCKET_ENABLED` to `True` will **not** enable real-time +collaboration on all the maps served by the server. Instead, a switch will be +available in the "advanced properties" of the map. -You can run the websocket server with this command: +The websocket server can be run with the following command: ```bash python -m umap.ws @@ -286,19 +289,31 @@ Configuration example: ```python WEBSOCKET_ENABLED = True -WEBSOCKET_HOST = "localhost" -WEBSOCKET_PORT = 8002 -WEBSOCKET_URI = "ws://localhost:8002" +WEBSOCKET_BACK_HOST = "localhost" +WEBSOCKET_BACK_PORT = 8002 +WEBSOCKET_FRONT_URI = "ws://localhost:8002" ``` These settings can also be set with the (same names) environment variables. -#### WEBSOCKET_HOST -#### WEBSOCKET_PORT +#### WEBSOCKET_BACK_HOST +#### WEBSOCKET_BACK_PORT -The host and port for the websocket server. +The internal host and port the websocket server will connect to. -#### WEBSOCKET_URI +#### WEBSOCKET_FRONT_URI -The connection string that will be used by the client to connect to the websocket server. -Use `wss://host:port` if the server is behind TLS, and `ws://host:port` otherwise. +The connection string that will be used by the client to connect to the +websocket server. In practice, as it's useful to put the WebSocket server behind +TLS encryption, the values defined by `WEBSOCKET_FRONT_URI` are different than +the values defined by `WEBSOCKET_BACK_PORT` and `WEBSOCKET_BACK_HOST`. + +This value is comprised of three parts: + +``` +protocol://host:port +``` + +- `protocol`: can either be `ws` for plain unencrypted WebSockets, or `wss` when using TLS encryption. +- `host`: is the address where the connection will be sent. It should be public facing. +- `port`: is the port that is open on the host. diff --git a/umap/settings/base.py b/umap/settings/base.py index 63c42e1dd..7d926869d 100644 --- a/umap/settings/base.py +++ b/umap/settings/base.py @@ -1,11 +1,14 @@ """Base settings shared by all environments""" # Import global settings to make it easier to extend settings. +import os from email.utils import parseaddr import environ from django.conf.locale import LANG_INFO +import umap as project_module + env = environ.Env() # ============================================================================= @@ -137,9 +140,6 @@ # Calculation of directories relative to the project module location # ============================================================================= -import os - -import umap as project_module PROJECT_DIR = os.path.dirname(os.path.realpath(project_module.__file__)) @@ -310,6 +310,6 @@ # WebSocket configuration WEBSOCKET_ENABLED = env.bool("WEBSOCKET_ENABLED", default=False) -WEBSOCKET_HOST = env("WEBSOCKET_HOST", default="localhost") -WEBSOCKET_PORT = env.int("WEBSOCKET_PORT", default=8001) -WEBSOCKET_URI = env("WEBSOCKET_URI", default="ws://localhost:8001") +WEBSOCKET_BACK_HOST = env("WEBSOCKET_BACK_HOST", default="localhost") +WEBSOCKET_BACK_PORT = env.int("WEBSOCKET_BACK_PORT", default=8001) +WEBSOCKET_FRONT_URI = env("WEBSOCKET_FRONT_URI", default="ws://localhost:8001") diff --git a/umap/tests/settings.py b/umap/tests/settings.py index 4a5f0130c..b776c0835 100644 --- a/umap/tests/settings.py +++ b/umap/tests/settings.py @@ -27,5 +27,5 @@ WEBSOCKET_ENABLED = True -WEBSOCKET_PORT = "8010" -WEBSOCKET_URI = "ws://localhost:8010" +WEBSOCKET_BACK_PORT = "8010" +WEBSOCKET_FRONT_URI = "ws://localhost:8010" diff --git a/umap/views.py b/umap/views.py index d3046281d..9a3e2dd23 100644 --- a/umap/views.py +++ b/umap/views.py @@ -504,7 +504,7 @@ def get_map_properties(self): "umap_version": VERSION, "featuresHaveOwner": settings.UMAP_DEFAULT_FEATURES_HAVE_OWNERS, "websocketEnabled": settings.WEBSOCKET_ENABLED, - "websocketURI": settings.WEBSOCKET_URI, + "websocketURI": settings.WEBSOCKET_FRONT_URI, } created = bool(getattr(self, "object", None)) if (created and self.object.owner) or (not created and not user.is_anonymous): diff --git a/umap/ws.py b/umap/ws.py index 22d82f2fa..54345af73 100644 --- a/umap/ws.py +++ b/umap/ws.py @@ -83,15 +83,20 @@ async def handler(websocket): async def main(): if not settings.WEBSOCKET_ENABLED: - print("WEBSOCKET_ENABLED should be set to True to run the WebSocket Server") + msg = ( + "WEBSOCKET_ENABLED should be set to True to run the WebSocket Server. " + "See the documentation at " + "https://docs.umap-project.org/en/stable/config/settings/#websocket_enabled " + "for more information." + ) + print(msg) exit(1) - async with serve(handler, settings.WEBSOCKET_HOST, settings.WEBSOCKET_PORT): - print( - ( - f"Waiting for connections on {settings.WEBSOCKET_HOST}:{settings.WEBSOCKET_PORT}" - ) - ) + host = settings.WEBSOCKET_BACK_HOST + port = settings.WEBSOCKET_BACK_PORT + + async with serve(handler, host, port): + print(f"Waiting for connections on {host}:{port}") await asyncio.Future() # run forever