treeadvisor/server/src/main.rs

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);
}