use std::rc::Rc; use std::string::ToString; use std::collections::HashMap; use route_recognizer::Router; use task::Task; use route::{Payload, RouteHandler}; use router::HttpHandler; use resource::HttpResource; use httpmessage::HttpRequest; /// Application pub struct HttpApplication { state: S, default: HttpResource, resources: HashMap>, } impl HttpApplication where S: 'static { pub(crate) fn prepare(self, prefix: String) -> Box { let mut router = Router::new(); let prefix = if prefix.ends_with('/') {prefix } else { prefix + "/" }; for (path, handler) in self.resources { let path = prefix.clone() + path.trim_left_matches('/'); router.add(path.as_str(), handler); } Box::new( InnerApplication { state: Rc::new(self.state), default: self.default, router: router } ) } } impl HttpApplication<()> { /// Create `HttpApplication` with no state pub fn no_state() -> Self { HttpApplication { state: (), default: HttpResource::default(), resources: HashMap::new(), } } } impl HttpApplication where S: 'static { /// Create http application with specific state. State is shared with all /// routes within same application and could be /// accessed with `HttpContext::state()` method. pub fn new(state: S) -> HttpApplication { HttpApplication { state: state, default: HttpResource::default(), resources: HashMap::new(), } } /// Add resource by path. pub fn add(&mut self, path: P) -> &mut HttpResource { let path = path.to_string(); // add resource if !self.resources.contains_key(&path) { self.resources.insert(path.clone(), HttpResource::default()); } self.resources.get_mut(&path).unwrap() } /// Default resource is used if no matched route could be found. pub fn default(&mut self) -> &mut HttpResource { &mut self.default } } pub(crate) struct InnerApplication { state: Rc, default: HttpResource, router: Router>, } impl HttpHandler for InnerApplication { fn handle(&self, req: HttpRequest, payload: Option) -> Task { if let Ok(h) = self.router.recognize(req.path()) { h.handler.handle(req.with_params(h.params), payload, Rc::clone(&self.state)) } else { self.default.handle(req, payload, Rc::clone(&self.state)) } } }