From dcb150bde7f69232760103abe6080566aa034823 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Tue, 15 Mar 2016 00:41:22 -0700 Subject: [PATCH] Something works! A simple hacked-up handler, that is. At the moment, I simply install the first route I see into the Rocket struct directly. This is quite terrible. What's worse is that I assume that the Route's path and handler are static! The handler, actually, does have to be static, but its response may have whatever (valid) lifetime, though I'm not sure anything but `static makes sense. I'll think about it. In any case, the weird `static` restrictions need to be removed, and I need to think about which lifetimes are safe here. IE: Must all routes be static? Can I use a closure as a route? (that'd be neat). If so, how do we make that work? In any case, it's nice to see SOMETHING work. Yay! --- examples/hello/src/main.rs | 7 +++- lib/src/lib.rs | 39 +++++++++++++++----- lib/src/request.rs | 4 ++ lib/src/response.rs | 69 +++++++++++++++++++++++++++++------ macros/src/route_decorator.rs | 8 ++-- macros/src/routes_macro.rs | 2 +- 6 files changed, 103 insertions(+), 26 deletions(-) diff --git a/examples/hello/src/main.rs b/examples/hello/src/main.rs index dd22479a..27899282 100644 --- a/examples/hello/src/main.rs +++ b/examples/hello/src/main.rs @@ -4,6 +4,11 @@ extern crate rocket; use rocket::Rocket; +#[route(GET, path = "/")] +fn simple() -> &'static str { + "Hello, simple example world! How is thou?" +} + #[route(GET, path = "/")] fn hello(name: String) -> String { format!("Hello, {}!", name) @@ -16,5 +21,5 @@ fn bye(x: usize, y: usize) -> String { fn main() { let rocket = Rocket::new("localhost", 8000); - rocket.mount_and_launch("/", routes![hello, bye]); + rocket.mount_and_launch("/", routes![simple, hello, bye]); } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index f3d2d299..6071abf7 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -5,9 +5,11 @@ mod error; mod response; mod request; +use std::io::Write; + pub use method::Method; pub use error::Error; -pub use response::Response; +pub use response::{Body, Response}; pub use request::Request; use hyper::server::Handler as HypHandler; @@ -16,27 +18,41 @@ use hyper::server::Response as HypResponse; use hyper::net::Fresh as HypFresh; use hyper::Server; -pub type Handler = fn(Request) -> Response; +pub type Handler<'a> = fn(Request) -> Response<'a>; #[allow(dead_code)] -pub struct Route<'a> { +#[derive(Clone)] +pub struct Route<'a, 'b> { pub method: Method, pub path: &'a str, - pub handler: Handler + pub handler: Handler<'b> } #[allow(dead_code)] pub struct Rocket { address: &'static str, port: isize, + handler: Option> // just for testing // mounts: HashMap<&'static str, Route<'a>> } impl HypHandler for Rocket { fn handle<'a, 'k>(&'a self, req: HypRequest<'a, 'k>, - res: HypResponse<'a, HypFresh>) { + mut res: HypResponse<'a, HypFresh>) { println!("Request: {:?}", req.uri); - res.send(b"Hello World!").unwrap(); + if self.handler.is_some() { + let response = (self.handler.as_ref().unwrap().handler)(Request::empty()); + *(res.headers_mut()) = response.headers; + *(res.status_mut()) = response.status; + match response.body { + Body::Str(string) => { + let mut stream = res.start().unwrap(); + stream.write_all(string.as_bytes()).unwrap(); + stream.end(); + } + _ => println!("UNIMPLEMENTED") + } + } } } @@ -44,20 +60,25 @@ impl Rocket { pub fn new(address: &'static str, port: isize) -> Rocket { Rocket { address: address, - port: port + port: port, + handler: None } } - pub fn mount(&mut self, base: &str, routes: &[&Route]) -> &mut Self { + pub fn mount(&mut self, base: &str, routes: &[&Route<'static, 'static>]) -> &mut Self { println!("🛰 Mounting '{}':", base); for route in routes { + if self.handler.is_none() { + println!("\t* INSTALLED: {} '{}'", route.method, route.path); + self.handler = Some((*route).clone()); + } println!("\t* {} '{}'", route.method, route.path); } self } - pub fn mount_and_launch(mut self, base: &str, routes: &[&Route]) { + pub fn mount_and_launch(mut self, base: &str, routes: &[&Route<'static, 'static>]) { self.mount(base, routes); self.launch(); } diff --git a/lib/src/request.rs b/lib/src/request.rs index 1648c5ed..e88bbab1 100644 --- a/lib/src/request.rs +++ b/lib/src/request.rs @@ -4,6 +4,10 @@ use error::Error; pub struct Request; impl Request { + pub fn empty() -> Request { + Request + } + pub fn get_param_str(&self, name: &str) -> Result<&str, Error> { Err(Error::NoKey) } diff --git a/lib/src/response.rs b/lib/src/response.rs index 245b9523..0cd1da46 100644 --- a/lib/src/response.rs +++ b/lib/src/response.rs @@ -1,20 +1,67 @@ -pub struct Response; +pub use hyper::status::StatusCode; +pub use hyper::header::{self, Headers}; +use std::io::Read; -impl<'a> From<&'a str> for Response { - fn from(_s: &'a str) -> Self { - Response +pub enum Body<'a> { + Bytes(&'a [u8]), + Str(&'a str), + String(String), + Stream(Box), + Empty +} + +pub struct Response<'a> { + pub status: StatusCode, + pub headers: Headers, + pub body: Body<'a> +} + +impl<'a> Response<'a> { + pub fn empty() -> Response<'a> { + Response { + status: StatusCode::Ok, + headers: Headers::new(), + body: Body::Empty + } + } + + pub fn not_found() -> Response<'a> { + Response { + status: StatusCode::NotFound, + headers: Headers::new(), + body: Body::Empty + } + } + + pub fn server_error() -> Response<'a> { + Response { + status: StatusCode::InternalServerError, + headers: Headers::new(), + body: Body::Empty + } } } -impl From for Response { - fn from(_s: String) -> Self { - Response +impl<'a> From<&'a str> for Response<'a> { + fn from(s: &'a str) -> Self { + let mut headers = Headers::new(); + headers.set(header::ContentLength(s.len() as u64)); + Response { + status: StatusCode::Ok, + headers: headers, + body: Body::Str(s) + } } } -impl Response { - pub fn error(number: usize) -> Response { - println!("ERROR {}!", number); - Response +impl<'a> From for Response<'a> { + fn from(s: String) -> Self { + let mut headers = Headers::new(); + headers.set(header::ContentLength(s.len() as u64)); + Response { + status: StatusCode::Ok, + headers: headers, + body: Body::String(s) + } } } diff --git a/macros/src/route_decorator.rs b/macros/src/route_decorator.rs index 83d594ae..474296af 100644 --- a/macros/src/route_decorator.rs +++ b/macros/src/route_decorator.rs @@ -189,9 +189,9 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem, for param in &fn_params { let param_ident = str_to_ident(param.as_str()); fn_param_exprs.push(quote_stmt!(ecx, - let $param_ident = match req.get_param($param) { + let $param_ident = match _req.get_param($param) { Ok(v) => v, - Err(_) => return rocket::Response::error(200) + Err(_) => return rocket::Response::not_found() }; ).unwrap()); } @@ -209,7 +209,7 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem, let route_fn_name = prepend_ident(FN_PREFIX, &item.ident); let fn_name = item.ident; let route_fn_item = quote_item!(ecx, - fn $route_fn_name(req: rocket::Request) -> rocket::Response { + fn $route_fn_name<'a>(_req: rocket::Request) -> rocket::Response<'a> { $fn_param_exprs let result = $fn_name($fn_param_idents); rocket::Response::from(result) @@ -223,7 +223,7 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem, let method = method_variant_to_expr(ecx, route_params.method); push(Annotatable::Item(quote_item!(ecx, #[allow(non_upper_case_globals)] - pub static $struct_name: rocket::Route<'static> = rocket::Route { + pub static $struct_name: rocket::Route<'static, 'static> = rocket::Route { method: $method, path: $path, handler: $route_fn_name diff --git a/macros/src/routes_macro.rs b/macros/src/routes_macro.rs index ee766b77..c16e0510 100644 --- a/macros/src/routes_macro.rs +++ b/macros/src/routes_macro.rs @@ -42,7 +42,7 @@ pub fn routes_macro(ecx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) last_seg.identifier = new_ident; } - // Build up the P for each &path. + // Build up the P for each path. let path_exprs = paths.iter().map(|p| { quote_expr!(ecx, &$p) }).collect(); MacEager::expr(ecx.expr_vec_slice(sp, path_exprs)) }