From 36d9e9bf062e444e2efc236125a909dfee644d5a Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Thu, 16 Jan 2025 16:43:48 +0100 Subject: [PATCH] wip(sync): use the correct URL for websocket Co-authored-by: David Larlet --- umap/settings/base.py | 1 - umap/static/umap/js/modules/sync/engine.js | 4 ++- umap/sync/app.py | 26 ++++++++-------- umap/utils.py | 35 +++++++++++++++------- umap/views.py | 1 - 5 files changed, 41 insertions(+), 26 deletions(-) diff --git a/umap/settings/base.py b/umap/settings/base.py index 1dc7748f..788a03b3 100644 --- a/umap/settings/base.py +++ b/umap/settings/base.py @@ -342,6 +342,5 @@ LOGGING = { WEBSOCKET_ENABLED = env.bool("WEBSOCKET_ENABLED", default=False) 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") REDIS_URL = "redis://localhost:6379" diff --git a/umap/static/umap/js/modules/sync/engine.js b/umap/static/umap/js/modules/sync/engine.js index c9b32167..9928865e 100644 --- a/umap/static/umap/js/modules/sync/engine.js +++ b/umap/static/umap/js/modules/sync/engine.js @@ -76,8 +76,10 @@ export class SyncEngine { } start(authToken) { + const path = this._umap.urls.get('ws_sync', { map_id: this._umap.id }) + const protocol = window.location.protocol === 'http:' ? 'ws:' : 'wss:' this.transport = new WebSocketTransport( - Utils.template(this._umap.properties.websocketURI, { id: this._umap.id }), + `${protocol}//${window.location.host}${path}`, authToken, this ) diff --git a/umap/sync/app.py b/umap/sync/app.py index 18db1c86..3b0bea0c 100644 --- a/umap/sync/app.py +++ b/umap/sync/app.py @@ -5,7 +5,7 @@ import uuid import redis.asyncio as redis from django.conf import settings from django.core.signing import TimestampSigner -from django.urls.resolvers import RoutePattern +from django.urls import path from pydantic import ValidationError from .payloads import ( @@ -17,20 +17,19 @@ from .payloads import ( Request, ) -ws_pattern = RoutePattern("/ws/sync/") - async def application(scope, receive, send): - matched = ws_pattern.match(scope["path"]) - print(matched) - if not matched: - print("Wrong path") - return - _, _, kwargs = matched + path = scope["path"].lstrip("/") + for pattern in urlpatterns: + if matched := pattern.resolve(path): + await matched.func(scope, receive, send, **matched.kwargs) + break + else: + await send({"type": "websocket.close"}) - map_id = kwargs["map_id"] - peer = Peer(uuid=uuid.uuid4(), map_id=map_id) - print(peer) + +async def sync(scope, receive, send, **kwargs): + peer = Peer(uuid=uuid.uuid4(), map_id=kwargs["map_id"]) peer._send = send while True: event = await receive() @@ -153,3 +152,6 @@ class Peer: async def send(self, text): print("SEND", text) await self._send({"type": "websocket.send", "text": text}) + + +urlpatterns = [path("ws/sync/", name="ws_sync", view=sync)] diff --git a/umap/utils.py b/umap/utils.py index 26cf581d..561ae702 100644 --- a/umap/utils.py +++ b/umap/utils.py @@ -7,23 +7,36 @@ from django.core.serializers.json import DjangoJSONEncoder from django.urls import URLPattern, URLResolver, get_resolver -def _urls_for_js(urls=None): +def _get_url_names(module): + def _get_names(resolver): + names = [] + for pattern in resolver.url_patterns: + if getattr(pattern, "url_patterns", None): + # Do not add "admin" and other third party apps urls. + if not pattern.namespace: + names.extend(_get_names(pattern)) + elif getattr(pattern, "name", None): + names.append(pattern.name) + return names + + return _get_names(get_resolver(module)) + + +def _urls_for_js(): """ Return templated URLs prepared for javascript. """ - if urls is None: - # prevent circular import - from .urls import i18n_urls, urlpatterns - - urls = [ - url.name for url in urlpatterns + i18n_urls if getattr(url, "name", None) - ] - urls = dict(zip(urls, [get_uri_template(url) for url in urls])) + urls = {} + for module in ["umap.urls", "umap.sync.app"]: + names = _get_url_names(module) + urls.update( + dict(zip(names, [get_uri_template(url, module=module) for url in names])) + ) urls.update(getattr(settings, "UMAP_EXTRA_URLS", {})) return urls -def get_uri_template(urlname, args=None, prefix=""): +def get_uri_template(urlname, args=None, prefix="", module=None): """ Utility function to return an URI Template from a named URL in django Copied from django-digitalpaper. @@ -45,7 +58,7 @@ def get_uri_template(urlname, args=None, prefix=""): paths = template % dict([p, "{%s}" % p] for p in args) return "%s/%s" % (prefix, paths) - resolver = get_resolver(None) + resolver = get_resolver(module) parts = urlname.split(":") if len(parts) > 1 and parts[0] in resolver.namespace_dict: namespace = parts[0] diff --git a/umap/views.py b/umap/views.py index d1952405..c8c09476 100644 --- a/umap/views.py +++ b/umap/views.py @@ -609,7 +609,6 @@ class MapDetailMixin(SessionMixin): "umap_version": VERSION, "featuresHaveOwner": settings.UMAP_DEFAULT_FEATURES_HAVE_OWNERS, "websocketEnabled": settings.WEBSOCKET_ENABLED, - "websocketURI": settings.WEBSOCKET_FRONT_URI, "importers": settings.UMAP_IMPORTERS, "defaultLabelKeys": settings.UMAP_LABEL_KEYS, }