diff --git a/docs/config/settings.md b/docs/config/settings.md index 7e867ab0..fe7273bd 100644 --- a/docs/config/settings.md +++ b/docs/config/settings.md @@ -279,12 +279,15 @@ 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. -The websocket server can be run with the following command: +The websocket server can be started with the following command: ```bash -python -m umap.ws +umap run_websocket_server ``` +And can take optional settings `--host` and `--port` (default values are defined in +the settings). + Configuration example: ```python diff --git a/umap/management/commands/run_websocket_server.py b/umap/management/commands/run_websocket_server.py new file mode 100644 index 00000000..62fb2142 --- /dev/null +++ b/umap/management/commands/run_websocket_server.py @@ -0,0 +1,23 @@ +from django.conf import settings +from django.core.management.base import BaseCommand + +from umap import ws + + +class Command(BaseCommand): + help = "Run the websocket server" + + def add_arguments(self, parser): + parser.add_argument( + "--host", + help="The server host to bind to.", + default=settings.WEBSOCKET_BACK_HOST, + ) + parser.add_argument( + "--port", + help="The server port to bind to.", + default=settings.WEBSOCKET_BACK_PORT, + ) + + def handle(self, *args, **options): + ws.run(options["host"], options["port"]) diff --git a/umap/settings/__init__.py b/umap/settings/__init__.py index e12998df..914e8dc6 100644 --- a/umap/settings/__init__.py +++ b/umap/settings/__init__.py @@ -43,6 +43,3 @@ if path: globals()["STATICFILES_DIRS"].insert(0, value) else: globals()[key] = value - -# Expose these settings for consumption by e.g. django.settings.configure. -settings_as_dict = {k: v for k, v in globals().items() if k.isupper()} diff --git a/umap/ws.py b/umap/ws.py index 54345af7..3ba81394 100644 --- a/umap/ws.py +++ b/umap/ws.py @@ -4,7 +4,6 @@ import asyncio from collections import defaultdict from typing import Literal, Optional -import django import websockets from django.conf import settings from django.core.signing import TimestampSigner @@ -12,13 +11,6 @@ from pydantic import BaseModel, ValidationError from websockets import WebSocketClientProtocol from websockets.server import serve -# This needs to run before the django-specific imports -# See https://docs.djangoproject.com/en/5.0/topics/settings/#calling-django-setup-is-required-for-standalone-django-usage -from umap.settings import settings_as_dict - -settings.configure(**settings_as_dict) -django.setup() - from umap.models import Map, User # NOQA # Contains the list of websocket connections handled by this process. @@ -81,7 +73,7 @@ async def handler(websocket): await join_and_listen(map_id, permissions, user, websocket) -async def main(): +def run(host, port): if not settings.WEBSOCKET_ENABLED: msg = ( "WEBSOCKET_ENABLED should be set to True to run the WebSocket Server. " @@ -92,12 +84,9 @@ async def main(): print(msg) exit(1) - host = settings.WEBSOCKET_BACK_HOST - port = settings.WEBSOCKET_BACK_PORT + async def _serve(): + async with serve(handler, host, port): + print(f"Waiting for connections on {host}:{port}") + await asyncio.Future() # run forever - async with serve(handler, host, port): - print(f"Waiting for connections on {host}:{port}") - await asyncio.Future() # run forever - - -asyncio.run(main()) + asyncio.run(_serve())