Mercurial > lbo > hg > geohub
changeset 59:373b6ad155ba
Add accuracy field and properly treat notes
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Fri, 04 Dec 2020 11:02:22 +0100 |
parents | f64f759b5b28 |
children | 5074024fc84d |
files | pgsql_schema.sql src/db.rs src/http.rs src/main.rs src/types.rs |
diffstat | 5 files changed, 43 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/pgsql_schema.sql Fri Dec 04 10:02:38 2020 +0100 +++ b/pgsql_schema.sql Fri Dec 04 11:02:22 2020 +0100 @@ -32,6 +32,7 @@ lat double precision, long double precision, spd double precision, + accuracy double precision, t timestamp with time zone not null, ele double precision secret bytea,
--- a/src/db.rs Fri Dec 04 10:02:38 2020 +0100 +++ b/src/db.rs Fri Dec 04 11:02:22 2020 +0100 @@ -21,14 +21,14 @@ ) -> Result<types::GeoJSON, postgres::Error> { let mut returnable = types::GeoJSON::new(); let stmt = self.0.prepare_cached( - r"SELECT id, t, lat, long, spd, ele, note FROM geohub.geodata + r"SELECT id, t, lat, long, spd, ele, note, accuracy FROM geohub.geodata WHERE (client = $1) and (t between $2 and $3) AND (secret = public.digest($4, 'sha256') or secret is null) AND (id > $5) ORDER BY t ASC LIMIT $6").unwrap(); // Must succeed. let rows = stmt.query(&[&name, &from_ts, &to_ts, &secret, &last.unwrap_or(0), &limit])?; returnable.reserve_features(rows.len()); for row in rows.iter() { - let (id, ts, lat, long, spd, ele, note) = ( + let (id, ts, lat, long, spd, ele, note, acc) = ( row.get(0), row.get(1), row.get(2), @@ -36,12 +36,14 @@ row.get(4), row.get(5), row.get(6), + row.get(7), ); let point = types::GeoPoint { lat: lat, long: long, spd: spd, ele: ele, + accuracy: acc, note: note, time: ts, }; @@ -56,7 +58,9 @@ secret: &Option<String>, point: &types::GeoPoint, ) -> Result<(), postgres::Error> { - let stmt = self.0.prepare_cached("INSERT INTO geohub.geodata (client, lat, long, spd, t, ele, secret, note) VALUES ($1, $2, $3, $4, $5, $6, public.digest($7, 'sha256'), $8)").unwrap(); + let stmt = self.0.prepare_cached( + r"INSERT INTO geohub.geodata (client, lat, long, spd, t, ele, secret, note, accuracy) + VALUES ($1, $2, $3, $4, $5, $6, public.digest($7, 'sha256'), $8, $9)").unwrap(); let channel = format!( "NOTIFY {}, '{}'", ids::channel_name(name, secret.as_ref().unwrap_or(&"".into()).as_str()), @@ -72,6 +76,7 @@ &point.ele, &secret, &point.note, + &point.accuracy, ]) .unwrap(); notify.execute(&[]).unwrap(); @@ -88,7 +93,7 @@ ) -> Option<(types::GeoJSON, i32)> { let mut returnable = types::GeoJSON::new(); let check_for_new = self.0.prepare_cached( - r"SELECT id, t, lat, long, spd, ele, note FROM geohub.geodata + r"SELECT id, t, lat, long, spd, ele, note, accuracy FROM geohub.geodata WHERE (client = $1) and (id > $2) AND (secret = public.digest($3, 'sha256') or secret is null) ORDER BY id DESC LIMIT $4").unwrap(); // Must succeed. @@ -104,7 +109,7 @@ let mut last = 0; for row in rows.iter() { - let (id, ts, lat, long, spd, ele, note) = ( + let (id, ts, lat, long, spd, ele, note, acc) = ( row.get(0), row.get(1), row.get(2), @@ -112,6 +117,7 @@ row.get(4), row.get(5), row.get(6), + row.get(7), ); let point = types::GeoPoint { time: ts, @@ -120,6 +126,7 @@ spd: spd, ele: ele, note: note, + accuracy: acc, }; returnable.push_feature(types::geofeature_from_point(Some(id), point)); if id > last {
--- a/src/http.rs Fri Dec 04 10:02:38 2020 +0100 +++ b/src/http.rs Fri Dec 04 11:02:22 2020 +0100 @@ -1,5 +1,7 @@ use rocket::response::Responder; +use std::io::Read; + #[derive(Responder)] pub enum GeoHubResponse { #[response(status = 200, content_type = "json")] @@ -26,3 +28,13 @@ pub fn server_error(msg: String) -> GeoHubResponse { GeoHubResponse::ServerError(msg) } + +pub fn read_data(d: rocket::Data, limit: u64) -> Result<String, GeoHubResponse> { + let mut ds = d.open().take(limit); + let mut dest = Vec::with_capacity(limit as usize); + if let Err(e) = std::io::copy(&mut ds, &mut dest) { + return Err(GeoHubResponse::BadRequest(format!("Error reading request: {}", e))); + } + + String::from_utf8(dest).map_err(|e| GeoHubResponse::BadRequest(format!("Decoding error: {}", e))) +}
--- a/src/main.rs Fri Dec 04 10:02:38 2020 +0100 +++ b/src/main.rs Fri Dec 04 11:02:22 2020 +0100 @@ -122,7 +122,7 @@ /// time is like 2020-11-30T20:12:36.444Z (ISO 8601). By default, server time is set. /// secret can be used to protect points. #[rocket::post( - "/geo/<name>/log?<lat>&<longitude>&<time>&<s>&<ele>&<secret>", + "/geo/<name>/log?<lat>&<longitude>&<time>&<s>&<ele>&<secret>&<accuracy>", data = "<note>" )] fn log( @@ -134,7 +134,8 @@ time: Option<String>, s: Option<f64>, ele: Option<f64>, - note: Option<String>, + accuracy: Option<f64>, + note: rocket::data::Data, ) -> http::GeoHubResponse { let db = db::DBQuery(&db.0); // Check that secret and client name are legal. @@ -144,28 +145,6 @@ .into(), ); } - // Length-limit notes. - if let Some(note) = note.as_ref() { - if note.len() > 4096 { - return http::bad_request("A note attached to a point may not be longer than 4 KiB.".into()); - } - } - - let mut ts = chrono::Utc::now(); - if let Some(time) = time { - ts = util::flexible_timestamp_parse(time).unwrap_or(ts); - } - - // Only store a note if one was attached. - let note = if let Some(note) = note { - if note.is_empty() { - None - } else { - Some(note) - } - } else { - note - }; let secret = if let Some(secret) = secret { if secret.is_empty() { None @@ -176,12 +155,24 @@ secret }; + let mut ts = chrono::Utc::now(); + if let Some(time) = time { + ts = util::flexible_timestamp_parse(time).unwrap_or(ts); + } + + // Length-limit notes. + let note = match http::read_data(note, 4096) { + Ok(n) => { if n.is_empty() { None } else { Some(n) } }, + Err(e) => return e, + }; + let point = types::GeoPoint { lat: lat, long: longitude, time: ts, spd: s, ele: ele, + accuracy: accuracy, note: note, }; if let Err(e) = db.log_geopoint(name.as_str(), &secret, &point) {
--- a/src/types.rs Fri Dec 04 10:02:38 2020 +0100 +++ b/src/types.rs Fri Dec 04 11:02:22 2020 +0100 @@ -5,6 +5,7 @@ pub long: f64, pub spd: Option<f64>, pub ele: Option<f64>, + pub accuracy: Option<f64>, pub time: chrono::DateTime<chrono::Utc>, pub note: Option<String>, } @@ -36,6 +37,7 @@ time: chrono::DateTime<chrono::Utc>, altitude: Option<f64>, speed: Option<f64>, + accuracy: Option<f64>, /// The unique ID of the point. id: Option<i32>, /// An arbitrary note attached by the logging client. @@ -88,6 +90,7 @@ altitude: point.ele, speed: point.spd, note: point.note, + accuracy: point.accuracy, }, geometry: GeoGeometry { typ: "Point".into(),