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;
use rocket::Rocket;
#[route(GET, path = "/")]
fn simple() -> &'static str {
"Hello, simple example world! How is thou?"
}
#[route(GET, path = "/<name>")]
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]);
}

View File

@ -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<Route<'static, 'static>> // 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();
}

View File

@ -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)
}

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

View File

@ -42,7 +42,7 @@ pub fn routes_macro(ecx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
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();
MacEager::expr(ecx.expr_vec_slice(sp, path_exprs))
}