diff --git a/server/.sqlx/query-12fcf6d9b61300d488f1f0099e0f4f2e40f4a123327f912324435bd9ba8481c1.json b/server/.sqlx/query-12fcf6d9b61300d488f1f0099e0f4f2e40f4a123327f912324435bd9ba8481c1.json new file mode 100644 index 000000000..fd778cb56 --- /dev/null +++ b/server/.sqlx/query-12fcf6d9b61300d488f1f0099e0f4f2e40f4a123327f912324435bd9ba8481c1.json @@ -0,0 +1,32 @@ +{ + "db_name": "SQLite", + "query": "SELECT DISTINCT key,visible_id,type FROM aliases WHERE alias = ?", + "describe": { + "columns": [ + { + "name": "key", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "visible_id", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "type", + "ordinal": 2, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "12fcf6d9b61300d488f1f0099e0f4f2e40f4a123327f912324435bd9ba8481c1" +} diff --git a/server/.sqlx/query-1dd631d6d3f59f92d7a45f9599fe945c0d4355576c2675f7694f4fdc3b8b55a0.json b/server/.sqlx/query-1dd631d6d3f59f92d7a45f9599fe945c0d4355576c2675f7694f4fdc3b8b55a0.json new file mode 100644 index 000000000..649ed8ca5 --- /dev/null +++ b/server/.sqlx/query-1dd631d6d3f59f92d7a45f9599fe945c0d4355576c2675f7694f4fdc3b8b55a0.json @@ -0,0 +1,62 @@ +{ + "db_name": "SQLite", + "query": "SELECT key,name,tumonline_room_nr,type,type_common_name,lat,lon,data FROM en WHERE key = ?", + "describe": { + "columns": [ + { + "name": "key", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "tumonline_room_nr", + "ordinal": 2, + "type_info": "Int64" + }, + { + "name": "type", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "type_common_name", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "lat", + "ordinal": 5, + "type_info": "Float" + }, + { + "name": "lon", + "ordinal": 6, + "type_info": "Float" + }, + { + "name": "data", + "ordinal": 7, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + true, + false, + false, + false, + false, + false + ] + }, + "hash": "1dd631d6d3f59f92d7a45f9599fe945c0d4355576c2675f7694f4fdc3b8b55a0" +} diff --git a/server/.sqlx/query-9c731c313e4a8940a38ce04a0fe6a1c1a154b3dc74ee459e865623085638aadf.json b/server/.sqlx/query-9c731c313e4a8940a38ce04a0fe6a1c1a154b3dc74ee459e865623085638aadf.json new file mode 100644 index 000000000..93c1f3516 --- /dev/null +++ b/server/.sqlx/query-9c731c313e4a8940a38ce04a0fe6a1c1a154b3dc74ee459e865623085638aadf.json @@ -0,0 +1,62 @@ +{ + "db_name": "SQLite", + "query": "SELECT key,name,tumonline_room_nr,type,type_common_name,lat,lon,data FROM de WHERE key = ?", + "describe": { + "columns": [ + { + "name": "key", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "tumonline_room_nr", + "ordinal": 2, + "type_info": "Int64" + }, + { + "name": "type", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "type_common_name", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "lat", + "ordinal": 5, + "type_info": "Float" + }, + { + "name": "lon", + "ordinal": 6, + "type_info": "Float" + }, + { + "name": "data", + "ordinal": 7, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + true, + false, + false, + false, + false, + false + ] + }, + "hash": "9c731c313e4a8940a38ce04a0fe6a1c1a154b3dc74ee459e865623085638aadf" +} diff --git a/server/.sqlx/query-ca4c11b14efa6564387df4dbc475539734b181798e2dba867f40bc460c7b9a3a.json b/server/.sqlx/query-ca4c11b14efa6564387df4dbc475539734b181798e2dba867f40bc460c7b9a3a.json new file mode 100644 index 000000000..13d4ee508 --- /dev/null +++ b/server/.sqlx/query-ca4c11b14efa6564387df4dbc475539734b181798e2dba867f40bc460c7b9a3a.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT data FROM en WHERE key = ?", + "describe": { + "columns": [ + { + "name": "data", + "ordinal": 0, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false + ] + }, + "hash": "ca4c11b14efa6564387df4dbc475539734b181798e2dba867f40bc460c7b9a3a" +} diff --git a/server/.sqlx/query-fe271671edc17aafa97e4da7ea8d7097d4186c3eb97649a45abc378fc8a2a83b.json b/server/.sqlx/query-fe271671edc17aafa97e4da7ea8d7097d4186c3eb97649a45abc378fc8a2a83b.json new file mode 100644 index 000000000..3809e3cac --- /dev/null +++ b/server/.sqlx/query-fe271671edc17aafa97e4da7ea8d7097d4186c3eb97649a45abc378fc8a2a83b.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT data FROM de WHERE key = ?", + "describe": { + "columns": [ + { + "name": "data", + "ordinal": 0, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false + ] + }, + "hash": "fe271671edc17aafa97e4da7ea8d7097d4186c3eb97649a45abc378fc8a2a83b" +} diff --git a/server/Cargo.lock b/server/Cargo.lock index fc747ac07..f4ba02293 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -861,9 +861,7 @@ dependencies = [ "chrono", "diesel_derives", "itoa", - "libsqlite3-sys", "pq-sys", - "time", ] [[package]] @@ -2120,7 +2118,6 @@ dependencies = [ "actix-web", "actix-web-prom", "cached", - "diesel", "env_logger", "futures", "image", diff --git a/server/main-api/Cargo.toml b/server/main-api/Cargo.toml index 9a14424fe..e97c840c1 100644 --- a/server/main-api/Cargo.toml +++ b/server/main-api/Cargo.toml @@ -33,7 +33,6 @@ unicode-truncate = "0.2.0" serde_yaml = "0.9" # database -diesel = { version = "2.1.1", features = ["default", "sqlite"] } libsqlite3-sys = { version = "*", features = ["bundled"] } sqlx = { version = "0.7.1", features = ["sqlite", "runtime-tokio", "migrate", "macros"] } diff --git a/server/main-api/diesel.toml b/server/main-api/diesel.toml deleted file mode 100644 index 35a12ff0d..000000000 --- a/server/main-api/diesel.toml +++ /dev/null @@ -1,8 +0,0 @@ -# For documentation on how to configure this file, -# see https://diesel.rs/guides/configuring-diesel-cli - -[print_schema] -file = "src/schema.rs" - -[migrations_directory] -dir = "migrations" diff --git a/server/main-api/src/entries/get.rs b/server/main-api/src/entries/get.rs index 3c843996e..680d99001 100644 --- a/server/main-api/src/entries/get.rs +++ b/server/main-api/src/entries/get.rs @@ -1,40 +1,43 @@ -use crate::models::DBRoomKeyAlias; -use crate::utils; +use crate::{utils, AppState}; use actix_web::{get, web, HttpResponse}; -use diesel::prelude::*; use log::error; +use sqlx::SqlitePool; + +#[derive(Debug, Clone)] +pub struct DBRoomKeyAlias { + pub key: String, + pub visible_id: String, + pub r#type: String, +} #[get("/api/get/{id}")] pub async fn get_handler( params: web::Path, web::Query(args): web::Query, + data: web::Data, ) -> HttpResponse { - let conn = &mut utils::establish_connection(); - let (probable_id, redirect_url) = match get_alias_and_redirect(conn, ¶ms.into_inner()) { - Some(alias_and_redirect) => alias_and_redirect, - None => return HttpResponse::NotFound().body("Not found"), - }; + let (probable_id, redirect_url) = + match get_alias_and_redirect(&data.db, ¶ms.into_inner()).await { + Some(alias_and_redirect) => alias_and_redirect, + None => return HttpResponse::NotFound().body("Not found"), + }; let result = match args.should_use_english() { true => { - use crate::schema::en::dsl; - dsl::en - .filter(dsl::key.eq(&probable_id)) - .select(dsl::data) - .load::(conn) + sqlx::query_scalar!("SELECT data FROM en WHERE key = ?", probable_id) + .fetch_optional(&data.db) + .await } false => { - use crate::schema::de::dsl; - dsl::de - .filter(dsl::key.eq(&probable_id)) - .select(dsl::data) - .load::(conn) + sqlx::query_scalar!("SELECT data FROM de WHERE key = ?", probable_id) + .fetch_optional(&data.db) + .await } }; match result { - Ok(d) => match d.len() { - 0 => HttpResponse::NotFound().body("Not found"), - _ => { - let mut response_json = d[0].clone(); + Ok(d) => match d { + None => HttpResponse::NotFound().body("Not found"), + Some(s) => { + let mut response_json = s.clone(); // We don not want to serialise this data at any point in the server. // This just flows through the server, but adding redirect_url to the response is necessary response_json.pop(); // remove last } @@ -53,18 +56,19 @@ pub async fn get_handler( } } -fn get_alias_and_redirect(conn: &mut SqliteConnection, query: &str) -> Option<(String, String)> { - use crate::schema::aliases::dsl::{alias, aliases, key, type_, visible_id}; - let result = aliases - .filter(alias.eq(query).or(key.eq(query))) - .select((key, visible_id, type_)) - .distinct() - .load::(conn); +async fn get_alias_and_redirect(conn: &SqlitePool, query: &str) -> Option<(String, String)> { + let result = sqlx::query_as!( + DBRoomKeyAlias, + "SELECT DISTINCT key,visible_id,type FROM aliases WHERE alias = ?", + query + ) + .fetch_all(conn) + .await; match result { Ok(d) => { let redirect_url = match d.len() { 0 => return None, // not key or alias - 1 => extract_redirect_exact_match(&d[0].type_, &d[0].visible_id), + 1 => extract_redirect_exact_match(&d[0].r#type, &d[0].visible_id), _ => { let keys = d .clone() diff --git a/server/main-api/src/main.rs b/server/main-api/src/main.rs index b6948f257..bb1a99950 100644 --- a/server/main-api/src/main.rs +++ b/server/main-api/src/main.rs @@ -3,17 +3,21 @@ use actix_web::{get, middleware, web, App, HttpResponse, HttpServer}; use actix_web_prom::PrometheusMetricsBuilder; use futures::try_join; use log::info; +use sqlx::sqlite::SqlitePoolOptions; +use sqlx::SqlitePool; use std::collections::HashMap; mod entries; mod maps; mod models; -mod schema; mod search; mod setup; mod utils; const MAX_JSON_PAYLOAD: usize = 1024 * 1024; // 1 MB +pub struct AppState { + db: SqlitePool, +} #[get("/api/status")] async fn health_status_handler() -> HttpResponse { @@ -47,6 +51,10 @@ async fn main() -> Result<(), Box> { .build() .unwrap(); + let uri = std::env::var("DB_LOCATION").unwrap_or_else(|_| "api_data.db".to_string()); + let uri = format!("{uri}?mode=ro"); + let pool = SqlitePoolOptions::new().connect(&uri).await?; + HttpServer::new(move || { let cors = Cors::default() .allow_any_origin() @@ -59,6 +67,7 @@ async fn main() -> Result<(), Box> { .wrap(cors) .wrap(middleware::Logger::default().exclude("/api/status")) .wrap(middleware::Compress::default()) + .app_data(web::Data::new(pool.clone())) .app_data(web::JsonConfig::default().limit(MAX_JSON_PAYLOAD)) .service(health_status_handler) .service(web::scope("/api/preview").configure(maps::configure)) diff --git a/server/main-api/src/maps/mod.rs b/server/main-api/src/maps/mod.rs index 2ad8ec425..3682eb2ab 100644 --- a/server/main-api/src/maps/mod.rs +++ b/server/main-api/src/maps/mod.rs @@ -8,16 +8,14 @@ use crate::models::DBRoomEntry; use actix_web::{get, web, HttpResponse}; use cached::proc_macro::cached; use cached::SizedCache; -use diesel::prelude::*; use image::Rgba; use std::io::Cursor; use log::{debug, error, warn}; - use tokio::time::Instant; use unicode_truncate::UnicodeTruncateStr; -use crate::utils; +use crate::{utils, AppState}; pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(maps_handler); @@ -27,33 +25,6 @@ pub fn configure(cfg: &mut web::ServiceConfig) { } } -fn get_localised_data(id: &str, should_use_english: bool) -> Result { - let conn = &mut utils::establish_connection(); - - let result = if should_use_english { - use crate::schema::en::dsl; - dsl::en.filter(dsl::key.eq(&id)).load::(conn) - } else { - use crate::schema::de::dsl; - dsl::de.filter(dsl::key.eq(&id)).load::(conn) - }; - - match result { - Ok(r) => match r.len() { - 0 => Err(HttpResponse::NotFound() - .content_type("text/plain") - .body("Not found")), - _ => Ok(r[0].clone()), - }, - Err(e) => { - error!("Error preparing statement: {e:?}"); - return Err(HttpResponse::InternalServerError() - .content_type("text/plain") - .body("Internal Server Error")); - } - } -} - // type and create are specified, because a custom conversion is needed // size=1 is about 3Mi #[cached( @@ -124,13 +95,28 @@ fn load_default_image() -> Vec { pub async fn maps_handler( params: web::Path, web::Query(args): web::Query, + data: web::Data, ) -> HttpResponse { let start_time = Instant::now(); let id = params.into_inner(); - let data = match get_localised_data(&id, args.should_use_english()) { - Ok(data) => data, + let result = if args.should_use_english() { + sqlx::query_as!(DBRoomEntry,"SELECT key,name,tumonline_room_nr,type,type_common_name,lat,lon,data FROM en WHERE key = ?", id).fetch_optional(&data.db).await + } else { + sqlx::query_as!(DBRoomEntry,"SELECT key,name,tumonline_room_nr,type,type_common_name,lat,lon,data FROM de WHERE key = ?", id).fetch_optional(&data.db).await + }; + + let data = match result { + Ok(Some(d)) => d.clone(), + Ok(None) => { + return HttpResponse::NotFound() + .content_type("text/plain") + .body("Not found") + } Err(e) => { - return e; + error!("Error getting {e:?}"); + return HttpResponse::InternalServerError() + .content_type("text/plain") + .body("Internal Server Error"); } }; let img = construct_image_from_data(&id, data) diff --git a/server/main-api/src/maps/overlay_map.rs b/server/main-api/src/maps/overlay_map.rs index 84f49e3b1..3cd08f06c 100644 --- a/server/main-api/src/maps/overlay_map.rs +++ b/server/main-api/src/maps/overlay_map.rs @@ -4,14 +4,14 @@ use futures::{stream::FuturesUnordered, StreamExt}; use log::warn; pub(crate) struct OverlayMapTask { - pub(crate) x: f32, - pub(crate) y: f32, + pub(crate) x: f64, + pub(crate) y: f64, pub(crate) z: u32, } impl OverlayMapTask { pub fn with(entry: &DBRoomEntry) -> Self { - let zoom = match entry.type_.as_str() { + let zoom = match entry.r#type.as_str() { "campus" => 14, "area" | "site" => 15, "building" | "joined_building" => 16, @@ -77,11 +77,11 @@ impl OverlayMapTask { } } -fn lat_lon_z_to_xyz(lat_deg: f32, lon_deg: f32, zoom: u32) -> (f32, f32, u32) { +fn lat_lon_z_to_xyz(lat_deg: f64, lon_deg: f64, zoom: u32) -> (f64, f64, u32) { let lat_rad = lat_deg.to_radians(); - let n = 2_u32.pow(zoom) as f32; + let n = 2_u64.pow(zoom) as f64; let xtile = (lon_deg + 180.0) / 360.0 * n; - let ytile = (1.0 - lat_rad.tan().asinh() / std::f32::consts::PI) / 2.0 * n; + let ytile = (1.0 - lat_rad.tan().asinh() / std::f64::consts::PI) / 2.0 * n; (xtile, ytile, zoom) } @@ -109,16 +109,16 @@ mod overlay_tests { #[test] fn test_lat_lon_z_to_xyz() { let (x, y, _) = lat_lon_z_to_xyz(52.520_008, 13.404_954, 17); - assert_eq!(x, 70416.59_f32); - assert_eq!(y, 42985.734_f32); + assert_eq!(x, 70416.59_f64); + assert_eq!(y, 42985.734_f64); } #[test] fn test_lat_lon_no_zoom_mut() { for x in -5..5 { - let x = x as f32; + let x = x as f64; for y in -5..5 { - let y = y as f32; + let y = y as f64; for z in 0..20 { let (_, _, zg) = lat_lon_z_to_xyz(x + y / 100.0, y, z); assert_eq!(z, zg); diff --git a/server/main-api/src/models.rs b/server/main-api/src/models.rs index 780967e4e..8f1029f17 100644 --- a/server/main-api/src/models.rs +++ b/server/main-api/src/models.rs @@ -1,20 +1,11 @@ -use diesel::prelude::*; - -#[derive(Queryable, Debug, Clone)] +#[derive(Debug, Clone)] pub struct DBRoomEntry { pub key: String, pub name: String, - pub tumonline_room_nr: Option, - pub type_: String, + pub tumonline_room_nr: Option, + pub r#type: String, pub type_common_name: String, - pub lat: f32, - pub lon: f32, + pub lat: f64, + pub lon: f64, pub data: String, } - -#[derive(Queryable, Debug, Clone)] -pub struct DBRoomKeyAlias { - pub key: String, - pub visible_id: String, - pub type_: String, -} diff --git a/server/main-api/src/schema.rs b/server/main-api/src/schema.rs deleted file mode 100644 index 479c54543..000000000 --- a/server/main-api/src/schema.rs +++ /dev/null @@ -1,42 +0,0 @@ -// @generated automatically by Diesel CLI. - -diesel::table! { - aliases (id) { - id -> Integer, - alias -> Text, - key -> Text, - visible_id -> Text, - #[sql_name = "type"] - type_ -> Text, - } -} - -diesel::table! { - de (key) { - key -> Text, - name -> Text, - tumonline_room_nr -> Nullable, - #[sql_name = "type"] - type_ -> Text, - type_common_name -> Text, - lat -> Float, - lon -> Float, - data -> Text, - } -} - -diesel::table! { - en (key) { - key -> Text, - name -> Text, - tumonline_room_nr -> Nullable, - #[sql_name = "type"] - type_ -> Text, - type_common_name -> Text, - lat -> Float, - lon -> Float, - data -> Text, - } -} - -diesel::allow_tables_to_appear_in_same_query!(aliases, de, en,); diff --git a/server/main-api/src/utils.rs b/server/main-api/src/utils.rs index fabada3e7..98219e562 100644 --- a/server/main-api/src/utils.rs +++ b/server/main-api/src/utils.rs @@ -1,4 +1,3 @@ -use diesel::{Connection, SqliteConnection}; use serde::Deserialize; #[derive(Deserialize)] @@ -11,8 +10,3 @@ impl LangQueryArgs { self.lang.as_ref().map_or(false, |c| c == "en") } } - -pub fn establish_connection() -> SqliteConnection { - let database_loc = std::env::var("DB_LOCATION").unwrap_or_else(|_| "api_data.db".to_string()); - SqliteConnection::establish(&database_loc).expect("Cannot open database") -}