use handlebars::Handlebars; use hyper::service::{make_service_fn, service_fn}; use hyper::Method; use hyper::StatusCode; use hyper::{Body, Request, Response, Server}; use serde::{Deserialize, Serialize}; use std::convert::Infallible; mod config; mod models; mod templates; #[tokio::main] async fn main() -> Result<(), Box> { let addr = config::INSTANCE.addr; let client = mongodb::Client::with_uri_str(&config::INSTANCE.db_uri).await?; let make_svc = make_service_fn(move |_conn| { let client = client.clone(); async { Ok::<_, Infallible>(service_fn(move |req| router(req, client.to_owned()))) } }); let server = Server::bind(&addr).serve(make_svc); let graceful = server.with_graceful_shutdown(shutdown_signal()); // run until shutdown signal if let Err(e) = graceful.await { eprintln!("server error: {}", e); } Ok(()) } async fn router( req: Request, _client: mongodb::Client, ) -> Result, Infallible> { match (req.method(), req.uri().path()) { (&Method::GET, "/") | (&Method::GET, "/index.html") => Ok(Response::new("Welcome!".into())), (&Method::GET, "/parts") | (&Method::GET, "/parts/index.html") => get_parts(req).await, _ => Ok(Response::builder() .status(StatusCode::NOT_FOUND) .body("Not found.".into()) .unwrap()), } } async fn get_parts(req: Request) -> Result, Infallible> { let query = req.uri().query().unwrap_or_default(); let filter = serde_urlencoded::de::from_str::(query).unwrap(); let mut reg = Handlebars::new(); reg.register_template_string("index", templates::INDEX_T) .unwrap(); let mut data = PartsData::default(); data.makes = Some(vec!["Hudson".into(), "Essex".into(), "Terraplane".into()]); if let Some(make) = filter.make { if make.eq("Hudson") { data.models = Some(vec!["Hornet".into(), "Wasp".into(), "Jet".into()]); } else if make.eq("Essex") { data.models = Some(vec!["Super Six".into()]); } data.selected_make = Some(make); } data.parts = Some(Vec::new()); if let Some(model) = filter.model { data.parts = Some(vec!["1".into(), "2".into(), "3".into()]); data.selected_model = Some(model); } let result = reg.render("index", &data).unwrap(); Ok(Response::new(result.into())) } async fn shutdown_signal() { // Wait for CTRL+C tokio::signal::ctrl_c() .await .expect("failed to install CTRL+C signal handler"); } #[derive(Debug, Deserialize)] struct PartsQuery { make: Option, year: Option, model: Option, engine: Option, } #[derive(Debug, Serialize, Default)] struct PartsData { makes: Option>, years: Option>, models: Option>, engines: Option>, selected_make: Option, selected_year: Option, selected_model: Option, selected_engine: Option, parts: Option>, }