changeset 74:ebbecfa4231f

Refine behavior of livemap UI
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 05 Dec 2020 11:43:38 +0100
parents e22189546e10
children afefa4d60653
files README.md assets/livemap.html assets/trackme.html src/main.rs src/notifier.rs src/types.rs
diffstat 6 files changed, 69 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/README.md	Sat Dec 05 10:58:26 2020 +0100
+++ b/README.md	Sat Dec 05 11:43:38 2020 +0100
@@ -152,10 +152,9 @@
 GeoHub with nothing more than Ajax and some third-party libraries.
 
 This also allows you to immediately use the `livemap` app at
-`https://yourhost.com/geo/assets/livemap.html?client=<yourclient>&secret=verysecret`,
-which consists of a single HTML page, a CSS file, and the leaflet.js library
-(which is included). - latter is (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011
-CloudMade.
+`https://yourhost.com/geo/assets/livemap.html`, which consists of a single HTML
+page, a CSS file, and the leaflet.js library (which is included). - latter is
+(c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade.
 
 ## Ingestion
 
--- a/assets/livemap.html	Sat Dec 05 10:58:26 2020 +0100
+++ b/assets/livemap.html	Sat Dec 05 11:43:38 2020 +0100
@@ -59,6 +59,27 @@
         }
         return userSecret ? userSecret : '';
     }
+    function updateURL(client, secret) {
+        var url = window.location.toString();
+
+        if (url.search('\\?') < 0) {
+            url += '?';
+        }
+
+        if (url.search('secret=') > 0) {
+            url = url.replace(/secret=[a-zA-Z0-9]*/, `secret=${secret}`);
+        } else {
+            url += `&secret=${secret}`;
+        }
+
+        if (url.search('client=') > 0) {
+            url = url.replace(/client=[a-zA-Z0-9]*/, `client=${client}`);
+        } else {
+            url += `&client=${client}`;
+        }
+
+        window.history.pushState({}, "", url);
+    }
 
     // Set the current location, called on every new point. Updates the marker and adds
     // a new point (former position).
@@ -84,7 +105,12 @@
         console.log('xhrcallback called.', xhr.readyState, xhr.status);
         if (xhr.readyState === XMLHttpRequest.DONE && xhr.status == 200) {
             const response = xhr.response;
-            if (response['geo']) {
+            console.log("Client update for", response.client);
+            if (response.client != getClient()) {
+                console.log("Received outdated client update.");
+                return;
+            }
+            if (response.client == getClient() && response['geo']) {
                 const features = response['geo']['features'];
                 const lastfeature = features[0];
                 console.log(`xhrcallback: ${features.length} elements received.`);
@@ -109,13 +135,15 @@
 
             // Install next XHR.
             waitforupdate();
+        } else {
+            return;
         }
     };
 
 
     // Fetch the most recent point for this client and display them.
     function backfill(args) {
-        xhr = new XMLHttpRequest();
+        var xhr = new XMLHttpRequest();
         var client = getClient();
         var secret = getSecret();
         if (!client) {
@@ -132,7 +160,7 @@
     // Ask for updates. This request will hang until timeout is reached or
     // an update arrives.
     function waitforupdate() {
-        xhr = new XMLHttpRequest();
+        var xhr = new XMLHttpRequest();
         var client = getClient();
         var secret = getSecret();
         if (!client) {
@@ -150,6 +178,7 @@
     // "Go!" was clicked - clear markers and fetch data for new source.
     function buttonGoClicked() {
         clearAllMarkers();
+        updateURL(getClient(), getSecret());
         // Accelerate display.
         backfill();
     }
--- a/assets/trackme.html	Sat Dec 05 10:58:26 2020 +0100
+++ b/assets/trackme.html	Sat Dec 05 11:43:38 2020 +0100
@@ -84,6 +84,28 @@
         }
         return userSecret;
     }
+    // Update URL from client/secret.
+    function updateURL(client, secret) {
+        var url = window.location.toString();
+        
+        if (url.search('\\?') < 0) {
+            url += '?';
+        }
+
+        if (url.search('secret=') > 0) {
+            url = url.replace(/secret=[a-zA-Z0-9]*/, `secret=${secret}`);
+        } else {
+            url += `&secret=${secret}`;
+        }
+
+        if (url.search('client=') > 0) {
+            url = url.replace(/client=[a-zA-Z0-9]*/, `client=${client}`);
+        } else {
+            url += `&client=${client}`;
+        }
+
+        window.history.pushState({}, "", url);
+    }
     // Update the link to the livemap if the user has changed client/secret.
     function updateLiveMap() {
         var secret = getSecret();
@@ -193,6 +215,7 @@
             inputSecret.disabled = false;
         };
         updateLiveMap();
+        updateURL();
     }
 
     // Pre-fill client/secret.
--- a/src/main.rs	Sat Dec 05 10:58:26 2020 +0100
+++ b/src/main.rs	Sat Dec 05 11:43:38 2020 +0100
@@ -15,10 +15,10 @@
 /// Almost like retrieve/json, but sorts in descending order, doesn't work with intervals (only
 /// limit), and returns a LiveUpdate.
 /// Used for backfilling recent points in the UI.
-#[rocket::get("/geo/<name>/retrieve/last?<secret>&<last>&<limit>")]
+#[rocket::get("/geo/<client>/retrieve/last?<secret>&<last>&<limit>")]
 fn retrieve_last(
     db: db::DBConn,
-    name: String,
+    client: String,
     secret: Option<String>,
     last: Option<i32>,
     limit: Option<i64>,
@@ -33,10 +33,11 @@
         secret
     };
     let db = db::DBQuery(&db.0);
-    if let Some((geojson, newlast)) = db.check_for_new_rows(&name, &secret, &last, &limit) {
-        rocket_contrib::json::Json(types::LiveUpdate::new(Some(newlast), Some(geojson), None))
+    if let Some((geojson, newlast)) = db.check_for_new_rows(&client, &secret, &last, &limit) {
+        rocket_contrib::json::Json(types::LiveUpdate::new(client, Some(newlast), Some(geojson), None))
     } else {
         rocket_contrib::json::Json(types::LiveUpdate::new(
+                client,
             last,
             None,
             Some("No rows returned".into()),
--- a/src/notifier.rs	Sat Dec 05 10:58:26 2020 +0100
+++ b/src/notifier.rs	Sat Dec 05 11:43:38 2020 +0100
@@ -75,16 +75,16 @@
         };
 
         let req = NotifyRequest {
-            client: client,
+            client: client.clone(),
             secret: secret,
             respond: send,
         };
         self.0.send(req).unwrap();
 
         if let Ok(response) = recv.recv_timeout(time::Duration::new(timeout.unwrap_or(30), 0)) {
-            types::LiveUpdate::new(response.last, response.geo, None)
+            types::LiveUpdate::new(client, response.last, response.geo, None)
         } else {
-            types::LiveUpdate::new(None, None, Some("timeout, try again".into()))
+            types::LiveUpdate::new(client, None, None, Some("timeout, try again".into()))
         }
     }
 
--- a/src/types.rs	Sat Dec 05 10:58:26 2020 +0100
+++ b/src/types.rs	Sat Dec 05 11:43:38 2020 +0100
@@ -14,15 +14,17 @@
 pub struct LiveUpdate {
     #[serde(rename = "type")]
     typ: String, // always "GeoHubUpdate"
+    client: String,
     last: Option<i32>,
     geo: Option<GeoJSON>,
     error: Option<String>,
 }
 
 impl LiveUpdate {
-    pub fn new(last: Option<i32>, geo: Option<GeoJSON>, err: Option<String>) -> LiveUpdate {
+    pub fn new(client: String, last: Option<i32>, geo: Option<GeoJSON>, err: Option<String>) -> LiveUpdate {
         LiveUpdate {
             typ: "GeoHubUpdate".into(),
+            client: client,
             last: last,
             geo: geo,
             error: err,