| 1 | 1 | extern crate hyper; | 
| 2 | 2 |  | 
| 3 |  | // use std::io::Write; | 
| 4 |  |  | 
| 5 | 3 | use hyper::Server; | 
| 6 |  | use hyper::server::{ Request,Response}; | 
|  | 4 | use hyper::server::{Handler,Request,Response}; | 
| 7 | 5 | use hyper::net::Fresh; | 
| 8 | 6 |  | 
| 9 |  | #[derive(Debug, Clone)] | 
| 10 |  | struct Delegate { | 
| 11 |  | name: String, | 
|  | 7 | use std::env::{args,current_dir,set_current_dir}; | 
|  | 8 | use std::fs::{File,read_dir}; | 
|  | 9 | use std::io::prelude::Read; | 
|  | 10 | use std::iter::Iterator; | 
|  | 11 | use std::path::Path; | 
|  | 12 |  | 
|  | 13 | mod matching; | 
|  | 14 |  | 
|  | 15 | #[derive(Debug)] | 
|  | 16 | enum AloysError { | 
|  | 17 | IOError(std::io::Error), | 
|  | 18 | HyperError(hyper::error::Error), | 
|  | 19 | } | 
|  | 20 |  | 
|  | 21 | impl From<std::io::Error> for AloysError { | 
|  | 22 | fn from(e: std::io::Error) -> AloysError { | 
|  | 23 | AloysError::IOError(e) | 
|  | 24 | } | 
|  | 25 | } | 
|  | 26 |  | 
|  | 27 | impl From<hyper::error::Error> for AloysError { | 
|  | 28 | fn from(e: hyper::error::Error) -> AloysError { | 
|  | 29 | AloysError::HyperError(e) | 
|  | 30 | } | 
| 12 | 31 | } | 
| 13 | 32 |  | 
| 14 | 33 | #[derive(Debug, Clone)] | 
| 15 |  | struct PathSpec { | 
| 16 |  | forPath:    Option<String>, | 
| 17 |  | forDomain:  Option<String>, | 
| 18 |  | delegateTo: Delegate, | 
|  | 34 | enum Delegate { | 
|  | 35 | Forward(HTTPForward), | 
|  | 36 | Defer(Routes), | 
| 19 | 37 | } | 
| 20 | 38 |  | 
| 21 |  | fn find_delegate(req: Request, delegates: Vec<PathSpec>) -> Option<Delegate> { | 
| 22 |  | for d in delegates.iter() { | 
| 23 |  | if let Some(ref domain) = d.forDomain { | 
| 24 |  | } | 
| 25 |  | if let Some(ref path) = d.forPath { | 
|  | 39 | #[derive(Debug, Clone)] | 
|  | 40 | struct HTTPForward { | 
|  | 41 | domn: String, | 
|  | 42 | port: u32, | 
|  | 43 | } | 
|  | 44 |  | 
|  | 45 | #[derive(Debug, Clone)] | 
|  | 46 | struct RouteSpec { | 
|  | 47 | for_path:    Option<String>, | 
|  | 48 | for_domain:  Option<String>, | 
|  | 49 | delegate_to: Delegate, | 
|  | 50 | } | 
|  | 51 |  | 
|  | 52 | #[derive(Debug, Clone)] | 
|  | 53 | struct Routes { | 
|  | 54 | routes: Vec<RouteSpec>, | 
|  | 55 | } | 
|  | 56 |  | 
|  | 57 | fn with_file_contents<A, F>(path: &Path, default: A, callback: F) -> A | 
|  | 58 | where F: FnOnce(String) -> A + 'static { | 
|  | 59 | match File::open(path) { | 
|  | 60 | Ok(mut f)  => { | 
|  | 61 | let mut s = String::new(); | 
|  | 62 | match f.read_to_string(&mut s) { | 
|  | 63 | Ok(_) => callback(s), | 
|  | 64 | Err(_) => default, | 
|  | 65 | } | 
|  | 66 | }, | 
|  | 67 | Err(_) => default, | 
|  | 68 | } | 
|  | 69 | } | 
|  | 70 |  | 
|  | 71 | impl RouteSpec { | 
|  | 72 | fn from_path(dir: &Path) -> Result<RouteSpec,AloysError> { | 
|  | 73 | let path   = with_file_contents(&dir.join("path"), None, |s| Some(s)); | 
|  | 74 | let domain = with_file_contents(&dir.join("domain"), None, |s| Some(s)); | 
|  | 75 | let mode   = with_file_contents(&dir.join("mode"), "http", |s| s); | 
|  | 76 | if mode == "http" { | 
|  | 77 | } else if mode == "alyos" { | 
|  | 78 | let fwd = with_file_contents(&dir.join("conf"), | 
|  | 79 | Path::new(&"/dev/null"), | 
|  | 80 | |s| Path::new(&s)); | 
|  | 81 | let rts = try!(Routes::load_paths(fwd)); | 
|  | 82 | Ok(RouteSpec { for_path: path, | 
|  | 83 | for_domain: domain, | 
|  | 84 | delegate_to: Delegate:: | 
|  | 85 | } else { | 
| 26 | 86 |  | 
| 27 | 87 | } | 
| 28 |  | return Some(d.delegateTo.clone()); | 
|  | 88 | // let forPath = match File::open(dir.join("path")) { | 
|  | 89 | //     Ok(f) => {}; | 
|  | 90 | //     Err | 
|  | 91 | // }; | 
|  | 92 | Ok(RouteSpec { for_path: None, | 
|  | 93 | for_domain: None, | 
|  | 94 | delegate_to: Delegate::Defer(Routes { routes: vec![] }), | 
|  | 95 | }) | 
| 29 | 96 | } | 
| 30 |  | return None; | 
| 31 | 97 | } | 
| 32 | 98 |  | 
| 33 |  | fn dispatch(req: Request, res: Response<Fresh>, delegates: Vec<PathSpec>) { | 
| 34 |  | println!("{:?}", req.headers); | 
| 35 |  | res.send(b"Unhandled request.").unwrap(); | 
|  | 99 | impl Routes { | 
|  | 100 | fn load_paths(dir: &Path) -> Result<Routes,AloysError> { | 
|  | 101 | let mut routes = vec![]; | 
|  | 102 | for entry in try!(read_dir(dir)) { | 
|  | 103 | let entry_path = try!(entry).path(); | 
|  | 104 | routes.push(try!(RouteSpec::from_path(entry_path.as_path()))); | 
|  | 105 | } | 
|  | 106 | Ok(Routes { routes: routes }) | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | fn dispatch(&self, req: &Request, res: Response<Fresh>) { | 
|  | 110 | match self.find_delegate(&req) { | 
|  | 111 | Some(delegate) => delegate.run(req, res), | 
|  | 112 | None => { | 
|  | 113 | let _ = res.send(b"[no matching handler]"); | 
|  | 114 | }, | 
|  | 115 | } | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 | fn find_delegate(&self, req: &Request) -> Option<&Delegate> { | 
|  | 119 | for d in self.routes.iter() { | 
|  | 120 | if let Some(ref d) = d.for_domain { | 
|  | 121 | println!("Matching against {:?}", d); | 
|  | 122 | } | 
|  | 123 | if let Some(ref p) = d.for_path { | 
|  | 124 | println!("Matching against {:?}", p); | 
|  | 125 | } | 
|  | 126 | return Some(&d.delegate_to); | 
|  | 127 | } | 
|  | 128 | return None; | 
|  | 129 | } | 
| 36 | 130 | } | 
| 37 | 131 |  | 
| 38 |  | fn hello(req: Request, res: Response<Fresh>) { | 
| 39 |  | res.send(b"Unhandled request.").unwrap(); | 
|  | 132 | impl Handler for Routes { | 
|  | 133 | fn handle(&self, req: Request, res: Response<Fresh>) { | 
|  | 134 | self.dispatch(&req, res); | 
|  | 135 | } | 
|  | 136 | } | 
|  | 137 |  | 
|  | 138 | impl Delegate { | 
|  | 139 | fn run(&self, req: &Request, res: Response<Fresh>) { | 
|  | 140 | match self { | 
|  | 141 | &Delegate::Forward(_) => { | 
|  | 142 | let _ = res.send(b"[matched by me!]"); | 
|  | 143 | }, | 
|  | 144 | &Delegate::Defer(ref rts) => { | 
|  | 145 | rts.dispatch(req, res); | 
|  | 146 | }, | 
|  | 147 | } | 
|  | 148 | } | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 |  | 
|  | 152 | fn run_server() -> Result<(), AloysError> { | 
|  | 153 | if let Some(target_dir) = args().next() { | 
|  | 154 | println!("switching to directory {:}", target_dir); | 
|  | 155 | try!(set_current_dir(Path::new(&target_dir))); | 
|  | 156 | } | 
|  | 157 | let cwd = try!(current_dir()); | 
|  | 158 | let paths = try!(Routes::load_paths(cwd.as_path())); | 
|  | 159 | let srv = try!(Server::http("127.0.0.1:8080")); | 
|  | 160 | let _ = srv.handle(paths); | 
|  | 161 | Ok(()) | 
| 40 | 162 | } | 
| 41 | 163 |  | 
| 42 | 164 | fn main() { | 
| 43 |  | let sample: Vec<PathSpec> = vec![ | 
| 44 |  | PathSpec { forPath: None, | 
| 45 |  | forDomain: None, | 
| 46 |  | delegateTo: Delegate { name: "default".to_owned() } } ]; | 
| 47 |  | match Server::http("127.0.0.1:8080") { | 
| 48 |  | Ok(s) => { | 
| 49 |  | let _ = s.handle(hello); | 
| 50 |  | } | 
| 51 |  | Err(e) => { | 
| 52 |  | println!("Unable to run server: {:?}", e); | 
| 53 |  | } | 
| 54 |  | } | 
|  | 165 | match run_server() { | 
|  | 166 | Ok(_) => (), | 
|  | 167 | Err(e) => println!("Got error: {:?}", e), | 
|  | 168 | }; | 
| 55 | 169 | } |