summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 2f5bdf46098b93b3bd6ad0f20a69974f3a817031 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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;
use std::net::SocketAddr;

mod templates;

#[tokio::main]
async fn main() {
    // bind to 127.0.0.1:3000
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

    let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(router)) });

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

async fn router(req: Request<Body>) -> 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") => parts(req).await,
        _ => Ok(Response::builder()
            .status(StatusCode::NOT_FOUND)
            .body("Not found.".into())
            .unwrap()),
    }
}

async fn parts(req: Request<Body>) -> Result<Response<Body>, Infallible> {
    let query = req.uri().query().unwrap_or_default();
    let filter = serde_urlencoded::de::from_str::<PartsRequest>(query).unwrap();
    let mut reg = Handlebars::new();
    reg.register_template_string("index", templates::INDEX_T)
        .unwrap();
    let mut data = PartsView::default();
    data.makes = Some(vec!["Hudson".into(), "Essex".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 PartsRequest {
    make: Option<String>,
    model: Option<String>,
}

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