Commit graph

2772 commits

Author SHA1 Message Date
49d0b715fb
refactor(sync): Sync layers creation with map.createDataLayer utility.
Rather than having it done inside the datalayer itself. This gives us
more control.
2024-06-07 16:32:25 +02:00
5366f24b51
refactor: rename geometrytoFeatures to geoJSONToLeaflet
Because we are dealing with technologies using overlapping vocabulary,
it is easy to get lost. Hopefully this change makes it clear that it
converts geoJSON inputs in Leaflet / uMap objects.
2024-06-07 16:32:25 +02:00
ec56b3f5c4
feat(sync): Add a proxy to the SyncEngine objects.
It is now possible to create proxy objects using `sync_engine.proxy(object)`.
The returned proxy object will automatically inject `metadata` and
`subject` parameters, after looking for them in the `getSyncMetadata`
method (these are only known to the synced objects).

As a result, the calls are now simplified:

```
this.sync.update("key", "value")
```
2024-06-07 16:32:24 +02:00
06e4d6a180
refactor(sync): remove formbuilder this._redraw() callbacks.
They are now handled in the `render()` call, so there is no more need
for them here.
2024-06-07 16:32:24 +02:00
5c17497431
refactor(sync): Remove syncUpdateProperties function.
The function was only used once, so removing it  simplified the whole
flow.
2024-06-07 16:32:24 +02:00
eb4f462e3d
fix: use array.includes(string) the proper way.
Because this `syncUpdatedProperties` function is only called once, it
didn't trigger any issue in practice (as the check was always returning
true).
2024-06-07 16:32:24 +02:00
5b99cc92fd
feat(websockets): run the WS server as a django management command.
This allows to handle the loading of the settings in a consistant way,
and aditionnaly to provide a way to override the `WEBSOCKET_BACK_HOST`
and `WEBSOCKET_BACK_PORT` settings with arg commands `--host` and
`--port`.

Without this change, because of how we are currently loading our
settings, we would require the settings the be exposed by the
`umap.settings.__init__` file.

Previous implementations were exposing these settings, with the
following code:

```python
settings_as_dict = {k: v for k, v in globals().items() if k.isupper()}
  ```
2024-06-07 16:32:24 +02:00
02f413bb41
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`.
2024-06-07 16:32:23 +02:00
fd42c2fca6
fixup: changes after @ybon's review. 2024-06-07 16:32:23 +02:00
d5c1e361c3
fix(sync): sync the reference-version across peers
This allows the merge algorithm to not be lost when receiving changes.
Without this change, the optimistic merge algorithm isn't able to make
the distinction between peers, and features end up duplicated.
2024-06-07 16:32:23 +02:00
8e1cf7b6da
tests(sync): Add a test ensuring cloned features aren't duplicated
This is currently a bug in the current implementation. Hopefully fixed
in later commits.
2024-06-07 16:32:23 +02:00
23e28e6698
test(sync): Ensure feature properties are synced 2024-06-07 16:32:23 +02:00
c5fdb8abde
docs(sync): Document WEBSOCKET_* settings 2024-06-07 16:32:22 +02:00
5fd0a2945a
chore(sync): remove belongsTo for now
As it requires more discussion, it will happen in a separate
pull-request.
2024-06-07 16:32:22 +02:00
f16491ace4
chore(test): remove empty test 2024-06-07 16:32:22 +02:00
5e6cb1ff03
chore(test): fix a typo
(but I would really like to see what web socker would look like)
2024-06-07 16:32:22 +02:00
b1e4233b25
chore(sync): relax some validation logic on the websocket server
Messages are now checked for conformity with the procol we defined, but
stop at the `operation` boundary. Values aren't checked.
2024-06-07 16:32:22 +02:00
8e7e071ad5
chore(sync): Sync engine now retrieves auth token
It's now it's responsability to get the authentication token from
the http server and pass it to the websocket server, it will make it
possible to redo the roundtrip when getting disconnected.
2024-06-07 16:32:21 +02:00
5c1c93f60e
chore(sync): use sync=false everywhere to stop propagation
In some cases, you want to stop the propagation of events. The previous
code was using `fromSync=true` and `sync=false` interchangeably. This
makes it use `sync=false` everywhere.
2024-06-07 16:32:21 +02:00
0a1b2760de
chore(utils): remove console.log calls 2024-06-07 16:32:21 +02:00
49913bf206
fix(schema): dashArray belongs to features as well 2024-06-07 16:32:21 +02:00
b0b0240103
test(sync): Ensure datalayer properties are synced 2024-06-07 16:32:21 +02:00
b57c37fe5c
test(sync): Ensure map properties are synced
This tests that the name of the map, and that zoom-control visibility is
properly synced over websockets.
2024-06-07 16:32:21 +02:00
83ff674d0c
test(sync): ensure polygon drag-n-drop is synced 2024-06-07 16:32:20 +02:00
91689d6c1c
test(sync): Ensure polygons and their edits can be synced 2024-06-07 16:32:20 +02:00
98a9815c33
test(sync): Marker drag-n-drop and delete are synced 2024-06-07 16:32:20 +02:00
7ad0708033
tests(sync): Test that marker sync works properly
This commit handles the start and stop of the websocket server during
the tests, using the xprocess library
2024-06-07 16:32:20 +02:00
fc61d41403
chore(tests): Rename "collaboration" tests to "optimistic merge"
As "collaboration" can be mistaken between "websocket" and
"server-merge". This naming makes it explicit.
2024-06-07 16:32:20 +02:00
0a37871e0c
chore(sync): Add message-dispatcher unit tests 2024-06-07 16:32:19 +02:00
ff840a29e0
feat(sync): Add JS unittests for updateObjectValue, and refactor.
The new implementation uses `reduce`, in the hopes of producing a more
readable version than old-style loops and reassignment of object values.
2024-06-07 16:32:19 +02:00
6d08f2085c
feat(sync): add tests for the websocket token view 2024-06-07 16:32:19 +02:00
41ce203c58
refactor(sync): Remove unnecessary complexity
Because we're relying on the `geoJSONToFeatures` method, we don't need
anymore updaters, the default ones (map, datalayer, feature) are enough.

It also makes the codebase compatible with our eslint configuration.
2024-06-07 16:32:19 +02:00
7d623e83d0
chore(sync) make the test pass 2024-06-07 16:32:19 +02:00
e6f74b1960
chore(docker) remove ws.py for now 2024-06-07 16:32:18 +02:00
b421455c25
fix(sync) only send datalayer options 2024-06-07 16:32:18 +02:00
981d9939a3
fix(sync): do not call getSyncMetadata if it doesn't exist
This can arise when the form isn't bound to a "syncable" object. We
might want to provide an utility to check an object is *syncable*, or a
specific form to not attempt to sync objects which don't need it.
2024-06-07 16:32:18 +02:00
9e20c2ba52
feat(sync): Allow the sync of datalayer creation 2024-06-07 16:32:18 +02:00
bf60b03a55
fix(sync): allow features geometries to be synced
By defining the `geometry` property in the schema.
2024-06-07 16:32:18 +02:00
cf64ed285a
chore(docker): run the websocket server as a separate command 2024-06-07 16:32:17 +02:00
d43a80b274
chore(sync): remove useless dependencies from ws.py 2024-06-07 16:32:17 +02:00
9ae4c57279
feat(settings): allow reading socket-related settings from ENV variables 2024-06-07 16:32:17 +02:00
05147feb2e
fix(sync): intialize the sync engine before entering edit mode.
Otherwise `this.sync` is not defined.
2024-06-07 16:32:17 +02:00
ef99bf9d86
feat(sync): handle syncing of map limitbounds. 2024-06-07 16:32:17 +02:00
a278b67d5d
feat(sync): Avoid syncing remote datalayers' features
They will be synced on their own, and we dont want them to be present
twice on the map.
2024-06-07 16:32:16 +02:00
a3fb993c57
fix(sync): Initialize tilelayerand remoteData earlier.
It makes it possible to set these values on a remote peer.
2024-06-07 16:32:16 +02:00
2b4a7abeb9
fix(sync): Allow overlays to sync
`this.options.overlay` is now set during `map.initialize()`, which makes
it possible to be set by incoming websocket operations.
2024-06-07 16:32:16 +02:00
c5f0f7dc22
chore(sync): Ensure properties can be updated before doing it.
When receiving a message, this checks the given properties belong to
the "subject" before applying the message.
2024-06-07 16:32:16 +02:00
8d2d7e4a6f
chore(schema): Add a belongsTo field in the schema.
The goal is to use this as a security measure, to check that the
updated properties belong the the "subject" when receiving sync
operations.
2024-06-07 16:32:16 +02:00
90f89c523d
fix(sync): Allow cloning of features
Removing the `id` from the feature when cloning makes it generate a new
one. Without this change, the cloned feature keep the already existing
`id`, and during sync, the original object is lost (replaced by the
clone).

Nobody wants to be replaced by a clone.
2024-06-07 16:32:15 +02:00
aa3fa5ce98
feat(sync): Sync only when the edition of a feature is over.
It's less spectacular than sending the position as it changes, but takes
less bandwidth and seems good enough.
2024-06-07 16:32:15 +02:00