181 lines
4.4 KiB
Rust
181 lines
4.4 KiB
Rust
// #![recursion_limit="2048"]
|
|
|
|
#[macro_use]
|
|
extern crate gotham_derive;
|
|
|
|
use core::f64::consts::PI;
|
|
use std::sync::{Arc, Mutex};
|
|
use gotham::{
|
|
handler::assets::FileOptions,
|
|
router::builder::{DefineSingleRoute, DrawRoutes},
|
|
middleware::state::StateMiddleware,
|
|
pipeline::single::single_pipeline,
|
|
pipeline::single_middleware,
|
|
router::builder::*,
|
|
};
|
|
use std::io::Cursor;
|
|
use gotham::{
|
|
helpers::http::response::create_response,
|
|
hyper::{Body, Response},
|
|
state::{FromState, State},
|
|
};
|
|
use geo::{Rect, Point};
|
|
use serde::Deserialize;
|
|
|
|
mod area;
|
|
mod trees;
|
|
mod tile_style;
|
|
mod tiles;
|
|
|
|
#[derive(Clone, StateData)]
|
|
pub struct AppState {
|
|
pub db_pool: Vec<Arc<Mutex<postgres::Client>>>,
|
|
pub db_pool_index: Arc<Mutex<usize>>,
|
|
}
|
|
|
|
impl AppState {
|
|
pub fn with_db<F: Fn(&mut postgres::Client) -> R, R>(&self, f: F) -> R {
|
|
use std::ops::Deref;
|
|
let mut db_pool_index = self.db_pool_index.lock().unwrap();
|
|
let mut db = self.db_pool[*db_pool_index].lock().unwrap();
|
|
|
|
*db_pool_index += 1;
|
|
if *db_pool_index >= self.db_pool.len() {
|
|
*db_pool_index = 0;
|
|
}
|
|
|
|
f(&mut db)
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug, Deserialize, StateData, StaticResponseExtender)]
|
|
pub struct IdExtractor {
|
|
pub id: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, StateData, StaticResponseExtender)]
|
|
pub struct AreaExtractor {
|
|
x1: f64,
|
|
y1: f64,
|
|
x2: f64,
|
|
y2: f64,
|
|
}
|
|
|
|
impl AreaExtractor {
|
|
fn grow(&self, a: f64) -> Self {
|
|
AreaExtractor {
|
|
x1: self.x1 - a * self.w(),
|
|
y1: self.y1 - a * self.h(),
|
|
x2: self.x2 + a * self.w(),
|
|
y2: self.y2 + a * self.h(),
|
|
}
|
|
}
|
|
|
|
fn to_rect(&self) -> Rect<f64> {
|
|
Rect::new((self.x1, self.y1), (self.x2, self.y2))
|
|
}
|
|
|
|
fn w(&self) -> f64 {
|
|
self.x2 - self.x1
|
|
}
|
|
|
|
fn h(&self) -> f64 {
|
|
self.y2 - self.y1
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, StateData, StaticResponseExtender)]
|
|
pub struct PointExtractor {
|
|
x: f64,
|
|
y: f64,
|
|
}
|
|
|
|
impl PointExtractor {
|
|
fn to_point(&self) -> Point<f64> {
|
|
Point::new(self.x, self.y)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, StateData, StaticResponseExtender)]
|
|
pub struct TileExtractor {
|
|
zoom: i32,
|
|
x: u32,
|
|
y: u32,
|
|
}
|
|
|
|
impl TileExtractor {
|
|
fn lon(&self) -> f64 {
|
|
360. * self.x as f64 / 2f64.powi(self.zoom) - 180.
|
|
}
|
|
|
|
fn lat(&self) -> f64 {
|
|
(PI * (1f64 - 2f64 * self.y as f64 / 2f64.powi(self.zoom))).sinh().atan() * 180. / PI
|
|
}
|
|
|
|
pub fn south_west(&self) -> Self {
|
|
TileExtractor {
|
|
zoom: self.zoom,
|
|
x: self.x + 1,
|
|
y: self.y + 1,
|
|
}
|
|
}
|
|
|
|
pub fn to_point(&self) -> Point<f64> {
|
|
Point::new(self.lon(), self.lat())
|
|
}
|
|
|
|
pub fn to_rect(&self) -> Rect<f64> {
|
|
let sw = self.south_west();
|
|
Rect::new(self.to_point(), sw.to_point())
|
|
}
|
|
|
|
}
|
|
|
|
fn main() {
|
|
const DB_URL: &str = "host=10.233.1.2 dbname=treeadvisor user=treeadvisor password=123";
|
|
|
|
let cpus = num_cpus::get();
|
|
let db_pool = (0..cpus).map(|_| Arc::new(Mutex::new(
|
|
postgres::Client::connect(DB_URL, postgres::NoTls)
|
|
.expect("DB")
|
|
))).collect();
|
|
|
|
let state = AppState {
|
|
db_pool: db_pool,
|
|
db_pool_index: Arc::new(Mutex::new(0)),
|
|
};
|
|
let (chain, pipelines) = single_pipeline(
|
|
single_middleware(
|
|
StateMiddleware::new(state)
|
|
)
|
|
);
|
|
let router = build_router(chain, pipelines, |route| {
|
|
route.get("/tiles/:zoom/:x/:y/tile.png")
|
|
.with_path_extractor::<TileExtractor>()
|
|
.to(tiles::get_tile);
|
|
route.get("/heatmap/:zoom/:x/:y/tile.png")
|
|
.with_path_extractor::<TileExtractor>()
|
|
.to(trees::get_heatmap);
|
|
route.get("/area/:x/:y")
|
|
.with_path_extractor::<PointExtractor>()
|
|
.to(area::get_details);
|
|
route.get("/trees/:x1/:y1/:x2/:y2")
|
|
.with_path_extractor::<AreaExtractor>()
|
|
.to(trees::get_trees);
|
|
route.get("/tree/:id")
|
|
.with_path_extractor::<IdExtractor>()
|
|
.to(trees::get_tree);
|
|
// route.get("/tiles/:zoom/:x/:y/tile.png")
|
|
// .with_path_extractor::<TileExtractor>()
|
|
// .to(trees::get_tile);
|
|
route.get("static/*").to_dir(
|
|
FileOptions::new(&"static")
|
|
.with_cache_control("no-cache")
|
|
.with_gzip(true)
|
|
.build()
|
|
);
|
|
});
|
|
gotham::start("0.0.0.0:8400", router);
|
|
}
|