Skip to content

Commit

Permalink
settings: Make the websocket settings clearer.
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
almet committed May 31, 2024
1 parent d4db078 commit 7990ac3
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 29 deletions.
41 changes: 28 additions & 13 deletions docs/config/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
12 changes: 6 additions & 6 deletions umap/settings/base.py
Original file line number Diff line number Diff line change
@@ -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()

# =============================================================================
Expand Down Expand Up @@ -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__))

Expand Down Expand Up @@ -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")
4 changes: 2 additions & 2 deletions umap/tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
2 changes: 1 addition & 1 deletion umap/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
19 changes: 12 additions & 7 deletions umap/ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down

0 comments on commit 7990ac3

Please sign in to comment.