changeset 4:5a0ac0fe8fb6

Implement robust timestamp parsing
author Lewin Bormann <lbo@spheniscida.de>
date Tue, 01 Dec 2020 20:03:31 +0100
parents 3586f77a0142
children b879b0124a07
files TODO src/main.rs
diffstat 2 files changed, 43 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/TODO	Tue Dec 01 19:07:32 2020 +0100
+++ b/TODO	Tue Dec 01 20:03:31 2020 +0100
@@ -1,6 +1,3 @@
-* move table into schema
-* use ids for geo records
-* ids only alphanumeric
 * notify via dynamic channels? static channels? polling?
 * deploy first version
 
--- a/src/main.rs	Tue Dec 01 19:07:32 2020 +0100
+++ b/src/main.rs	Tue Dec 01 20:03:31 2020 +0100
@@ -8,20 +8,54 @@
 #[rocket_contrib::database("geohub")]
 struct DBConn(postgres::Connection);
 
+/// Parse timestamps flexibly. Without any zone information, UTC is assumed.
+fn flexible_timestamp_parse(ts: String) -> Option<chrono::DateTime<chrono::Utc>> {
+    let fmtstrings = &[
+        "%Y-%m-%dT%H:%M:%S%.f%:z",
+        "%Y-%m-%dT%H:%M:%S%.fZ",
+        "%Y-%m-%d %H:%M:%S%.f",
+    ];
+    for fs in fmtstrings {
+        println!("{} {}", fs, ts);
+        let (naive, withtz) = (
+            chrono::NaiveDateTime::parse_from_str(ts.as_str(), fs).ok(),
+            chrono::DateTime::parse_from_str(ts.as_str(), fs).ok(),
+        );
+        if let Some(p) = withtz {
+            println!("tz: {:?}", p);
+            return Some(p.with_timezone(&chrono::Utc));
+        }
+        if let Some(p) = naive {
+            println!("naive: {:?}", p);
+            let utcd = chrono::Utc.from_utc_datetime(&p);
+            return Some(utcd);
+        }
+    }
+    None
+}
+
 /// lat, long are floats
 /// time is like 2020-11-30T20:12:36.444Z (ISO 8601)
-#[rocket::get("/geo/<name>/log?<lat>&<longitude>&<time>&<s>")]
-fn hello(db: DBConn, name: String, lat: f64, longitude: f64, time: String, s: f64) -> &'static str {
-    let ts = chrono::NaiveDateTime::parse_from_str(time.as_str(), "%Y-%m-%dT%H:%M:%S%.fZ")
-        .ok()
-        .map(|t| chrono::Utc::now().timezone().from_utc_datetime(&t));
-    println!("{:?}", ts);
+#[rocket::get("/geo/<name>/log?<lat>&<longitude>&<time>&<s>&<ele>")]
+fn hello(
+    db: DBConn,
+    name: String,
+    lat: f64,
+    longitude: f64,
+    time: String,
+    s: f64,
+    ele: Option<f64>,
+) -> rocket::http::Status {
+    if name.chars().any(|c| !c.is_alphanumeric()) {
+        return rocket::http::Status::NotAcceptable;
+    }
+    let ts = flexible_timestamp_parse(time);
     db.0.execute(
-        "INSERT INTO geohub.geodata (id, lat, long, spd, t) VALUES ($1, $2, $3, $4, $5)",
-        &[&name, &lat, &longitude, &s, &ts],
+        "INSERT INTO geohub.geodata (id, lat, long, spd, t, ele) VALUES ($1, $2, $3, $4, $5, $6)",
+        &[&name, &lat, &longitude, &s, &ts, &ele],
     )
     .unwrap();
-    "OK"
+    rocket::http::Status::Ok
 }
 
 fn main() {