diff options
| author | Fuwn <[email protected]> | 2022-03-26 23:39:27 +0000 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2022-03-26 23:39:27 +0000 |
| commit | 7c82e30086b77edd51fea2a893b65af5ec14e603 (patch) | |
| tree | 63b73e79af1588f16a39cabc94b3210c79c0565d | |
| parent | feat(mount): use a sophisticated route matcher (diff) | |
| download | windmark-7c82e30086b77edd51fea2a893b65af5ec14e603.tar.xz windmark-7c82e30086b77edd51fea2a893b65af5ec14e603.zip | |
refactor(mount): context is now struct
| -rw-r--r-- | examples/windmark.rs | 42 | ||||
| -rw-r--r-- | src/lib.rs | 58 | ||||
| -rw-r--r-- | src/returnable.rs | 54 |
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()) @@ -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, + } + } +} |