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!
This commit is contained in:
Sergio Benitez 2016-03-15 00:41:22 -07:00
parent 4d4985a0e7
commit dcb150bde7
6 changed files with 103 additions and 26 deletions

View File

@ -4,6 +4,11 @@
extern crate rocket; extern crate rocket;
use rocket::Rocket; use rocket::Rocket;
#[route(GET, path = "/")]
fn simple() -> &'static str {
"Hello, simple example world! How is thou?"
}
#[route(GET, path = "/<name>")] #[route(GET, path = "/<name>")]
fn hello(name: String) -> String { fn hello(name: String) -> String {
format!("Hello, {}!", name) format!("Hello, {}!", name)
@ -16,5 +21,5 @@ fn bye(x: usize, y: usize) -> String {
fn main() { fn main() {
let rocket = Rocket::new("localhost", 8000); let rocket = Rocket::new("localhost", 8000);
rocket.mount_and_launch("/", routes![hello, bye]); rocket.mount_and_launch("/", routes![simple, hello, bye]);
} }

View File

@ -5,9 +5,11 @@ mod error;
mod response; mod response;
mod request; mod request;
use std::io::Write;
pub use method::Method; pub use method::Method;
pub use error::Error; pub use error::Error;
pub use response::Response; pub use response::{Body, Response};
pub use request::Request; pub use request::Request;
use hyper::server::Handler as HypHandler; use hyper::server::Handler as HypHandler;
@ -16,27 +18,41 @@ use hyper::server::Response as HypResponse;
use hyper::net::Fresh as HypFresh; use hyper::net::Fresh as HypFresh;
use hyper::Server; use hyper::Server;
pub type Handler = fn(Request) -> Response; pub type Handler<'a> = fn(Request) -> Response<'a>;
#[allow(dead_code)] #[allow(dead_code)]
pub struct Route<'a> { #[derive(Clone)]
pub struct Route<'a, 'b> {
pub method: Method, pub method: Method,
pub path: &'a str, pub path: &'a str,
pub handler: Handler pub handler: Handler<'b>
} }
#[allow(dead_code)] #[allow(dead_code)]
pub struct Rocket { pub struct Rocket {
address: &'static str, address: &'static str,
port: isize, port: isize,
handler: Option<Route<'static, 'static>> // just for testing
// mounts: HashMap<&'static str, Route<'a>> // mounts: HashMap<&'static str, Route<'a>>
} }
impl HypHandler for Rocket { impl HypHandler for Rocket {
fn handle<'a, 'k>(&'a self, req: HypRequest<'a, 'k>, fn handle<'a, 'k>(&'a self, req: HypRequest<'a, 'k>,
res: HypResponse<'a, HypFresh>) { mut res: HypResponse<'a, HypFresh>) {
println!("Request: {:?}", req.uri); 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 { pub fn new(address: &'static str, port: isize) -> Rocket {
Rocket { Rocket {
address: address, 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); println!("🛰 Mounting '{}':", base);
for route in routes { 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); println!("\t* {} '{}'", route.method, route.path);
} }
self 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.mount(base, routes);
self.launch(); self.launch();
} }

View File

@ -4,6 +4,10 @@ use error::Error;
pub struct Request; pub struct Request;
impl Request { impl Request {
pub fn empty() -> Request {
Request
}
pub fn get_param_str(&self, name: &str) -> Result<&str, Error> { pub fn get_param_str(&self, name: &str) -> Result<&str, Error> {
Err(Error::NoKey) Err(Error::NoKey)
} }

View File

@ -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 { pub enum Body<'a> {
fn from(_s: &'a str) -> Self { Bytes(&'a [u8]),
Response Str(&'a str),
String(String),
Stream(Box<Read>),
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
} }
} }
impl From<String> for Response { pub fn not_found() -> Response<'a> {
fn from(_s: String) -> Self { Response {
Response status: StatusCode::NotFound,
headers: Headers::new(),
body: Body::Empty
} }
} }
impl Response { pub fn server_error() -> Response<'a> {
pub fn error(number: usize) -> Response { Response {
println!("ERROR {}!", number); status: StatusCode::InternalServerError,
Response headers: Headers::new(),
body: Body::Empty
}
}
}
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<'a> From<String> 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)
}
} }
} }

View File

@ -189,9 +189,9 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
for param in &fn_params { for param in &fn_params {
let param_ident = str_to_ident(param.as_str()); let param_ident = str_to_ident(param.as_str());
fn_param_exprs.push(quote_stmt!(ecx, 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, Ok(v) => v,
Err(_) => return rocket::Response::error(200) Err(_) => return rocket::Response::not_found()
}; };
).unwrap()); ).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 route_fn_name = prepend_ident(FN_PREFIX, &item.ident);
let fn_name = item.ident; let fn_name = item.ident;
let route_fn_item = quote_item!(ecx, 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 $fn_param_exprs
let result = $fn_name($fn_param_idents); let result = $fn_name($fn_param_idents);
rocket::Response::from(result) 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); let method = method_variant_to_expr(ecx, route_params.method);
push(Annotatable::Item(quote_item!(ecx, push(Annotatable::Item(quote_item!(ecx,
#[allow(non_upper_case_globals)] #[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, method: $method,
path: $path, path: $path,
handler: $route_fn_name handler: $route_fn_name

View File

@ -42,7 +42,7 @@ pub fn routes_macro(ecx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
last_seg.identifier = new_ident; last_seg.identifier = new_ident;
} }
// Build up the P<Expr> for each &path. // Build up the P<Expr> for each path.
let path_exprs = paths.iter().map(|p| { quote_expr!(ecx, &$p) }).collect(); let path_exprs = paths.iter().map(|p| { quote_expr!(ecx, &$p) }).collect();
MacEager::expr(ecx.expr_vec_slice(sp, path_exprs)) MacEager::expr(ecx.expr_vec_slice(sp, path_exprs))
} }