diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8914f63bdb380ed7fe68b4841fd3137c42763dc3..fae35be50959b44bcf0eb0162250b83967df1286 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,6 +5,7 @@ variables: stages: - docker +- build docker:front: image: docker @@ -19,3 +20,19 @@ docker:front: - docker push $CI_REGISTRY/$CI_PROJECT_PATH/rustaheat:$CI_COMMIT_REF_SLUG only: - master + + docker:back: + image: docker + services: + - name: docker:dind + alias: dockerhost + stage: build + before_script: + - i=0; while [ "$i" -lt 12 ]; do docker info && break; sleep 5; i=$(( i + 1 )) ; done + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + script: + - docker build -t $CI_REGISTRY/$CI_PROJECT_PATH/rustaheat-server:$CI_COMMIT_REF_SLUG ./server + - docker push $CI_REGISTRY/$CI_PROJECT_PATH/rustaheat-server:$CI_COMMIT_REF_SLUG + only: + - master + diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..52d25200ac30844054ac4a4a0d37cb2e0f9ff34b --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,30 @@ +FROM rust:alpine as builder + +#Install libc equivalent +RUN apk add --no-cache musl-dev +RUN apk add --no-cache pkgconfig +RUN apk add --no-cache libressl-dev + +RUN --mount=type=bind,source=src,target=src \ + --mount=type=bind,source=Cargo.toml,target=Cargo.toml \ + --mount=type=cache,target=/app/target/ \ + --mount=type=cache,target=/usr/local/cargo/registry/ \ + <<EOF +set -e +cargo build --bin server --release +cp ./target/release/server /bin/server +EOF + +FROM alpine as runner +# Copy the server binary to the /app directory + +COPY --from=builder /bin/server /bin/ + +COPY ./data.json data.json +COPY ./montreal.osm.pbf montreal.osm.pbf + +# Set any required env variables and +ENV RUST_LOG="debug" +EXPOSE 6942 + +CMD ["/bin/backend"] \ No newline at end of file diff --git a/server/compose.yml b/server/compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..edf1a838843b457ccc2898562f2f1b4cdf977fbf --- /dev/null +++ b/server/compose.yml @@ -0,0 +1,7 @@ +services: + server: + container_name: server + hostname: server + build: . + ports: + - 6942:6942 diff --git a/server/src/bin/transform.rs b/server/src/bin/transform.rs index 9794eb9222afb0debdd06b0c7432caae8c5963b5..839f16dd15e6c7c511b562c3a69f562095598211 100644 --- a/server/src/bin/transform.rs +++ b/server/src/bin/transform.rs @@ -7,7 +7,10 @@ use server::map::{ fn main() { let r = File::open(&std::path::Path::new("montreal.osm.pbf")).unwrap(); +<<<<<<< HEAD +======= let time = Instant::now(); +>>>>>>> 54fe160 (Initial commit) let mut pbf = osmpbfreader::OsmPbfReader::new(r); let mut map = Map::default(); @@ -18,9 +21,18 @@ fn main() { } map.build(); +<<<<<<< HEAD + let time = Instant::now(); + println!( + "{:#?} computed in {}s", + map.get(PlaceOfInterest::Restaurant, -73.76915, 45.53415), + time.elapsed().as_secs_f32() + ); +======= map.get(PlaceOfInterest::Restaurant, 45.53415, -73.76915); // println!( // "{:#?} computed in {}s", // time.elapsed().as_secs_f32() // ); +>>>>>>> 54fe160 (Initial commit) } diff --git a/server/src/main.rs b/server/src/main.rs index 639b716ca59f9997f5c3df9d30037c78b5cb6191..ed1f71ea5590c495df434dae7d5a3a5bd448540e 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -3,9 +3,12 @@ use std::{ sync::{Arc, Mutex}, }; -use poem::{listener::TcpListener, Route, Server}; +use poem::{listener::TcpListener, middleware::Cors, EndpointExt, Route, Server}; use poem_openapi::{payload::Json, ApiResponse, Object, OpenApi, OpenApiService}; -use server::map::{interest_point::InterestPoint, Map}; +use server::map::{ + interest_point::{InterestPoint, PlaceOfInterest}, + Map, +}; struct State { pub map: Map, } @@ -16,9 +19,9 @@ struct Api { #[derive(Object)] struct ServiceRequestData { - tags: Vec<String>, - latitude: f64, - longitude: f64, + pub tags: Vec<String>, + pub latitude: f64, + pub longitude: f64, } #[derive(Object)] @@ -51,16 +54,22 @@ impl Api { } #[oai(path = "/service", method = "post")] - async fn index(&self, data: Json<ServiceRequestData>) -> ServiceResponse { - let map = self - .state - .lock() - .unwrap() - .map - .get_interests_point(0) - .clone(); - let place_interest = map.iter().take(10).cloned().collect(); - ServiceResponse::Ok(Json(ServiceResponseData { place_interest })) + async fn index(&self, input: Json<ServiceRequestData>) -> ServiceResponse { + let mut data: Vec<InterestPoint> = vec![]; + for tag in input.tags.iter() { + let place_of_interest = PlaceOfInterest::from_str(tag.as_str(), None); + if let Some(place_of_interest) = place_of_interest { + let d = self.state.lock().unwrap().map.get( + place_of_interest, + input.longitude, + input.latitude, + ); + data.extend(d.iter().cloned()); + } + } + ServiceResponse::Ok(Json(ServiceResponseData { + place_interest: data, + })) } } @@ -76,6 +85,11 @@ async fn main() -> Result<(), std::io::Error> { let ui = api_service.swagger_ui(); Server::new(TcpListener::bind("0.0.0.0:6942")) - .run(Route::new().nest("/api", api_service).nest("/", ui)) + .run( + Route::new() + .nest("/api", api_service) + .nest("/", ui) + .with(Cors::new()), + ) .await } diff --git a/server/src/map/interest_point.rs b/server/src/map/interest_point.rs index 4e1da0e4518e7ec2ba4a5676f341baf13ca6d783..034aa1ec29643a797c52b74aa6bd6e842ffc1316 100644 --- a/server/src/map/interest_point.rs +++ b/server/src/map/interest_point.rs @@ -1,7 +1,7 @@ use osmpbfreader::OsmObj; use poem_openapi::{Enum, Object}; -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Enum)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Enum)] #[repr(u8)] pub enum PlaceOfInterest { Bank = 0, @@ -62,8 +62,8 @@ impl PlaceOfInterest { } } -#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Object)] -struct Tag { +#[derive(Clone, Debug, Hash, PartialEq, PartialOrd, Eq, Ord, Object)] +pub struct Tag { key: String, value: String, } @@ -74,10 +74,10 @@ impl Tag { } } -#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Object)] +#[derive(Clone, Debug, Hash, PartialEq, PartialOrd, Eq, Ord, Object)] pub struct InterestPoint { - longitude: i32, - latitude: i32, + pub longitude: i32, + pub latitude: i32, place_interest: PlaceOfInterest, tags: Vec<Tag>, } @@ -119,7 +119,7 @@ impl InterestPoint { } } pub fn get_type(&self) -> PlaceOfInterest { - PlaceOfInterest::Bank + self.place_interest } pub fn longitude(&self) -> f64 { self.longitude as f64 * 1e-7 diff --git a/server/src/map/interest_points.rs b/server/src/map/interest_points.rs new file mode 100644 index 0000000000000000000000000000000000000000..0a40c9fd41e6a5377bf1eeb58764f715bb8e5132 --- /dev/null +++ b/server/src/map/interest_points.rs @@ -0,0 +1,42 @@ +use std::collections::HashSet; + +use super::interest_point::InterestPoint; + +#[derive(Debug, Default)] +pub struct InterestPoints { + longitude: Vec<InterestPoint>, + latitude: Vec<InterestPoint>, +} + +const MAX_DISTANCE: f64 = 0.011; + +impl InterestPoints { + pub fn push(&mut self, interest_point: InterestPoint) { + self.longitude.push(interest_point.clone()); + self.latitude.push(interest_point); + } + pub fn sort(&mut self) { + self.longitude.sort_unstable_by_key(|point| point.longitude); + self.latitude.sort_unstable_by_key(|point| point.latitude); + } + pub fn get(&self, longitude: f64, latitude: f64) -> Vec<InterestPoint> { + let inf = self.latitude.partition_point(|interest_point| { + !(interest_point.latitude() > latitude - MAX_DISTANCE) + }); + let sup = self + .latitude + .partition_point(|interest_point| interest_point.latitude() < latitude + MAX_DISTANCE); + + let latitude: HashSet<InterestPoint> = self.latitude[inf..sup].iter().cloned().collect(); + + let inf = self.longitude.partition_point(|interest_point| { + !(interest_point.longitude() > longitude - MAX_DISTANCE) + }); + let sup = self.longitude.partition_point(|interest_point| { + interest_point.longitude() < longitude + MAX_DISTANCE + }); + + let longitude: HashSet<InterestPoint> = self.longitude[inf..sup].iter().cloned().collect(); + latitude.intersection(&longitude).cloned().collect() + } +} diff --git a/server/src/map/mod.rs b/server/src/map/mod.rs index d0806dc1f4906201a1263f59f9398dec67445ead..5c4aae807183677a5ca2a7742466697dff076493 100644 --- a/server/src/map/mod.rs +++ b/server/src/map/mod.rs @@ -1,21 +1,23 @@ -use self::interest_point::{InterestPoint, PlaceOfInterest}; +use self::{ + interest_point::{InterestPoint, PlaceOfInterest}, + interest_points::InterestPoints, +}; pub mod interest_point; +pub mod interest_points; #[derive(Debug, Default)] pub struct Map { - interests_point: [Vec<InterestPoint>; 20], + pub interests_point: [InterestPoints; 20], } -const MAX_DISTANCE: f64 = 0.011; - impl Map { pub fn push(&mut self, interest_point: InterestPoint) { self.interests_point[interest_point.get_type() as usize].push(interest_point); } pub fn build(&mut self) { for interest_point in self.interests_point.iter_mut() { - interest_point.sort_unstable(); + interest_point.sort(); } } pub fn get( @@ -24,26 +26,6 @@ impl Map { longitude: f64, latitude: f64, ) -> Vec<InterestPoint> { - let inf = - self.interests_point[place_of_interest as usize].partition_point(|interest_point| { - interest_point.latitude() > latitude - MAX_DISTANCE - && interest_point.longitude() > longitude - MAX_DISTANCE - }); - let sup = - self.interests_point[place_of_interest as usize].partition_point(|interest_point| { - interest_point.latitude() < latitude + MAX_DISTANCE - && interest_point.longitude() < longitude + MAX_DISTANCE - }); - println!( - "{} {} {}", - inf, - sup, - self.interests_point[place_of_interest as usize].len() - ); - self.interests_point[place_of_interest as usize][inf..sup].to_vec() - } - - pub fn get_interests_point(&self, place_of_interest: usize) -> &Vec<InterestPoint> { - &self.interests_point[place_of_interest] + self.interests_point[place_of_interest as usize].get(longitude, latitude) } }