forked from richerarc/saphir
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Macro generation for contollers: richerarc#62 (richerarc#65)
* saphir_macro: Macros now generate dispatches correctly * Fixed doc comments * Moved handler functions to handler file * Added HandlerAttrs type * Parse guard meta * Working guard macro * Added generation of wrapper fn and auto loading of body for sync fns * marco v1.0.0-beta & saphir v2.0.0-beta * Fixed warnings + runned rustfmt * Applied a couple of clippy fixes Co-authored-by: Luc Fauvel <[email protected]>
- Loading branch information
Showing
25 changed files
with
1,250 additions
and
476 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
/target | ||
**/target | ||
**/*.rs.bk | ||
.idea/ | ||
*.lock | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,5 @@ | ||
[package] | ||
name = "saphir" | ||
version = "2.0.0-alpha4" | ||
edition = "2018" | ||
authors = ["Richer Archambault <[email protected]>"] | ||
description = "Fully async-await http server framework" | ||
documentation = "https://docs.rs/saphir" | ||
homepage = "https://github.com/richerarc/saphir" | ||
repository = "https://github.com/richerarc/saphir" | ||
readme = "README.md" | ||
keywords = ["hyper", "http", "server", "web", "async"] | ||
license = "MIT" | ||
|
||
[features] | ||
|
||
default = [] | ||
https = ["base64", "rustls", "tokio-rustls"] | ||
json = ["serde", "serde_json"] | ||
form = ["serde", "serde_urlencoded"] | ||
|
||
[dependencies] | ||
log = "0.4" | ||
hyper = "0.13" | ||
tokio = { version = "0.2", features = ["full"] } | ||
futures = "0.3" | ||
futures-util = "0.3" | ||
tower-service = "0.3" | ||
cookie = { package = "saphir-cookie", version = "0.13" } | ||
http = "0.2" | ||
http-body = "0.3" | ||
parking_lot = "0.10" | ||
regex = "1.3" | ||
rustls = { version = "0.17", optional = true } | ||
tokio-rustls = { version = "0.13", optional = true } | ||
base64 = { version = "0.11", optional = true } | ||
serde = { version = "1.0", optional = true } | ||
serde_json = { version = "1.0", optional = true } | ||
serde_urlencoded = { version = "0.6", optional = true } | ||
|
||
[dev-dependencies] | ||
tokio-timer = "0.2.13" | ||
env_logger = "0.7" | ||
serde = "1.0" | ||
serde_derive = "1.0" | ||
[workspace] | ||
members = [ | ||
"saphir", | ||
"saphir_macro", | ||
] |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
reorder_imports = true | ||
merge_imports = true | ||
max_width = 160 |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
[package] | ||
name = "saphir" | ||
version = "2.0.0-beta" | ||
edition = "2018" | ||
authors = ["Richer Archambault <[email protected]>"] | ||
description = "Fully async-await http server framework" | ||
documentation = "https://docs.rs/saphir" | ||
homepage = "https://github.com/richerarc/saphir" | ||
repository = "https://github.com/richerarc/saphir" | ||
readme = "README.md" | ||
keywords = ["hyper", "http", "server", "web", "async"] | ||
license = "MIT" | ||
|
||
[features] | ||
|
||
default = [] | ||
https = ["base64", "rustls", "tokio-rustls"] | ||
json = ["serde", "serde_json"] | ||
form = ["serde", "serde_urlencoded"] | ||
|
||
[dependencies] | ||
log = "0.4" | ||
hyper = "0.13" | ||
tokio = { version = "0.2", features = ["full"] } | ||
futures = "0.3" | ||
futures-util = "0.3" | ||
tower-service = "0.3" | ||
cookie = { package = "saphir-cookie", version = "0.13" } | ||
http = "0.2" | ||
http-body = "0.3" | ||
parking_lot = "0.10" | ||
regex = "1.3" | ||
rustls = { version = "0.17", optional = true } | ||
tokio-rustls = { version = "0.13", optional = true } | ||
base64 = { version = "0.11", optional = true } | ||
serde = { version = "1.0", optional = true } | ||
serde_json = { version = "1.0", optional = true } | ||
serde_urlencoded = { version = "0.6", optional = true } | ||
|
||
[dev-dependencies] | ||
tokio-timer = "0.2.13" | ||
env_logger = "0.7" | ||
serde = "1.0" | ||
serde_derive = "1.0" | ||
saphir_macro = { path = "../saphir_macro", version = "1.0.0-beta"} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ extern crate log; | |
|
||
use futures::future::Ready; | ||
use saphir::prelude::*; | ||
use serde_derive::{Serialize, Deserialize}; | ||
use serde_derive::{Deserialize, Serialize}; | ||
use tokio::sync::RwLock; | ||
|
||
// == controller == // | ||
|
@@ -28,14 +28,14 @@ impl Controller for MagicController { | |
let b = EndpointsBuilder::new(); | ||
|
||
#[cfg(feature = "json")] | ||
let b = b.add(Method::POST, "/json", MagicController::user_json); | ||
let b = b.add(Method::POST, "/json", MagicController::user_json); | ||
#[cfg(feature = "json")] | ||
let b = b.add(Method::GET, "/json", MagicController::get_user_json); | ||
let b = b.add(Method::GET, "/json", MagicController::get_user_json); | ||
|
||
#[cfg(feature = "form")] | ||
let b = b.add(Method::POST, "/form", MagicController::user_form); | ||
let b = b.add(Method::POST, "/form", MagicController::user_form); | ||
#[cfg(feature = "form")] | ||
let b = b.add(Method::GET, "/form", MagicController::get_user_form); | ||
let b = b.add(Method::GET, "/form", MagicController::get_user_form); | ||
|
||
b.add(Method::GET, "/delay/{delay}", MagicController::magic_delay) | ||
.add_with_guards(Method::GET, "/guarded/{delay}", MagicController::magic_delay, |g| { | ||
|
@@ -63,7 +63,7 @@ impl MagicController { | |
(200, body) | ||
} | ||
|
||
async fn match_any_route(&self, req: Request) -> (u16, String) { | ||
async fn match_any_route(&self, req: Request) -> (u16, String) { | ||
(200, req.uri().path().to_string()) | ||
} | ||
|
||
|
@@ -79,7 +79,10 @@ impl MagicController { | |
#[cfg(feature = "form")] | ||
async fn user_form(&self, mut req: Request) -> (u16, String) { | ||
if let Ok(user) = req.body_mut().take_as::<Form<User>>().await { | ||
(200, format!("New user with username: {} and age: {} read from Form data", user.username, user.age)) | ||
( | ||
200, | ||
format!("New user with username: {} and age: {} read from Form data", user.username, user.age), | ||
) | ||
} else { | ||
(400, "Bad user format".to_string()) | ||
} | ||
|
@@ -92,7 +95,7 @@ impl MagicController { | |
Json(User { | ||
username: "[email protected]".to_string(), | ||
age: 42, | ||
}) | ||
}), | ||
) | ||
} | ||
|
||
|
@@ -103,7 +106,7 @@ impl MagicController { | |
Form(User { | ||
username: "[email protected]".to_string(), | ||
age: 42, | ||
}) | ||
}), | ||
) | ||
} | ||
} | ||
|
@@ -138,10 +141,7 @@ impl StatsData { | |
let mut entered = self.entered.write().await; | ||
let exited = self.exited.read().await; | ||
*entered += 1; | ||
info!( | ||
"entered stats middleware! Current data: entered={} ; exited={}", | ||
*entered, *exited | ||
); | ||
info!("entered stats middleware! Current data: entered={} ; exited={}", *entered, *exited); | ||
} | ||
|
||
let res = chain.next(ctx).await?; | ||
|
@@ -150,21 +150,14 @@ impl StatsData { | |
let mut exited = self.exited.write().await; | ||
let entered = self.entered.read().await; | ||
*exited += 1; | ||
info!( | ||
"exited stats middleware! Current data: entered={} ; exited={}", | ||
*entered, *exited | ||
); | ||
info!("exited stats middleware! Current data: entered={} ; exited={}", *entered, *exited); | ||
} | ||
|
||
Ok(res) | ||
} | ||
} | ||
|
||
async fn log_middleware( | ||
prefix: &String, | ||
ctx: HttpContext<Body>, | ||
chain: &dyn MiddlewareChain, | ||
) -> Result<Response<Body>, SaphirError> { | ||
async fn log_middleware(prefix: &String, ctx: HttpContext<Body>, chain: &dyn MiddlewareChain) -> Result<Response<Body>, SaphirError> { | ||
info!("{} | new request on path: {}", prefix, ctx.request.uri().path()); | ||
let res = chain.next(ctx).await?; | ||
info!("{} | new response with status: {}", prefix, res.status()); | ||
|
@@ -198,25 +191,15 @@ impl ForbidderData { | |
} | ||
|
||
async fn forbidder_guard(data: &ForbidderData, req: Request<Body>) -> Result<Request<Body>, u16> { | ||
if req | ||
.captures() | ||
.get("variable") | ||
.and_then(|v| data.filter_forbidden(v)) | ||
.is_some() | ||
{ | ||
if req.captures().get("variable").and_then(|v| data.filter_forbidden(v)).is_some() { | ||
Err(403) | ||
} else { | ||
Ok(req) | ||
} | ||
} | ||
|
||
async fn numeric_delay_guard(_: &(), req: Request<Body>) -> Result<Request<Body>, &'static str> { | ||
if req | ||
.captures() | ||
.get("delay") | ||
.and_then(|v| v.parse::<u64>().ok()) | ||
.is_some() | ||
{ | ||
if req.captures().get("delay").and_then(|v| v.parse::<u64>().ok()).is_some() { | ||
Ok(req) | ||
} else { | ||
Err("Guard blocked request: delay is not a valid number.") | ||
|
@@ -234,13 +217,13 @@ async fn main() -> Result<(), SaphirError> { | |
.route("/{variable}/print", Method::GET, test_handler) | ||
.route_with_guards("/{variable}/guarded_print", Method::GET, test_handler, |g| { | ||
g.add(forbidder_guard, ForbidderData { forbidden: "forbidden" }) | ||
.add(forbidder_guard, ForbidderData { forbidden: "password" }) | ||
.add(forbidder_guard, ForbidderData { forbidden: "password" }) | ||
}) | ||
.controller(MagicController::new("Just Like Magic!")) | ||
}) | ||
.configure_middlewares(|m| { | ||
m.apply(log_middleware, "LOG".to_string(), vec!["/"], None) | ||
.apply(StatsData::stats_middleware, StatsData::new(), vec!["/"], None) | ||
.apply(StatsData::stats_middleware, StatsData::new(), vec!["/"], None) | ||
}) | ||
.build(); | ||
|
||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
use saphir::prelude::*; | ||
use saphir_macro::controller; | ||
use serde_derive::{Deserialize, Serialize}; | ||
|
||
fn guard_string(_controller: &UserController) -> String { | ||
UserController::BASE_PATH.to_string() | ||
} | ||
|
||
async fn print_string_guard(string: &String, req: Request<Body>) -> Result<Request<Body>, &'static str> { | ||
println!("{}", string); | ||
|
||
Ok(req) | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Clone)] | ||
struct User { | ||
username: String, | ||
age: i64, | ||
} | ||
|
||
struct UserController {} | ||
|
||
#[controller(name = "/users", version = 1, prefix = "api")] | ||
impl UserController { | ||
#[get("/<user_id>")] | ||
async fn get_user(&self, _req: Request) -> (u16, String) { | ||
(200, "Yo".to_string()) | ||
} | ||
|
||
#[post("/sync")] | ||
fn get_user_sync(&self, mut req: Request<Json<User>>) -> (u16, Json<User>) { | ||
let u = req.body_mut(); | ||
u.username = "Samuel".to_string(); | ||
(200, Json(u.clone())) | ||
} | ||
|
||
#[guard(fn = "print_string_guard", data = "guard_string")] | ||
#[get("/")] | ||
async fn list_user(&self, _req: Request<Body<Vec<u8>>>) -> (u16, String) { | ||
(200, "Yo".to_string()) | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), SaphirError> { | ||
env_logger::init(); | ||
|
||
let server = Server::builder() | ||
.configure_listener(|l| l.interface("127.0.0.1:3000")) | ||
.configure_router(|r| r.controller(UserController {})) | ||
.build(); | ||
|
||
server.run().await | ||
} |
Oops, something went wrong.