This commit is contained in:
2025-11-26 11:57:23 +01:00
parent 80bdaef5c8
commit 696d058fed
10 changed files with 754 additions and 185 deletions

View File

@@ -48,6 +48,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.route("/api/tiles/:z/:x/:y/buildings", get(get_tile_buildings))
.route("/api/tiles/:z/:x/:y/landuse", get(get_tile_landuse))
.route("/api/tiles/:z/:x/:y/water", get(get_tile_water))
.route("/api/tiles/:z/:x/:y/railways", get(get_tile_railways))
.nest_service("/", ServeDir::new("static"))
.layer(CorsLayer::permissive())
.with_state(state);
@@ -74,17 +75,22 @@ struct MapNode {
async fn get_tile(
Path((z, x, y)): Path<(i32, i32, i32)>,
State(state): State<Arc<AppState>>,
) -> Json<Vec<MapNode>> {
) -> Result<Json<Vec<MapNode>>, (axum::http::StatusCode, String)> {
let query = "SELECT id, lat, lon, tags FROM map_data.nodes WHERE zoom = ? AND tile_x = ? AND tile_y = ?";
let rows = state.scylla_session.query(query, (z, x, y)).await.unwrap().rows.unwrap_or_default();
let rows = state.scylla_session.query(query, (z, x, y))
.await
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Database error: {}", e)))?
.rows
.unwrap_or_default();
let mut nodes = Vec::new();
for row in rows {
let (id, lat, lon, tags) = row.into_typed::<(i64, f64, f64, std::collections::HashMap<String, String>)>().unwrap();
let (id, lat, lon, tags) = row.into_typed::<(i64, f64, f64, std::collections::HashMap<String, String>)>()
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Serialization error: {}", e)))?;
nodes.push(MapNode { id, lat, lon, tags });
}
Json(nodes)
Ok(Json(nodes))
}
#[derive(Serialize)]
@@ -97,13 +103,18 @@ struct MapWay {
async fn get_tile_ways(
Path((z, x, y)): Path<(i32, i32, i32)>,
State(state): State<Arc<AppState>>,
) -> Json<Vec<MapWay>> {
) -> Result<Json<Vec<MapWay>>, (axum::http::StatusCode, String)> {
let query = "SELECT id, tags, points FROM map_data.ways WHERE zoom = ? AND tile_x = ? AND tile_y = ?";
let rows = state.scylla_session.query(query, (z, x, y)).await.unwrap().rows.unwrap_or_default();
let rows = state.scylla_session.query(query, (z, x, y))
.await
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Database error: {}", e)))?
.rows
.unwrap_or_default();
let mut ways = Vec::new();
for row in rows {
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>().unwrap();
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>()
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Serialization error: {}", e)))?;
// Deserialize points blob
let mut points = Vec::new();
@@ -118,19 +129,24 @@ async fn get_tile_ways(
ways.push(MapWay { id, tags, points });
}
Json(ways)
Ok(Json(ways))
}
async fn get_tile_buildings(
Path((z, x, y)): Path<(i32, i32, i32)>,
State(state): State<Arc<AppState>>,
) -> Json<Vec<MapWay>> {
) -> Result<Json<Vec<MapWay>>, (axum::http::StatusCode, String)> {
let query = "SELECT id, tags, points FROM map_data.buildings WHERE zoom = ? AND tile_x = ? AND tile_y = ?";
let rows = state.scylla_session.query(query, (z, x, y)).await.unwrap().rows.unwrap_or_default();
let rows = state.scylla_session.query(query, (z, x, y))
.await
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Database error: {}", e)))?
.rows
.unwrap_or_default();
let mut buildings = Vec::new();
for row in rows {
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>().unwrap();
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>()
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Serialization error: {}", e)))?;
// Deserialize points blob
let mut points = Vec::new();
@@ -145,45 +161,66 @@ async fn get_tile_buildings(
buildings.push(MapWay { id, tags, points });
}
Json(buildings)
Ok(Json(buildings))
}
async fn get_tile_landuse(
Path((z, x, y)): Path<(i32, i32, i32)>,
State(state): State<Arc<AppState>>,
) -> Json<Vec<MapWay>> {
) -> Result<Json<Vec<MapWay>>, (axum::http::StatusCode, String)> {
println!("Request: get_tile_landuse({}, {}, {})", z, x, y);
let query = "SELECT id, tags, points FROM map_data.landuse WHERE zoom = ? AND tile_x = ? AND tile_y = ?";
let rows = state.scylla_session.query(query, (z, x, y)).await.unwrap().rows.unwrap_or_default();
println!("Executing query...");
let result = state.scylla_session.query(query, (z, x, y)).await;
let mut landuse = Vec::new();
for row in rows {
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>().unwrap();
let mut points = Vec::new();
for chunk in points_blob.chunks(16) {
if chunk.len() == 16 {
let lat = f64::from_be_bytes(chunk[0..8].try_into().unwrap());
let lon = f64::from_be_bytes(chunk[8..16].try_into().unwrap());
points.push(vec![lat, lon]);
match result {
Ok(res) => {
println!("Query successful, processing rows...");
let rows = res.rows.unwrap_or_default();
let mut landuse = Vec::new();
for row in rows {
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>()
.map_err(|e| {
println!("Serialization error: {}", e);
(axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Serialization error: {}", e))
})?;
let mut points = Vec::new();
for chunk in points_blob.chunks(16) {
if chunk.len() == 16 {
let lat = f64::from_be_bytes(chunk[0..8].try_into().unwrap());
let lon = f64::from_be_bytes(chunk[8..16].try_into().unwrap());
points.push(vec![lat, lon]);
}
}
landuse.push(MapWay { id, tags, points });
}
println!("Returning {} landuse items", landuse.len());
Ok(Json(landuse))
},
Err(e) => {
println!("Query failed: {}", e);
Err((axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Database error: {}", e)))
}
landuse.push(MapWay { id, tags, points });
}
Json(landuse)
}
async fn get_tile_water(
Path((z, x, y)): Path<(i32, i32, i32)>,
State(state): State<Arc<AppState>>,
) -> Json<Vec<MapWay>> {
) -> Result<Json<Vec<MapWay>>, (axum::http::StatusCode, String)> {
let query = "SELECT id, tags, points FROM map_data.water WHERE zoom = ? AND tile_x = ? AND tile_y = ?";
let rows = state.scylla_session.query(query, (z, x, y)).await.unwrap().rows.unwrap_or_default();
let rows = state.scylla_session.query(query, (z, x, y))
.await
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Database error: {}", e)))?
.rows
.unwrap_or_default();
let mut water = Vec::new();
for row in rows {
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>().unwrap();
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>()
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Serialization error: {}", e)))?;
let mut points = Vec::new();
for chunk in points_blob.chunks(16) {
@@ -197,5 +234,36 @@ async fn get_tile_water(
water.push(MapWay { id, tags, points });
}
Json(water)
Ok(Json(water))
}
async fn get_tile_railways(
Path((z, x, y)): Path<(i32, i32, i32)>,
State(state): State<Arc<AppState>>,
) -> Result<Json<Vec<MapWay>>, (axum::http::StatusCode, String)> {
let query = "SELECT id, tags, points FROM map_data.railways WHERE zoom = ? AND tile_x = ? AND tile_y = ?";
let rows = state.scylla_session.query(query, (z, x, y))
.await
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Database error: {}", e)))?
.rows
.unwrap_or_default();
let mut railways = Vec::new();
for row in rows {
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>()
.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, format!("Serialization error: {}", e)))?;
let mut points = Vec::new();
for chunk in points_blob.chunks(16) {
if chunk.len() == 16 {
let lat = f64::from_be_bytes(chunk[0..8].try_into().unwrap());
let lon = f64::from_be_bytes(chunk[8..16].try_into().unwrap());
points.push(vec![lat, lon]);
}
}
railways.push(MapWay { id, tags, points });
}
Ok(Json(railways))
}