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
mod conn;
mod routes;
mod web;

extern crate futures;
extern crate regex;
#[macro_use]
extern crate serde_derive;

use conn::{conn_to_response, create_conn};
pub use conn::{html, json, xml, Conn};
use routes::match_route;
pub use routes::{Middleware, Pattern, Route};
use std::collections::HashMap;
use wasm_bindgen::prelude::*;
pub use web::{Method, Request, Response};

pub enum ConfettiError {}

pub async fn run(request_object: JsValue, routes: Vec<Route>) -> JsValue {
    let response = match process_request(request_object, routes).await {
        Ok(response) => response,
        Err(_) => Response {
            status: 400,
            body: "Invalid request".to_string(),
            headers: HashMap::new(),
        },
    };

    return JsValue::from_serde(&response).unwrap();
}

async fn process_request(request_object: JsValue, routes: Vec<Route>) -> Result<Response, JsValue> {
    let request: Request = request_object.into_serde().map_err(|e| e.to_string())?;
    let conn = create_conn(request);
    let path = conn.path.clone();
    let method = conn.method.clone();
    match match_route(&routes, method, path) {
        None => Ok(Response {
            status: 404,
            body: "Not Found".to_string(),
            headers: HashMap::new(),
        }),
        Some(route) => match run_route(route, conn).await {
            Ok(conn) => Ok(conn_to_response(conn)),
            Err(_) => Ok(Response {
                status: 500,
                body: "Internal Server Error".to_string(),
                headers: HashMap::new(),
            }),
        },
    }
}

async fn run_route(route: &Route, conn: Conn) -> Result<Conn, ConfettiError> {
    let mut current_conn: Conn = conn;
    let middlewares = &route.middlewares[..];
    for middleware in middlewares {
        current_conn = (middleware.handler)(current_conn).await;
        if current_conn.halted {
            break;
        }
    }

    Ok(current_conn)
}