Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OLP-11 Implemented Authentication with JWT #29

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
255 changes: 254 additions & 1 deletion openlineplanner-backend/Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions openlineplanner-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ predicates = "3.0.3"
postcard = { version = "1.0.4", features = ["alloc"] }
rayon = "1.7.0"
datatypes = { path = "../datatypes" }
actix-web-httpauth = "0.8.0"
futures-util = "0.3.28"
jwtk = "0.2.4"
openssl-sys = { version = "0.9.65", features = ["vendored"] }
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
use std::collections::HashMap;

use actix_web::body::BoxBody;
use actix_web::http::header::ContentType;
use actix_web::web;
use actix_web::HttpResponse;
use actix_web::Responder;
use actix_web::{HttpResponse, Responder};
use datatypes::Streets;
use geo::Point;
use geojson::de::deserialize_geometry;
use geojson::ser::serialize_geometry;
use geojson::ser::to_feature_collection_string;
use serde::Deserialize;
use serde::Serialize;
use geojson::ser::{serialize_geometry, to_feature_collection_string};
use rayon::prelude::*;
use datatypes::Streets;
use serde::{Deserialize, Serialize};

use crate::error::OLPError;
use crate::geometry::DistanceCalculator;
use crate::geometry::DistanceFromPoint;
use crate::geometry::HaversineDistanceCalculator;
use crate::geometry::OsmDistanceCalculator;
use crate::layers::Layers;
use super::geometry::{
DistanceCalculator, DistanceFromPoint, HaversineDistanceCalculator, OsmDistanceCalculator,
};
use super::Station;
use crate::layers::PopulatedCentroid;
use crate::Station;

use std::collections::HashMap;
use std::sync::RwLock;

#[derive(Serialize)]
pub struct CoverageMap<'a, 'b>(pub HashMap<&'a str, StationCoverageInfo<'b>>);
Expand Down Expand Up @@ -80,21 +72,28 @@ pub fn get_houses_in_coverage<'a, D: DistanceCalculator + Sync>(
distance_calculator: D,
possible_collision_stations: &[&Station],
) -> Vec<PopulatedCentroidInfo<'a>> {
let distance_from_origin = distance_calculator.fix_point(origin);
let Some(distance_from_origin) = distance_calculator.fix_point(origin) else {
return Vec::new()
};
houses
.par_iter()
.filter_map(|house| {
let distance = distance_from_origin.distance(house);
if distance < coverage {
Some(PopulatedCentroidInfo{centroid: house, distance})
Some(PopulatedCentroidInfo {
centroid: house,
distance,
})
} else {
None
}
}) // PopulatedCentroid is in the radius of our station
.filter(|hi| {
possible_collision_stations.iter().all(|other| {
distance_calculator.distance(hi.centroid, &other.location) > other.coverage() // PopulatedCentroid is not in the coverage area of the other station or
|| distance_calculator.distance(hi.centroid, &origin) < distance_calculator.distance(hi.centroid, &other.location)
// PopulatedCentroid is not in the coverage area of the other station or
distance_calculator.distance(hi.centroid, &other.location) > other.coverage()
|| distance_calculator.distance(hi.centroid, &origin)
< distance_calculator.distance(hi.centroid, &other.location)
// PopulatedCentroid is closer to the current station
})
})
Expand Down Expand Up @@ -190,19 +189,3 @@ pub struct PopulatedCentroidCoverage {
distance: f64,
closest_station: String,
}

pub async fn coverage_info(
stations: web::Json<Vec<Station>>,
routing: web::Path<Routing>,
layers: web::Data<RwLock<Layers>>,
) -> Result<PopulatedCentroidCoverageLayer, OLPError> {
let layer = layers.read().map_err(OLPError::from_error)?.all_merged();
let coverage_info = houses_for_stations(
&stations,
layer.get_centroids(),
&Method::Absolute,
&routing,
layer.get_streets(),
);
Ok(PopulatedCentroidCoverageLayer::from(coverage_info))
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use std::collections::HashMap;

use datatypes::Streets;
use geo::{
CoordFloat, HaversineDistance, HaversineLength, Line, LineInterpolatePoint, LineString, Point,
};
use std::collections::HashMap;
use datatypes::Streets;

use crate::layers::PopulatedCentroid;
use osmpbfreader::NodeId;
use petgraph::algo::dijkstra;

use crate::layers::PopulatedCentroid;

pub trait DensifyHaversine<F: CoordFloat> {
type Output;

Expand Down Expand Up @@ -58,7 +59,7 @@ where
pub trait DistanceCalculator {
type FixedPoint: DistanceFromPoint + Sync;
fn distance(&self, a: &PopulatedCentroid, b: &Point) -> f64;
fn fix_point(&self, point: &Point) -> Self::FixedPoint;
fn fix_point(&self, point: &Point) -> Option<Self::FixedPoint>;
}

pub trait DistanceFromPoint {
Expand All @@ -83,10 +84,10 @@ impl DistanceCalculator for HaversineDistanceCalculator {
fn distance(&self, a: &PopulatedCentroid, b: &Point) -> f64 {
a.haversine_distance(b)
}
fn fix_point(&self, point: &Point) -> Self::FixedPoint {
HaversineFixedPoint {
fn fix_point(&self, point: &Point) -> Option<Self::FixedPoint> {
Some(HaversineFixedPoint {
point: point.clone(),
}
})
}
}

Expand Down Expand Up @@ -118,20 +119,24 @@ impl<'a> DistanceCalculator for OsmDistanceCalculator<'a> {
type FixedPoint = OsmFixedPoint;

fn distance(&self, a: &PopulatedCentroid, b: &Point) -> f64 {
let (origin_node, diff_distance) = self.find_closest_node_to_point(b);
let Some((origin_node, diff_distance)) = self.find_closest_node_to_point(b) else {
return f64::MAX
};
let osm_distance_matrix = dijkstra(&self.streets.streetgraph, origin_node, None, |e| *e.2);
osm_distance_matrix
.get(&a.street_graph_id.unwrap())
.unwrap_or(&f64::MAX)
+ diff_distance
}
fn fix_point(&self, point: &Point) -> Self::FixedPoint {
let (origin_node, diff_distance) = self.find_closest_node_to_point(point);
fn fix_point(&self, point: &Point) -> Option<Self::FixedPoint> {
let Some((origin_node, diff_distance)) = self.find_closest_node_to_point(point) else {
return None
};
let distance_matrix = dijkstra(&self.streets.streetgraph, origin_node, None, |e| *e.2);
OsmFixedPoint {
Some(OsmFixedPoint {
diff_distance,
distance_matrix,
}
})
}
}

Expand All @@ -140,12 +145,11 @@ impl<'a> OsmDistanceCalculator<'a> {
Self { streets }
}

fn find_closest_node_to_point(&self, origin: &Point) -> (NodeId, f64) {
fn find_closest_node_to_point(&self, origin: &Point) -> Option<(NodeId, f64)> {
self.streets
.nodes
.iter()
.min_by_key(|(_, node)| node.haversine_distance(&origin) as u32)
.map(|(id, node)| (id.clone(), node.haversine_distance(&origin)))
.unwrap()
}
}
101 changes: 101 additions & 0 deletions openlineplanner-backend/src/calculation/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use std::sync::{Arc, RwLock};

use actix_web::{web, Scope};
use anyhow::Result;
use coverage::{CoverageMap, Method, Routing};
use geo::Point;
use population::InhabitantsMap;
use serde::Deserialize;
use station::{OptimalStationResult, Station};

use self::coverage::{houses_for_stations, PopulatedCentroidCoverageLayer};
use crate::error::OLPError;
use crate::layers::{LayerType, Layers};

mod coverage;
mod geometry;
mod population;
mod station;

pub fn calculation() -> Scope {
web::scope("/calculate")
.route("/station-info", web::post().to(station_info))
.route("/coverage-info/{router}", web::post().to(coverage_info))
.route("/find-station", web::post().to(find_station))
}

#[derive(Deserialize)]
pub struct StationInfoRequest {
stations: Vec<Station>,
_separation_distance: Option<i32>,
method: Option<Method>,
routing: Option<Routing>,
}

pub async fn station_info(
request: web::Json<StationInfoRequest>,
layers: web::ReqData<Arc<RwLock<Layers>>>,
) -> Result<InhabitantsMap, OLPError> {
let merged_layers = layers
.read()
.map_err(OLPError::from_error)?
.all_merged_by_type();
let coverage_info: Vec<(LayerType, CoverageMap)> = merged_layers
.iter()
.map(|layer| {
log::debug!("calculating for layer type: {}", layer.get_type());
(
layer.get_type().clone(),
coverage::houses_for_stations(
&request.stations,
layer.get_centroids(),
&request.method.as_ref().unwrap_or(&Method::Relative),
&request.routing.as_ref().unwrap_or(&Routing::Osm),
layer.get_streets(),
),
)
})
.collect();
let coverage_slice: &[(LayerType, CoverageMap)] = &coverage_info;
Ok(population::InhabitantsMap::from(coverage_slice))
}

#[derive(Deserialize)]
pub struct FindStationRequest {
stations: Vec<Station>,
route: Vec<Point>,
method: Option<Method>,
routing: Option<Routing>,
}

pub async fn find_station(
request: web::Json<FindStationRequest>,
layers: web::ReqData<Arc<RwLock<Layers>>>,
) -> Result<OptimalStationResult, OLPError> {
let layer = layers.read().map_err(OLPError::from_error)?.all_merged();
Ok(station::find_optimal_station(
request.route.clone(),
300f64,
layer.get_centroids(),
&request.stations,
&request.method.as_ref().unwrap_or(&Method::Relative),
&request.routing.as_ref().unwrap_or(&Routing::Osm),
layer.get_streets(),
))
}

pub async fn coverage_info(
stations: web::Json<Vec<Station>>,
routing: web::Path<Routing>,
layers: web::ReqData<Arc<RwLock<Layers>>>,
) -> Result<PopulatedCentroidCoverageLayer, OLPError> {
let layer = layers.read().map_err(OLPError::from_error)?.all_merged();
let coverage_info = houses_for_stations(
&stations,
layer.get_centroids(),
&Method::Absolute,
&routing,
layer.get_streets(),
);
Ok(PopulatedCentroidCoverageLayer::from(coverage_info))
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use std::collections::HashMap;

use actix_web::body::BoxBody;
use actix_web::http::header::ContentType;
use actix_web::HttpResponse;
use actix_web::Responder;
use actix_web::{HttpResponse, Responder};
use serde::Serialize;

use crate::coverage::CoverageMap;
use super::coverage::CoverageMap;
use crate::layers::LayerType;

use std::collections::HashMap;

#[derive(Serialize)]
pub struct InhabitantsInfo {
layer_type: LayerType,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use std::borrow::Borrow;

use actix_web::{body::BoxBody, http::header::ContentType, HttpResponse, Responder};
use actix_web::body::BoxBody;
use actix_web::http::header::ContentType;
use actix_web::{HttpResponse, Responder};
use datatypes::Streets;
use geo::{HaversineDistance, LineString, Point};
use serde::{Deserialize, Serialize};
use datatypes::Streets;
use rayon::prelude::*;

use crate::{
coverage::StationCoverageInfo,
coverage::{get_houses_in_coverage, houses_for_stations, Method, Routing},
geometry::{DensifyHaversine, OsmDistanceCalculator},
layers::PopulatedCentroid,
use super::coverage::{
get_houses_in_coverage, houses_for_stations, Method, Routing, StationCoverageInfo,
};
use super::geometry::{DensifyHaversine, OsmDistanceCalculator};
use crate::layers::PopulatedCentroid;

static DEFAULT_COVERAGE: f64 = 300f64;

Expand Down Expand Up @@ -45,18 +47,18 @@ pub fn find_optimal_station(
let original_coverage: Vec<&PopulatedCentroid> =
houses_for_stations(other_stations, houses, method, routing, streets)
.0
.values()
.into_iter()
.flat_map(|elem| elem.houses.clone())
.into_par_iter()
.flat_map(|(_,elem)| elem.houses.clone())
.map(|elem| elem.centroid)
.collect();
let leftover_houses: Vec<PopulatedCentroid> = houses
.iter()
.par_iter()
.filter(|house| !original_coverage.contains(house))
.cloned()
.collect();
let location = linestring
.points()
.par_bridge()
.max_by_key(|point| {
StationCoverageInfo::from_houses_with_method(
get_houses_in_coverage(
Expand Down
6 changes: 4 additions & 2 deletions openlineplanner-backend/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{error::Error, fmt::Display};
use std::error::Error;
use std::fmt::Display;

use actix_web::{body::BoxBody, HttpResponse, Responder, ResponseError};
use actix_web::body::BoxBody;
use actix_web::{HttpResponse, Responder, ResponseError};

#[derive(Debug)]
pub enum OLPError {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use actix_web::{body::BoxBody, http::header::ContentType, HttpResponse, Responder};
use actix_web::body::BoxBody;
use actix_web::http::header::ContentType;
use actix_web::{HttpResponse, Responder};
use geo::{Point, Polygon};
use geojson::{
feature::Id,
ser::{serialize_geometry, to_feature_collection_string},
Feature, GeoJson,
};
use geojson::feature::Id;
use geojson::ser::{serialize_geometry, to_feature_collection_string};
use geojson::{Feature, GeoJson};
use serde::Serialize;
use tinytemplate::TinyTemplate;

use crate::error::OLPError;

use super::overpass::query_overpass;
use crate::error::OLPError;

#[derive(Serialize)]
pub struct AdminArea {
Expand Down
Loading