diff --git a/umap/static/umap/js/modules/sync/engine.js b/umap/static/umap/js/modules/sync/engine.js index 9a3ef611..749a707f 100644 --- a/umap/static/umap/js/modules/sync/engine.js +++ b/umap/static/umap/js/modules/sync/engine.js @@ -48,7 +48,7 @@ const MAX_RECONNECT_DELAY = 32000; * ``` */ export class SyncEngine { - constructor(map, urls, server) { + constructor(map, websocketTokenURI, websocketURI, server) { this.updaters = { map: new MapUpdater(map), feature: new FeatureUpdater(map), @@ -58,14 +58,12 @@ export class SyncEngine { this._operations = new Operations() this._server = server - // Store URIs to avoid persisting the map - // mainly to ensure separation of concerns. - this._websocketTokenURI = urls.get('map_websocket_auth_token', { - map_id: map.options.umap_id, - }) - this._websocketURI = map.options.websocketURI + this._websocketTokenURI = websocketTokenURI + this._websocketURI = websocketURI + this._reconnectTimeout = null; this._reconnectDelay = RECONNECT_DELAY; + this.websocketConnected = false; } /** @@ -92,9 +90,13 @@ export class SyncEngine { onConnection() { this._reconnectTimeout = null; this._reconnectDelay = RECONNECT_DELAY; + this.websocketConnected = true; } reconnect() { + this.websocketConnected = false; + this.updaters.map.update({ key: 'numberOfConnectedPeers' }) + console.log("reconnecting in ", this._reconnectDelay, " ms") this._reconnectTimeout = setTimeout(() => { if (this._reconnectDelay < MAX_RECONNECT_DELAY) { diff --git a/umap/static/umap/js/umap.controls.js b/umap/static/umap/js/umap.controls.js index c6e85e12..96847bd8 100644 --- a/umap/static/umap/js/umap.controls.js +++ b/umap/static/umap/js/umap.controls.js @@ -661,30 +661,43 @@ const ControlsMixin = { }) } - const connectedPeers = this.sync.getNumberOfConnectedPeers() - if (connectedPeers !== 0) { - const connectedPeersCount = L.DomUtil.createButton( - 'leaflet-control-connected-peers', - rightContainer, - '' - ) - L.DomEvent.on(connectedPeersCount, 'mouseover', () => { - this.tooltip.open({ - content: L._('{connectedPeers} peer(s) currently connected to this map', { - connectedPeers: connectedPeers, - }), - anchor: connectedPeersCount, - position: 'bottom', - delay: 500, - duration: 5000, - }) - }) + if (this.options.syncEnabled) { + const connectedPeers = this.sync.getNumberOfConnectedPeers() + let hoverMessage = '' - const updateConnectedPeersCount = () => { - connectedPeersCount.innerHTML = - '' + this.sync.getNumberOfConnectedPeers() + '' + if (connectedPeers !== 0 || !this.sync.websocketConnected) { + const connectedPeersCount = L.DomUtil.createButton( + 'leaflet-control-connected-peers', + rightContainer, + '' + ) + if (this.sync.websocketConnected) { + connectedPeersCount.innerHTML = + '' + this.sync.getNumberOfConnectedPeers() + '' + hoverMessage = L._( + '{connectedPeers} peer(s) currently connected to this map', + { + connectedPeers: connectedPeers, + } + ) + } else { + connectedPeersCount.innerHTML = '' + L._('Disconnected') + '' + connectedPeersCount.classList.add('disconnected') + hoverMessage = L._('Reconnecting in {seconds} seconds', { + seconds: this.sync._reconnectDelay / 1000, + }) + } + + L.DomEvent.on(connectedPeersCount, 'mouseover', () => { + this.tooltip.open({ + content: hoverMessage, + anchor: connectedPeersCount, + position: 'bottom', + delay: 500, + duration: 5000, + }) + }) } - updateConnectedPeersCount() } this.help.getStartedLink(rightContainer) diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index ccd94e15..0d51fcdd 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -68,7 +68,14 @@ U.Map = L.Map.extend({ this.server = new U.ServerRequest() this.request = new U.Request() - this.sync_engine = new U.SyncEngine(this, this.urls, this.server) + // Store URIs to avoid persisting the map + // mainly to ensure separation of concerns. + const websocketTokenURI = this.urls.get('map_websocket_auth_token', { + map_id: this.options.umap_id, + }) + const websocketURI = this.options.websocketURI + + this.sync_engine = new U.SyncEngine(this, websocketTokenURI, websocketURI, this.server) this.sync = this.sync_engine.proxy(this) this.initLoader() @@ -206,7 +213,9 @@ U.Map = L.Map.extend({ }, initSyncEngine: async function () { + // This.options.websocketEnabled is set by the server admin if (this.options.websocketEnabled === false) return + // This.options.syncEnabled is set by the user in the map settings if (this.options.syncEnabled !== true) { this.sync.stop() } else { diff --git a/umap/static/umap/map.css b/umap/static/umap/map.css index ce59df08..28bd63aa 100644 --- a/umap/static/umap/map.css +++ b/umap/static/umap/map.css @@ -518,6 +518,12 @@ ul.photon-autocomplete { background-color: var(--color-lightCyan); color: var(--color-dark); } +.leaflet-container .leaflet-control-connected-peers.disconnected, +.leaflet-container .leaflet-control-connected-peers.disconnected:hover +{ + background-color: var(--color-red); + color: var(--color-darkGray); +} .leaflet-container .leaflet-control-edit-disable:before, .leaflet-container .leaflet-control-edit-save:before, diff --git a/umap/static/umap/unittests/sync.js b/umap/static/umap/unittests/sync.js index 36d22b10..4d5a8e44 100644 --- a/umap/static/umap/unittests/sync.js +++ b/umap/static/umap/unittests/sync.js @@ -8,8 +8,11 @@ import { MapUpdater } from '../js/modules/sync/updaters.js' import { SyncEngine, Operations } from '../js/modules/sync/engine.js' describe('SyncEngine', () => { + const websocketTokenURI = 'http://localhost:8000/api/v1/maps/1/websocket_auth_token/' + const websocketURI = 'ws://localhost:8000/ws/maps/1/' + it('should initialize methods even before start', () => { - const engine = new SyncEngine({}) + const engine = new SyncEngine({}, websocketTokenURI, websocketURI, {}) engine.upsert() engine.update() engine.delete()