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
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::collections::HashMap;
use std::io::Cursor;
use tiny_http::{Request, Response};

// Implement a middleware system from scratch
// Notionally, this is a list of before/after hooks for each route
// We also associate a generic before/after hook list.

pub enum Responsa {
    // Nothing yet.
    None,
    // It all goes over the wire as bytes.
    // Write your own layer of serde that talks bytes.
    Exists(Response<Cursor<Vec<u8>>>)
}

pub struct CallFrame<'a> {
    pub req: &'a mut Request,
    pub resp: Responsa,
    // Abnormal end.
    pub abend: bool,
    // To share among the middleware bits.
    pub kv: HashMap<String, String>
}

pub struct Middleware
{
    pub generic_before: Vec<fn(&mut CallFrame)>,
    pub generic_after: Vec<fn(&mut CallFrame)>,

    //route_before: HashMap<String, Vec<Fn(&mut CallFrame) -> ()>>,
    //route_after: HashMap<String, Vec<Fn(&mut CallFrame) -> ()>>
}

impl Middleware {
    pub fn new() -> Middleware {
        Middleware {
            generic_before: Vec::new(),
            generic_after: Vec::new(),
        }
    }
}


pub struct RouteTable {
    pub table: HashMap<String, fn(&mut CallFrame)>
}

impl RouteTable {
    pub fn new() -> RouteTable {
        RouteTable {
            table: HashMap::new()
        }
    }
}

// On initial request, we take a Request, formulate it into a
// CallFrame, and trundle it along the Middleware lists.  Design here
// is a specialized lift from the Common Lisp Object System
// "before/after".
//
// The order is:
//
// Generic Befores, Specific Befores, Handler, Specific Afters,
// Generic Afters.


// Linear. One process() per request.
// Takes ownership of request
pub fn process(handlers: &RouteTable, mw: &Middleware, mut req: Request) -> () {
    let route = req.url();
    let mut collect_funcs: Vec<fn(&mut CallFrame)> = Vec::new();
    collect_funcs.extend_from_slice(&mw.generic_before);
    //collect_funcs.add(mw.routeBefore.get(route));
    match  handlers.table.get(route) {
        None => {
            // Problem
        }
        Some(r) => {
            collect_funcs.push(*r);
        }
    }

    //collect_funcs.add(mw.routeAfter.get(route));
    let mut cf = CallFrame { req: &mut req,
                             resp: Responsa::None,
                             kv: HashMap::new(),
                             abend: false };
    for f in collect_funcs {
        // STATE MUTATION.
        f(&mut cf);
        if cf.abend {
            break;
        }
    }
    // Logging, timing, etc
    for f in &mw.generic_after {
        f(&mut cf);
    }
    match cf.resp {
        Responsa::Exists(r) => {
            req.respond(r);

        }
        Responsa::None => {}
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}