first commit
This commit is contained in:
146
backend/src/main.rs
Normal file
146
backend/src/main.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
mod db;
|
||||
|
||||
use axum::{
|
||||
routing::get,
|
||||
Router,
|
||||
extract::{State, Path},
|
||||
Json,
|
||||
};
|
||||
use scylla::{Session, SessionBuilder};
|
||||
use std::sync::Arc;
|
||||
use tower_http::services::ServeDir;
|
||||
use tower_http::cors::CorsLayer;
|
||||
use serde::Serialize;
|
||||
|
||||
struct AppState {
|
||||
scylla_session: Arc<Session>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
println!("Connecting to ScyllaDB...");
|
||||
let uri = std::env::var("SCYLLA_URI").unwrap_or_else(|_| "127.0.0.1:9042".to_string());
|
||||
|
||||
let session = SessionBuilder::new()
|
||||
.known_node(uri)
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
// Initialize schema and seed data
|
||||
db::initialize_schema(&session).await?;
|
||||
db::seed_data(&session).await?;
|
||||
|
||||
let session = Arc::new(session);
|
||||
println!("Connected to ScyllaDB!");
|
||||
|
||||
let state = Arc::new(AppState {
|
||||
scylla_session: session,
|
||||
});
|
||||
|
||||
let app = Router::new()
|
||||
.route("/health", get(health_check))
|
||||
.route("/api/tiles/:z/:x/:y", get(get_tile))
|
||||
.route("/api/tiles/:z/:x/:y/ways", get(get_tile_ways))
|
||||
.route("/api/tiles/:z/:x/:y/buildings", get(get_tile_buildings))
|
||||
.nest_service("/", ServeDir::new("static"))
|
||||
.layer(CorsLayer::permissive())
|
||||
.with_state(state);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
||||
println!("Server listening on {}", listener.local_addr()?);
|
||||
axum::serve(listener, app).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn health_check() -> &'static str {
|
||||
"OK"
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct MapNode {
|
||||
id: i64,
|
||||
lat: f64,
|
||||
lon: f64,
|
||||
tags: std::collections::HashMap<String, String>,
|
||||
}
|
||||
|
||||
async fn get_tile(
|
||||
Path((z, x, y)): Path<(i32, i32, i32)>,
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Json<Vec<MapNode>> {
|
||||
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 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();
|
||||
nodes.push(MapNode { id, lat, lon, tags });
|
||||
}
|
||||
|
||||
Json(nodes)
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct MapWay {
|
||||
id: i64,
|
||||
tags: std::collections::HashMap<String, String>,
|
||||
points: Vec<Vec<f64>>, // List of [lat, lon]
|
||||
}
|
||||
|
||||
async fn get_tile_ways(
|
||||
Path((z, x, y)): Path<(i32, i32, i32)>,
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Json<Vec<MapWay>> {
|
||||
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 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();
|
||||
|
||||
// Deserialize points blob
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
ways.push(MapWay { id, tags, points });
|
||||
}
|
||||
|
||||
Json(ways)
|
||||
}
|
||||
|
||||
async fn get_tile_buildings(
|
||||
Path((z, x, y)): Path<(i32, i32, i32)>,
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Json<Vec<MapWay>> {
|
||||
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 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();
|
||||
|
||||
// Deserialize points blob
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
buildings.push(MapWay { id, tags, points });
|
||||
}
|
||||
|
||||
Json(buildings)
|
||||
}
|
||||
Reference in New Issue
Block a user