summaryrefslogblamecommitdiff
path: root/src/main.rs
blob: b71df18cb1a265de68d2c6f65c7332667eda818b (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                           
                                                  

                      
                                             
                                    
                             
 

           

              
              

                                                           
 






                                                                                            
 
                                                     

                                                                    
                                


                                         

          

 



                                         

                                                                                                    
                                                                                               






                                          
                                                                              
                                                      
                                                                              


                                                             

                                                                                  

















                                                                                   


                            
                      



                                                           

                             
                   
                         
                         
                          
                           


                                    
                  
                               
                               
                                
                                 
                                  
                                  
                                   
                                    

                               
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<dyn std::error::Error>> {
    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<Body>,
    _client: mongodb::Client,
) -> Result<Response<Body>, 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<Body>) -> Result<Response<Body>, Infallible> {
    let query = req.uri().query().unwrap_or_default();
    let filter = serde_urlencoded::de::from_str::<PartsQuery>(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<String>,
    year: Option<String>,
    model: Option<String>,
    engine: Option<String>,
}

#[derive(Debug, Serialize, Default)]
struct PartsData {
    makes: Option<Vec<String>>,
    years: Option<Vec<String>>,
    models: Option<Vec<String>>,
    engines: Option<Vec<String>>,
    selected_make: Option<String>,
    selected_year: Option<String>,
    selected_model: Option<String>,
    selected_engine: Option<String>,
    parts: Option<Vec<String>>,
}