diff --git a/examples/disk-auth-with-state.rs b/examples/disk-auth-with-state.rs
new file mode 100644
index 0000000..42c7cf1
--- /dev/null
+++ b/examples/disk-auth-with-state.rs
@@ -0,0 +1,63 @@
+use http::{Request, Response, StatusCode};
+use hyper::Body;
+use ratpack::{app::App, compose_handler, handler::Params, Error, HTTPResult, ServerError};
+
+async fn validate_authtoken(
+ req: Request
,
+ resp: Option>,
+ _params: Params,
+ app: App,
+) -> HTTPResult {
+ let token = req.headers().get("X-AuthToken");
+ if token.is_none() {
+ return Err(Error::StatusCode(StatusCode::UNAUTHORIZED));
+ }
+
+ let token = token.unwrap();
+
+ let state = app.state().await;
+ if state.is_none() {
+ return Err(Error::StatusCode(StatusCode::UNAUTHORIZED));
+ }
+
+ let state = state.unwrap();
+
+ if !(state.clone().lock().await.authtoken == token) {
+ return Err(Error::StatusCode(StatusCode::UNAUTHORIZED));
+ }
+
+ return Ok((req, resp));
+}
+
+async fn hello(
+ req: Request,
+ _resp: Option>,
+ params: Params,
+ _app: App,
+) -> HTTPResult {
+ let name = params.get("name").unwrap();
+ let bytes = Body::from(format!("hello, {}!\n", name));
+
+ return Ok((
+ req,
+ Some(Response::builder().status(200).body(bytes).unwrap()),
+ ));
+}
+
+#[derive(Clone)]
+struct State {
+ authtoken: &'static str,
+}
+
+#[tokio::main]
+async fn main() -> Result<(), ServerError> {
+ let mut app = App::with_state(State {
+ authtoken: "867-5309",
+ });
+ app.get("/auth/:name", compose_handler!(validate_authtoken, hello));
+ app.get("/:name", compose_handler!(hello));
+
+ app.serve("127.0.0.1:3000").await?;
+
+ Ok(())
+}
diff --git a/examples/disk-auth.rs b/examples/disk-auth.rs
index 244467d..0b31ed7 100644
--- a/examples/disk-auth.rs
+++ b/examples/disk-auth.rs
@@ -5,10 +5,14 @@ use ratpack::{app::App, compose_handler, handler::Params, Error, HTTPResult, Ser
const DEFAULT_AUTHTOKEN: &str = "867-5309";
const AUTHTOKEN_FILENAME: &str = "authtoken.secret";
+#[derive(Clone)]
+struct State;
+
async fn validate_authtoken(
req: Request,
resp: Option>,
_params: Params,
+ _app: App,
) -> HTTPResult {
let token = req.headers().get("X-AuthToken");
if token.is_none() {
@@ -32,7 +36,12 @@ async fn validate_authtoken(
return Ok((req, resp));
}
-async fn hello(req: Request, _resp: Option>, params: Params) -> HTTPResult {
+async fn hello(
+ req: Request,
+ _resp: Option>,
+ params: Params,
+ _app: App,
+) -> HTTPResult {
let name = params.get("name").unwrap();
let bytes = Body::from(format!("hello, {}!\n", name));
diff --git a/examples/hello-world.rs b/examples/hello-world.rs
index 52df2ea..ddf704d 100644
--- a/examples/hello-world.rs
+++ b/examples/hello-world.rs
@@ -2,7 +2,15 @@ use http::{Request, Response};
use hyper::Body;
use ratpack::{app::App, compose_handler, handler::Params, HTTPResult, ServerError};
-async fn hello(req: Request, _resp: Option>, params: Params) -> HTTPResult {
+#[derive(Clone)]
+struct State;
+
+async fn hello(
+ req: Request,
+ _resp: Option>,
+ params: Params,
+ _app: App,
+) -> HTTPResult {
let name = params.get("name").unwrap();
let bytes = Body::from(format!("hello, {}!\n", name));
diff --git a/examples/log.rs b/examples/log.rs
index 1a040b3..77a770b 100644
--- a/examples/log.rs
+++ b/examples/log.rs
@@ -3,12 +3,25 @@ use hyper::Body;
use log::LevelFilter;
use ratpack::{app::App, compose_handler, handler::Params, HTTPResult, ServerError};
-async fn log(req: Request, resp: Option>, _params: Params) -> HTTPResult {
+#[derive(Clone)]
+struct State;
+
+async fn log(
+ req: Request,
+ resp: Option>,
+ _params: Params,
+ _app: App,
+) -> HTTPResult {
log::trace!("New request: {}", req.uri().path());
Ok((req, resp))
}
-async fn hello(req: Request, _resp: Option>, params: Params) -> HTTPResult {
+async fn hello(
+ req: Request,
+ _resp: Option>,
+ params: Params,
+ _app: App,
+) -> HTTPResult {
let name = params.get("name").unwrap();
log::info!("Saying hello to {}", name);
let bytes = Body::from(format!("hello, {}!\n", name));
diff --git a/src/app.rs b/src/app.rs
index 6230bdd..1e70860 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,61 +1,74 @@
-use std::{convert::Infallible, net::SocketAddr};
+use std::{convert::Infallible, net::SocketAddr, sync::Arc};
use http::{Method, Request, Response, StatusCode};
use hyper::{server::conn::Http, service::service_fn, Body};
-use tokio::net::TcpListener;
+use tokio::{net::TcpListener, sync::Mutex};
use crate::{handler::Handler, router::Router, Error, ServerError};
#[derive(Clone)]
-pub struct App {
- router: Router,
+pub struct App {
+ router: Router,
+ global_state: Option>>,
}
-impl App {
+impl App {
pub fn new() -> Self {
Self {
router: Router::new(),
+ global_state: None,
}
}
- pub fn get(&mut self, path: &str, ch: Handler) {
+ pub fn with_state(state: S) -> Self {
+ Self {
+ router: Router::new(),
+ global_state: Some(Arc::new(Mutex::new(state))),
+ }
+ }
+
+ pub async fn state(&self) -> Option>> {
+ self.global_state.clone()
+ }
+
+ pub fn get(&mut self, path: &str, ch: Handler) {
self.router.add(Method::GET, path.to_string(), ch);
}
- pub fn post(&mut self, path: &str, ch: Handler) {
+ pub fn post(&mut self, path: &str, ch: Handler) {
self.router.add(Method::POST, path.to_string(), ch);
}
- pub fn delete(&mut self, path: &str, ch: Handler) {
+ pub fn delete(&mut self, path: &str, ch: Handler) {
self.router.add(Method::DELETE, path.to_string(), ch);
}
- pub fn put(&mut self, path: &str, ch: Handler) {
+ pub fn put(&mut self, path: &str, ch: Handler) {
self.router.add(Method::PUT, path.to_string(), ch);
}
- pub fn options(&mut self, path: &str, ch: Handler) {
+ pub fn options(&mut self, path: &str, ch: Handler) {
self.router.add(Method::OPTIONS, path.to_string(), ch);
}
- pub fn patch(&mut self, path: &str, ch: Handler) {
+ pub fn patch(&mut self, path: &str, ch: Handler) {
self.router.add(Method::PATCH, path.to_string(), ch);
}
- pub fn head(&mut self, path: &str, ch: Handler) {
+ pub fn head(&mut self, path: &str, ch: Handler) {
self.router.add(Method::HEAD, path.to_string(), ch);
}
- pub fn connect(&mut self, path: &str, ch: Handler) {
+ pub fn connect(&mut self, path: &str, ch: Handler) {
self.router.add(Method::CONNECT, path.to_string(), ch);
}
- pub fn trace(&mut self, path: &str, ch: Handler) {
+ pub fn trace(&mut self, path: &str, ch: Handler) {
self.router.add(Method::TRACE, path.to_string(), ch);
}
pub async fn dispatch(&self, req: Request) -> Result, Infallible> {
- match self.router.dispatch(req).await {
+ match self.router.dispatch(req, self.clone()).await {
Ok(resp) => Ok(resp),
Err(e) => match e {
Error::StatusCode(sc) => Ok(Response::builder()
diff --git a/src/handler.rs b/src/handler.rs
index 425e64c..ce8417e 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -1,6 +1,6 @@
use std::{collections::BTreeMap, future::Future};
-use crate::{HTTPResult, PinBox};
+use crate::{app::App, HTTPResult, PinBox};
use async_recursion::async_recursion;
use http::{Request, Response};
@@ -8,23 +8,25 @@ use hyper::Body;
pub type Params = BTreeMap;
-pub type HandlerFunc = fn(
+pub type HandlerFunc = fn(
req: Request,
response: Option>,
params: Params,
+ app: App,
) -> PinBox + Send>;
#[derive(Clone)]
-pub struct Handler {
- handler: HandlerFunc,
- next: Box