aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2022-03-26 23:39:27 +0000
committerFuwn <[email protected]>2022-03-26 23:39:27 +0000
commit7c82e30086b77edd51fea2a893b65af5ec14e603 (patch)
tree63b73e79af1588f16a39cabc94b3210c79c0565d
parentfeat(mount): use a sophisticated route matcher (diff)
downloadwindmark-7c82e30086b77edd51fea2a893b65af5ec14e603.tar.xz
windmark-7c82e30086b77edd51fea2a893b65af5ec14e603.zip
refactor(mount): context is now struct
-rw-r--r--examples/windmark.rs42
-rw-r--r--src/lib.rs58
-rw-r--r--src/returnable.rs54
3 files changed, 110 insertions, 44 deletions
diff --git a/examples/windmark.rs b/examples/windmark.rs
index 03385ae..5568249 100644
--- a/examples/windmark.rs
+++ b/examples/windmark.rs
@@ -28,9 +28,7 @@ fn main() -> std::io::Result<()> {
.set_private_key_file("windmark_private.pem")
.set_certificate_chain_file("windmark_pair.pem")
.enable_default_logger(true)
- .set_error_handler(|_, _, _| {
- Response::PermanentFailure("error...".to_string())
- })
+ .set_error_handler(|_| Response::PermanentFailure("error...".to_string()))
.set_pre_route_callback(|stream, url, _| {
info!(
"accepted connection from {} to {}",
@@ -44,26 +42,26 @@ fn main() -> std::io::Result<()> {
stream.peer_addr().unwrap().ip()
)
})
- .set_header(|_, _, _| "```\nART IS COOL\n```".to_string())
- .set_footer(|_, _, _| "Copyright 2022".to_string())
- .mount("/", |_, _, _| {
+ .set_header(|_| "```\nART IS COOL\n```".to_string())
+ .set_footer(|_| "Copyright 2022".to_string())
+ .mount("/", |_| {
Response::Success(
"# INDEX\n\nWelcome!\n\n=> /test Test Page\n=> /time Unix Epoch\n"
.to_string(),
)
})
- .mount("/ip", |stream, _, _| {
+ .mount("/ip", |context| {
Response::Success(
- { format!("Hello, {}", stream.peer_addr().unwrap().ip()) }.into(),
+ { format!("Hello, {}", context.tcp.peer_addr().unwrap().ip()) }.into(),
)
})
- .mount("/test", |_, _, _| {
+ .mount("/test", |_| {
Response::Success("hi there\n=> / back".to_string())
})
- .mount("/temporary-failure", |_, _, _| {
+ .mount("/temporary-failure", |_| {
Response::TemporaryFailure("Woops, temporarily...".into())
})
- .mount("/time", |_, _, _| {
+ .mount("/time", |_| {
Response::Success(
std::time::UNIX_EPOCH
.elapsed()
@@ -72,34 +70,34 @@ fn main() -> std::io::Result<()> {
.to_string(),
)
})
- .mount("/query", |_, url, _| {
+ .mount("/query", |context| {
Response::Success(format!(
"queries: {:?}",
- windmark::utilities::queries_from_url(&url)
+ windmark::utilities::queries_from_url(&context.url)
))
})
- .mount("/param/:lang", |_, _url, dynamic_parameter| {
+ .mount("/param/:lang", |context| {
Response::Success(format!(
"Parameter lang is {}",
- dynamic_parameter.unwrap().get("lang").unwrap()
+ context.params.get("lang").unwrap()
))
})
- .mount("/names/:first/:last", |_, _url, Some(dynamic_parameter)| {
+ .mount("/names/:first/:last", |context| {
Response::Success(format!(
"{} {}",
- dynamic_parameter.get("first").unwrap(),
- dynamic_parameter.get("last").unwrap()
+ context.params.get("first").unwrap(),
+ context.params.get("last").unwrap()
))
})
- .mount("/input", |_, url, _| {
- if let Some(name) = url.query() {
+ .mount("/input", |context| {
+ if let Some(name) = context.url.query() {
Response::Success(format!("Your name is {}!", name))
} else {
Response::Input("What is your name?".into())
}
})
- .mount("/sensitive-input", |_, url, _| {
- if let Some(password) = url.query() {
+ .mount("/sensitive-input", |context| {
+ if let Some(password) = context.url.query() {
Response::Success(format!("Your password is {}!", password))
} else {
Response::SensitiveInput("What is your password?".into())
diff --git a/src/lib.rs b/src/lib.rs
index bf7fdf3..4f68ca6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -29,6 +29,7 @@
#![recursion_limit = "128"]
pub mod response;
+pub(crate) mod returnable;
pub mod status;
pub mod utilities;
@@ -42,17 +43,20 @@ use matchit::Params;
use openssl::ssl::{self, SslAcceptor, SslMethod};
use url::Url;
-use crate::response::{to_value_set_status, Response};
+use crate::{
+ response::{to_value_set_status, Response},
+ returnable::{ErrorContext, RouteContext},
+};
-type RouteResponseHandler =
- fn(&TcpStream, &Url, Option<&Params<'_, '_>>) -> Response;
+type RouteResponseHandler = fn(RouteContext<'_>) -> Response;
+type ErrorResponseHandler = fn(ErrorContext<'_>) -> Response;
type CallbackHandler = fn(&TcpStream, &Url, Option<&Params<'_, '_>>);
-type PartialHandler = fn(&TcpStream, &Url, &Params<'_, '_>) -> String;
+type PartialHandler = fn(RouteContext<'_>) -> String;
#[derive(Clone)]
pub struct Router {
routes: matchit::Router<RouteResponseHandler>,
- error_handler: RouteResponseHandler,
+ error_handler: ErrorResponseHandler,
private_key_file_name: String,
certificate_chain_file_name: String,
header: PartialHandler,
@@ -118,10 +122,8 @@ impl Router {
/// use windmark::response::Response;
///
/// windmark::Router::new()
- /// .mount("/", |_, _, _| {
- /// Response::Success("This is the index page!".into())
- /// })
- /// .mount("/test", |_, _, _| {
+ /// .mount("/", |_| Response::Success("This is the index page!".into()))
+ /// .mount("/test", |_| {
/// Response::Success("This is a test page!".into())
/// });
/// ```
@@ -144,7 +146,7 @@ impl Router {
/// # Examples
///
/// ```rust
- /// windmark::Router::new().set_error_handler(|_, _, _| {
+ /// windmark::Router::new().set_error_handler(|_| {
/// windmark::response::Response::Success(
/// "You have encountered an error!".into(),
/// )
@@ -152,7 +154,7 @@ impl Router {
/// ```
pub fn set_error_handler(
&mut self,
- handler: RouteResponseHandler,
+ handler: ErrorResponseHandler,
) -> &mut Self {
self.error_handler = handler;
@@ -164,8 +166,8 @@ impl Router {
/// # Examples
///
/// ```rust
- /// windmark::Router::new().set_header(|_, _, _| {
- /// "This will be displayed on every route! (at the top)".into()
+ /// windmark::Router::new().set_header(|context| {
+ /// format!("This is displayed at the top of {}!", context.url.path())
/// });
/// ```
pub fn set_header(&mut self, handler: PartialHandler) -> &mut Self {
@@ -179,8 +181,8 @@ impl Router {
/// # Examples
///
/// ```rust
- /// windmark::Router::new().set_footer(|_, _, _| {
- /// "This will be displayed on every route! (at the bottom)".into()
+ /// windmark::Router::new().set_footer(|context| {
+ /// format!("This is displayed at the bottom of {}!", context.url.path())
/// });
/// ```
pub fn set_footer(&mut self, handler: PartialHandler) -> &mut Self {
@@ -267,7 +269,11 @@ impl Router {
if let Ok(ref route) = route {
header = {
- let header = (self.header)(stream.get_ref(), &url, &route.params);
+ let header = (self.header)(RouteContext::new(
+ stream.get_ref(),
+ &url,
+ &route.params,
+ ));
if header.is_empty() {
"".to_string()
@@ -276,7 +282,11 @@ impl Router {
}
};
footer = {
- let footer = (self.footer)(stream.get_ref(), &url, &route.params);
+ let footer = (self.footer)(RouteContext::new(
+ stream.get_ref(),
+ &url,
+ &route.params,
+ ));
if footer.is_empty() {
"".to_string()
@@ -286,13 +296,17 @@ impl Router {
};
content = {
to_value_set_status(
- (route.value)(stream.get_ref(), &url, Some(&route.params)),
+ (route.value)(RouteContext::new(
+ stream.get_ref(),
+ &url,
+ &route.params,
+ )),
&mut response_status,
)
};
} else {
content = to_value_set_status(
- (self.error_handler)(stream.get_ref(), &url, None),
+ (self.error_handler)(ErrorContext::new(stream.get_ref(), &url)),
&mut response_status,
);
}
@@ -430,15 +444,15 @@ impl Default for Router {
fn default() -> Self {
Self {
routes: matchit::Router::new(),
- error_handler: |_, _, _| {
+ error_handler: |_| {
Response::NotFound(
"This capsule has not implemented an error handler...".to_string(),
)
},
private_key_file_name: "".to_string(),
certificate_chain_file_name: "".to_string(),
- header: |_, _, _| "".to_string(),
- footer: |_, _, _| "".to_string(),
+ header: |_| "".to_string(),
+ footer: |_| "".to_string(),
ssl_acceptor: Arc::new(
SslAcceptor::mozilla_intermediate(SslMethod::tls())
.unwrap()
diff --git a/src/returnable.rs b/src/returnable.rs
new file mode 100644
index 0000000..79a3d7a
--- /dev/null
+++ b/src/returnable.rs
@@ -0,0 +1,54 @@
+// This file is part of Windmark <https://github.com/gemrest/windmark>.
+// Copyright (C) 2022-2022 Fuwn <[email protected]>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+// Copyright (C) 2022-2022 Fuwn <[email protected]>
+// SPDX-License-Identifier: GPL-3.0-only
+
+use std::net::TcpStream;
+
+use matchit::Params;
+use url::Url;
+
+pub struct RouteContext<'a> {
+ pub tcp: &'a TcpStream,
+ pub url: &'a Url,
+ pub params: &'a Params<'a, 'a>,
+}
+impl<'a> RouteContext<'a> {
+ pub const fn new(
+ tcp: &'a TcpStream,
+ url: &'a Url,
+ params: &'a Params<'a, 'a>,
+ ) -> Self {
+ Self {
+ tcp,
+ url,
+ params,
+ }
+ }
+}
+
+pub struct ErrorContext<'a> {
+ pub tcp: &'a TcpStream,
+ pub url: &'a Url,
+}
+impl<'a> ErrorContext<'a> {
+ pub const fn new(tcp: &'a TcpStream, url: &'a Url) -> Self {
+ Self {
+ tcp,
+ url,
+ }
+ }
+}