173 lines
6 KiB
Rust
173 lines
6 KiB
Rust
use actix_web::{get, web::{self, Data}, HttpRequest, HttpResponse, Responder};
|
|
use anyhow::anyhow;
|
|
use std::{collections::{HashMap, HashSet}, sync::Arc, time::Instant};
|
|
use libseptastic::{direction, route::RouteType, stop_schedule::Trip};
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
use crate::AppState;
|
|
//use crate::{routing::{bfs_rts, construct_graph, get_stops_near}, AppState};
|
|
//use crate::routing;
|
|
|
|
#[get("/routes")]
|
|
async fn get_routes_html(req: HttpRequest, state: Data<Arc<AppState>>) -> impl Responder {
|
|
crate::perform_action(req, move || {
|
|
let statex = state.clone();
|
|
async move {
|
|
let start_time = Instant::now();
|
|
|
|
let all_routes: Vec<libseptastic::route::Route> = statex.gtfs_service.get_routes();
|
|
let rr_routes = all_routes.clone().into_iter().filter(|x| x.route_type == RouteType::RegionalRail).collect();
|
|
let subway_routes = all_routes.clone().into_iter().filter(|x| x.route_type == RouteType::SubwayElevated).collect();
|
|
let trolley_routes = all_routes.clone().into_iter().filter(|x| x.route_type == RouteType::Trolley).collect();
|
|
let bus_routes = all_routes.into_iter().filter(|x| x.route_type == RouteType::TracklessTrolley || x.route_type == RouteType::Bus).collect();
|
|
|
|
Ok(crate::templates::ContentTemplate {
|
|
page_title: Some(String::from("Routes")),
|
|
page_desc: Some(String::from("All SEPTA routes.")),
|
|
widescreen: false,
|
|
content: crate::templates::RoutesTemplate {
|
|
rr_routes,
|
|
subway_routes,
|
|
trolley_routes,
|
|
bus_routes,
|
|
},
|
|
load_time_ms: Some(start_time.elapsed().as_millis())
|
|
})
|
|
}
|
|
}).await
|
|
}
|
|
|
|
|
|
#[get("/routes.json")]
|
|
async fn get_routes_json(state: Data<Arc<AppState>>) -> impl Responder {
|
|
let all_routes: Vec<libseptastic::route::Route> = state.gtfs_service.get_routes();
|
|
HttpResponse::Ok().json(all_routes)
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
|
pub struct RouteQueryParams {
|
|
#[serde(default)] // Optional: handle missing parameters with a default value
|
|
stops: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct RouteResponse {
|
|
pub route: libseptastic::route::Route,
|
|
pub directions: Vec<libseptastic::direction::Direction>,
|
|
pub schedule: Vec<Trip>
|
|
}
|
|
|
|
async fn get_route_info(route_id: String, state: Data<Arc<AppState>>) -> ::anyhow::Result<RouteResponse> {
|
|
let route = state.gtfs_service.get_route(route_id.clone())?;
|
|
let mut trips = state.gtfs_service.get_schedule(route_id)?;
|
|
|
|
let mut seen = HashSet::new();
|
|
let directions: Vec<_> = trips
|
|
.iter()
|
|
.map(|x| x.direction.clone())
|
|
.filter(|dir| seen.insert(dir.direction.to_string()))
|
|
.collect();
|
|
|
|
state.trip_tracking_service.annotate_trips(&mut trips).await;
|
|
|
|
Ok(RouteResponse{
|
|
route,
|
|
directions,
|
|
schedule: trips
|
|
})
|
|
}
|
|
|
|
//#[get("/directions")]
|
|
//async fn get_directions(state: Data<Arc<AppState>>) -> impl Responder {
|
|
// let near_thresh = 0.45;
|
|
//
|
|
// let sig_cds = routing::Coordinates {
|
|
// lat: 40.008420,
|
|
// lng: -75.213439
|
|
// };
|
|
//
|
|
// let home_cds = routing::Coordinates {
|
|
// lat: 39.957210,
|
|
// lng: -75.166214
|
|
// };
|
|
//
|
|
// let all_stops = state.gtfs_service.get_all_stops();
|
|
//
|
|
//
|
|
//
|
|
// let origin_stops: HashSet<String> = get_stops_near(home_cds, &all_stops);
|
|
// let dest_stops: HashSet<String> = get_stops_near(sig_cds.clone(), &all_stops);
|
|
//
|
|
// let mut graph = construct_graph(sig_cds, &all_stops, &state.gtfs_service);
|
|
//
|
|
// let mut response = String::new();
|
|
// for stop in &origin_stops {
|
|
// response += bfs_rts(&stop, &mut graph, &dest_stops).as_str();
|
|
// }
|
|
//
|
|
// return response;
|
|
//}
|
|
|
|
#[get("/route/{route_id}")]
|
|
async fn get_route(state: Data<Arc<AppState>>, req: HttpRequest, info: web::Query<RouteQueryParams>, path: web::Path<String>) -> impl Responder {
|
|
crate::perform_action(req, move || {
|
|
let pathx = path.clone();
|
|
let infox = info.clone();
|
|
let statex = state.clone();
|
|
async move {
|
|
let mut filters: Option<Vec<String>> = None;
|
|
if let Some (stops_v) = infox.stops.clone() {
|
|
let mut items = Vec::new();
|
|
|
|
for sid in stops_v.split(",") {
|
|
items.push(String::from(sid));
|
|
}
|
|
filters = Some(items);
|
|
}
|
|
|
|
let route_id = pathx;
|
|
let route_info_r = get_route_info(route_id.clone(), statex.clone()).await;
|
|
|
|
if let Ok(route_info) = route_info_r {
|
|
let timetables = crate::templates::build_timetables(route_info.directions, route_info.schedule);
|
|
|
|
Ok(crate::templates::ContentTemplate {
|
|
widescreen: false,
|
|
page_title: Some(format!("Schedules for {}", route_id.clone())),
|
|
page_desc: Some(format!("Schedule information for {}", route_id.clone())),
|
|
content: crate::templates::RouteTemplate {
|
|
route: route_info.route,
|
|
timetables,
|
|
filter_stops: filters.clone()
|
|
},
|
|
load_time_ms: None
|
|
})
|
|
} else {
|
|
Err(anyhow!("test"))
|
|
}
|
|
}}).await
|
|
}
|
|
|
|
#[get("/route/{route_id}.json")]
|
|
async fn api_get_route(state: Data<Arc<AppState>>, path: web::Path<String>) -> impl Responder {
|
|
let route_id = path.into_inner();
|
|
let route_info_r = get_route_info(route_id, state).await;
|
|
if let Ok(route_info) = route_info_r {
|
|
HttpResponse::Ok().json(route_info)
|
|
} else {
|
|
HttpResponse::InternalServerError().body("Error")
|
|
}
|
|
}
|
|
|
|
#[get("/api/route/{route_id}/schedule")]
|
|
async fn api_get_schedule(state: Data<Arc<AppState>>, path: web::Path<String>) -> impl Responder {
|
|
let route_id = path.into_inner();
|
|
let route_r: anyhow::Result<i32> = Ok(5);
|
|
|
|
if let Ok(route) = route_r {
|
|
HttpResponse::Ok().json(route)
|
|
} else {
|
|
HttpResponse::InternalServerError().body("Error")
|
|
}
|
|
}
|
|
|