Created
January 19, 2016 19:07
-
-
Save clonejo/64c09bec272e2f85caa2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::any::Any; | |
| use std::cmp::min; | |
| use std::str; | |
| use db::DbCon; | |
| use db; | |
| use rustc_serialize::json::{Json, Object, ToJson}; | |
| use std::sync::{Arc, Mutex}; | |
| use std::io::Read; | |
| use model::{json_to_object, Action}; | |
| use hyper::server::{Server, Request, Response}; | |
| use hyper::header; | |
| use hyper::uri::RequestUri; | |
| use hyper::method::Method; | |
| use hyper::status::StatusCode; | |
| use hyper_router::{RouterBuilder, Route}; | |
| use route_recognizer::{Router, Match, Params}; | |
| fn check_authentication(req: &Request, password: &Option<&str>) -> bool { | |
| match *password { | |
| None => true, | |
| Some(pass_str) => { | |
| match req.headers.get::<header::Authorization<header::Basic>>() { | |
| Some(authorization) => true, | |
| None => false | |
| } | |
| } | |
| } | |
| } | |
| trait Handler: Sync + Send + Any { | |
| fn handle(&self, params: Params, req: Request, authenticated: bool, res: Response, con: Arc<Mutex<DbCon>>); | |
| } | |
| impl<F> Handler for F | |
| where F: Send + Sync + Any + Fn(Params, Request, bool, Response, Arc<Mutex<DbCon>>) { | |
| fn handle(&self, params: Params, req: Request, authenticated: bool, res: Response, con: Arc<Mutex<DbCon>>) { | |
| (*self)(params, req, authenticated, res, con); | |
| } | |
| } | |
| pub fn run(con: DbCon, listen: &str, password: Option<&str>) { | |
| let shared_con = Arc::new(Mutex::new(con)); | |
| let mut router: Router<(Method, Box<Handler>)> = Router::new(); | |
| router.add("/api/versions", (Method::Get, Box::new(api_versions))); | |
| router.add("/api/v0", (Method::Put, Box::new(create_action))); | |
| router.add("/api/v0/:type", (Method::Get, Box::new(query))); | |
| router.add("/api/v0/status/current", (Method::Get, Box::new(status_current))); | |
| Server::http(listen).unwrap().handle(move |req: Request, res: Response| { | |
| let match_result = { | |
| let path_str = match req.uri { | |
| RequestUri::AbsolutePath(ref p) => p, | |
| _ => panic!() | |
| }; | |
| router.recognize(&*path_str) | |
| }; | |
| match match_result { | |
| Ok(Match{ handler: tup, params: params }) => { | |
| let authenticated = { check_authentication(&req, &password) }; | |
| //let authenticated = true; | |
| let &(ref method, ref handler): &(Method, Box<Handler>) = tup; | |
| if *method == req.method { | |
| handler.handle(params, req, authenticated, res, shared_con.clone()); | |
| } else { | |
| handler_405(req, res); | |
| } | |
| }, | |
| Err(_) => | |
| handler_404(req, res) | |
| }; | |
| }).unwrap(); | |
| } | |
| fn handler_404(_req: Request, mut res: Response) { | |
| { | |
| let status = res.status_mut(); | |
| *status = StatusCode::NotFound; | |
| } | |
| res.send(b"Not Found\n"); | |
| } | |
| fn handler_405(_req: Request, mut res: Response) { | |
| { | |
| let status = res.status_mut(); | |
| *status = StatusCode::MethodNotAllowed; | |
| } | |
| res.send(b"Method Not Allowed\n"); | |
| } | |
| fn send_status(mut res: Response, status: StatusCode) { | |
| let s = res.status_mut(); | |
| *s = status; | |
| } | |
| fn send(mut res: Response, status: StatusCode, msg: &[u8]) { | |
| { | |
| let s = res.status_mut(); | |
| *s = status; | |
| } | |
| res.send(msg); | |
| } | |
| fn api_versions(_params: Params, _req: Request, authenticated: bool, mut res: Response, _shared_con: Arc<Mutex<DbCon>>) { | |
| let mut obj = Object::new(); | |
| obj.insert("versions".into(), [0].to_json()); | |
| { | |
| let headers = res.headers_mut(); | |
| headers.set(header::AccessControlAllowOrigin::Any); | |
| } | |
| let mut resp_str = obj.to_json().to_string(); | |
| resp_str.push('\n'); | |
| res.send(resp_str.as_bytes()); | |
| } | |
| /* | |
| * PUT | |
| */ | |
| fn create_action(params: Params, mut req: Request, authenticated: bool, res: Response, shared_con: Arc<Mutex<DbCon>>) { | |
| // TODO: check auth | |
| let mut action_buf = &mut [0; 1024]; | |
| // parse at maximum 1k bytes | |
| let bytes_read = req.read(action_buf).unwrap(); | |
| let (action_buf, _) = action_buf.split_at(bytes_read); | |
| let action_str = str::from_utf8(action_buf).unwrap(); | |
| match Json::from_str(action_str) { | |
| Err(_) => | |
| send_status(res, StatusCode::BadRequest), | |
| Ok(action_json) => { | |
| match json_to_object(action_json) { | |
| Ok(mut action) => { | |
| let con = shared_con.lock().unwrap(); | |
| action.store(&*con); | |
| let mut resp_str = format!("{}", action.get_base_action().id.unwrap()); | |
| resp_str.push('\n'); | |
| res.send(resp_str.as_bytes()); | |
| }, | |
| Err(msg) => { | |
| send(res, StatusCode::BadRequest, msg.as_bytes()); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /* | |
| * GET | |
| */ | |
| fn status_current(params: Params, req: Request, authenticated: bool, res: Response, shared_con: Arc<Mutex<DbCon>>) { | |
| //let public_api = req.headers.has("public"); | |
| let mut obj = Object::new(); | |
| let con = shared_con.lock().unwrap(); | |
| obj.insert("last".into(), db::status::get_last(&*con).unwrap().to_json()); | |
| obj.insert("changed".into(), db::status::get_last_changed(&*con).unwrap().to_json()); | |
| let mut resp_str = obj.to_json().to_string(); | |
| resp_str.push('\n'); | |
| res.send(resp_str.as_bytes()); | |
| // for non-authenticated API | |
| //Ok(Response::with((status::Ok, resp_str, modifiers::Header(headers::AccessControlAllowOrigin::Any)))) | |
| } | |
| fn query(params: Params, req: Request, authenticated: bool, res: Response, shared_con: Arc<Mutex<DbCon>>) { | |
| let count = 20; | |
| let count: u64 = min(count, 100); | |
| let mut obj = Object::new(); | |
| let con = shared_con.lock().unwrap(); | |
| let actions = db::query(count, &*con); | |
| obj.insert("actions".into(), actions.unwrap().to_json()); | |
| let mut resp_str = obj.to_json().to_string(); | |
| resp_str.push('\n'); | |
| res.send(resp_str.as_bytes()); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| RUST_BACKTRACE=1 cargo run -- -c example.conf | |
| Compiling clubstatusd v0.1.0 (file:///home/clonejo/code/clubstatusd) | |
| src/api.rs:51:35: 73:7 error: the type `[closure@src/api.rs:51:42: 73:6 router:route_recognizer::Router<(hyper::method::Method, Box<api::Handler + 'static>)>, password:core::option::Option<&str>, shared_con:alloc::arc::Arc<std::sync::mutex::Mutex<rusqlite::SqliteConnection>>]` does not fulfill the required lifetime [E0477] | |
| src/api.rs:51 Server::http(listen).unwrap().handle(move |req: Request, res: Response| { | |
| src/api.rs:52 let match_result = { | |
| src/api.rs:53 let path_str = match req.uri { | |
| src/api.rs:54 RequestUri::AbsolutePath(ref p) => p, | |
| src/api.rs:55 _ => panic!() | |
| src/api.rs:56 }; | |
| ... | |
| note: type must outlive the static lifetime | |
| error: aborting due to previous error | |
| Could not compile `clubstatusd`. | |
| To learn more, run the command again with --verbose. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment