From c1093984ee56e27926f6fa34acfad1916dee4246 Mon Sep 17 00:00:00 2001 From: ivmarkov Date: Sun, 3 Nov 2024 08:02:43 +0000 Subject: [PATCH 1/2] Handlers with non-static socket factories --- edge-http/README.md | 25 ++-- edge-http/src/io.rs | 8 +- edge-http/src/io/client.rs | 4 +- edge-http/src/io/server.rs | 115 +++++++++------ edge-http/src/io/server/registration.rs | 180 ++++++++++++++++++++++++ edge-http/src/lib.rs | 4 +- edge-ws/README.md | 38 ++--- examples/http_client.rs | 4 +- examples/http_server.rs | 21 +-- examples/ws_server.rs | 38 ++--- 10 files changed, 327 insertions(+), 110 deletions(-) create mode 100644 edge-http/src/io/server/registration.rs diff --git a/edge-http/README.md b/edge-http/README.md index c1ae228..2f31e86 100644 --- a/edge-http/README.md +++ b/edge-http/README.md @@ -68,8 +68,8 @@ where Ok(()) } -async fn request<'b, const N: usize, T: TcpConnect>( - conn: &mut Connection<'b, T, N>, +async fn request( + conn: &mut Connection<'_, T, N>, uri: &str, ) -> Result<(), Error> { conn.initiate_request(true, Method::Get, uri, &[("Host", "httpbin.org")]) @@ -103,7 +103,7 @@ async fn request<'b, const N: usize, T: TcpConnect>( ### HTTP server ```rust -use core::fmt::Display; +use core::fmt::{Debug, Display}; use edge_http::io::server::{Connection, DefaultServer, Handler}; use edge_http::io::Error; @@ -140,17 +140,20 @@ pub async fn run(server: &mut DefaultServer) -> Result<(), anyhow::Error> { struct HttpHandler; -impl<'b, T, const N: usize> Handler<'b, T, N> for HttpHandler -where - T: Read + Write, -{ - type Error = Error; +impl Handler for HttpHandler { + type Error + = Error + where + E: Debug; - async fn handle( + async fn handle( &self, _task_id: impl Display + Copy, - conn: &mut Connection<'b, T, N>, - ) -> Result<(), Self::Error> { + conn: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write, + { let headers = conn.headers()?; if headers.method != Method::Get { diff --git a/edge-http/src/io.rs b/edge-http/src/io.rs index 3d58acd..9674808 100644 --- a/edge-http/src/io.rs +++ b/edge-http/src/io.rs @@ -373,7 +373,7 @@ where Ok((connection_type, body_type)) } -impl<'b, const N: usize> Headers<'b, N> { +impl Headers<'_, N> { fn resolve( &self, carry_over_connection_type: Option, @@ -497,7 +497,7 @@ where type Error = Error; } -impl<'b, R> Read for Body<'b, R> +impl Read for Body<'_, R> where R: Read, { @@ -545,7 +545,7 @@ where type Error = R::Error; } -impl<'b, R> Read for PartiallyRead<'b, R> +impl Read for PartiallyRead<'_, R> where R: Read, { @@ -824,7 +824,7 @@ where type Error = Error; } -impl<'b, R> Read for ChunkedRead<'b, R> +impl Read for ChunkedRead<'_, R> where R: Read, { diff --git a/edge-http/src/io/client.rs b/edge-http/src/io/client.rs index 6f2fb10..0379025 100644 --- a/edge-http/src/io/client.rs +++ b/edge-http/src/io/client.rs @@ -401,7 +401,7 @@ where type Error = Error; } -impl<'b, T, const N: usize> Read for Connection<'b, T, N> +impl Read for Connection<'_, T, N> where T: TcpConnect, { @@ -410,7 +410,7 @@ where } } -impl<'b, T, const N: usize> Write for Connection<'b, T, N> +impl Write for Connection<'_, T, N> where T: TcpConnect, { diff --git a/edge-http/src/io/server.rs b/edge-http/src/io/server.rs index 8b20b61..f1b2003 100644 --- a/edge-http/src/io/server.rs +++ b/edge-http/src/io/server.rs @@ -23,6 +23,8 @@ pub use embedded_svc_compat::*; pub const DEFAULT_HANDLER_TASKS_COUNT: usize = 4; pub const DEFAULT_BUF_SIZE: usize = 2048; +pub mod registration; + const COMPLETION_BUF_SIZE: usize = 64; /// A connection state machine for handling HTTP server requests-response cycles. @@ -287,7 +289,7 @@ where type Error = Error; } -impl<'b, T, const N: usize> Read for Connection<'b, T, N> +impl Read for Connection<'_, T, N> where T: Read + Write, { @@ -296,7 +298,7 @@ where } } -impl<'b, T, const N: usize> Write for Connection<'b, T, N> +impl Write for Connection<'_, T, N> where T: Read + Write, { @@ -331,69 +333,98 @@ where } } +#[derive(Debug)] +pub enum HandlerError { + Io(T), + Connection(Error), + Handler(E), +} + +impl From> for HandlerError { + fn from(e: Error) -> Self { + Self::Connection(e) + } +} + /// A trait (async callback) for handling incoming HTTP requests -pub trait Handler<'b, T, const N: usize> -where - T: Read + Write, -{ - type Error: Debug; +pub trait Handler { + type Error: Debug + where + E: Debug; /// Handle an incoming HTTP request /// /// Parameters: /// - `task_id`: An identifier for the task, thast can be used by the handler for logging purposes /// - `connection`: A connection state machine for the request-response cycle - async fn handle( + async fn handle( &self, task_id: impl Display + Copy, - connection: &mut Connection<'b, T, N>, - ) -> Result<(), Self::Error>; + connection: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write; } -impl<'b, const N: usize, T, H> Handler<'b, T, N> for &H +impl Handler for &H where - T: Read + Write, - H: Handler<'b, T, N>, + H: Handler, { - type Error = H::Error; + type Error + = H::Error + where + E: Debug; - async fn handle( + async fn handle( &self, task_id: impl Display + Copy, - connection: &mut Connection<'b, T, N>, - ) -> Result<(), Self::Error> { + connection: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write, + { (**self).handle(task_id, connection).await } } -impl<'b, const N: usize, T, H> Handler<'b, T, N> for &mut H +impl Handler for &mut H where - T: Read + Write, - H: Handler<'b, T, N>, + H: Handler, { - type Error = H::Error; + type Error + = H::Error + where + E: Debug; - async fn handle( + async fn handle( &self, task_id: impl Display + Copy, - connection: &mut Connection<'b, T, N>, - ) -> Result<(), Self::Error> { + connection: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write, + { (**self).handle(task_id, connection).await } } -impl<'b, const N: usize, T, H> Handler<'b, T, N> for WithTimeout +impl Handler for WithTimeout where - T: Read + Write, - H: Handler<'b, T, N>, + H: Handler, { - type Error = WithTimeoutError; + type Error + = WithTimeoutError> + where + E: Debug; - async fn handle( + async fn handle( &self, task_id: impl Display + Copy, - connection: &mut Connection<'b, T, N>, - ) -> Result<(), Self::Error> { + connection: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write, + { let mut io = pin!(self.io().handle(task_id, connection)); with_timeout(self.timeout_ms(), &mut io).await?; @@ -413,22 +444,22 @@ where /// - `buf`: A work-area buffer used by the implementation /// - `task_id`: An identifier for the task, used for logging purposes /// - `handler`: An implementation of `Handler` to handle incoming requests -pub async fn handle_connection( +pub async fn handle_connection( mut io: T, buf: &mut [u8], task_id: impl Display + Copy, handler: H, ) where - H: for<'b> Handler<'b, &'b mut T, N>, + H: Handler, T: Read + Write + TcpShutdown, { let close = loop { debug!("Handler task {task_id}: Waiting for new request"); - let result = handle_request::(buf, &mut io, task_id, &handler).await; + let result = handle_request::<_, _, N>(buf, &mut io, task_id, &handler).await; match result { - Err(HandleRequestError::Connection(Error::ConnectionClosed)) => { + Err(HandlerError::Connection(Error::ConnectionClosed)) => { debug!("Handler task {task_id}: Connection closed"); break false; } @@ -518,14 +549,14 @@ where /// - `io`: A socket stream /// - `task_id`: An identifier for the task, used for logging purposes /// - `handler`: An implementation of `Handler` to handle incoming requests -pub async fn handle_request<'b, const N: usize, H, T>( - buf: &'b mut [u8], +pub async fn handle_request( + buf: &mut [u8], io: T, task_id: impl Display + Copy, handler: H, -) -> Result> +) -> Result>> where - H: Handler<'b, T, N>, + H: Handler, T: Read + Write, { let mut connection = Connection::<_, N>::new(buf, io).await?; @@ -537,7 +568,7 @@ where Result::Err(e) => connection .complete_err("INTERNAL ERROR") .await - .map_err(|_| HandleRequestError::Handler(e))?, + .map_err(|_| HandlerError::Handler(e))?, } Ok(connection.needs_close()) @@ -587,7 +618,7 @@ impl Server { pub async fn run(&mut self, acceptor: A, handler: H) -> Result<(), Error> where A: edge_nal::TcpAccept, - H: for<'b, 't> Handler<'b, &'b mut A::Socket<'t>, N>, + H: Handler, { let mutex = Mutex::::new(()); let mut tasks = heapless::Vec::<_, P>::new(); @@ -617,7 +648,7 @@ impl Server { debug!("Handler task {task_id}: Got connection request"); - handle_connection::( + handle_connection::<_, _, N>( io, unsafe { buf.as_mut() }.unwrap(), task_id, diff --git a/edge-http/src/io/server/registration.rs b/edge-http/src/io/server/registration.rs new file mode 100644 index 0000000..7ff81f9 --- /dev/null +++ b/edge-http/src/io/server/registration.rs @@ -0,0 +1,180 @@ +use core::fmt::{Debug, Display}; + +use embedded_io_async::{Read, Write}; + +use log::warn; + +use crate::{io::Error, Method}; + +use super::{Connection, Handler}; + +/// A chain of handlers that can be used to route requests to different handlers based on the path and method. +pub struct ChainHandler { + /// The path that this handler should handle. + pub path: &'static str, + /// The method that this handler should handle. + pub method: Method, + /// The handler that should be called if the path and method match. + pub handler: H, + /// The next handler in the chain. + pub next: N, +} + +impl ChainHandler { + /// Create a new chain handler for the provided path and for GET requests on that path + pub fn get

(self, path: &'static str, handler: H2) -> ChainHandler> { + self.request(path, Method::Get, handler) + } + + /// Create a new chain handler for the provided path and for POST requests on that path + pub fn post

(self, path: &'static str, handler: H2) -> ChainHandler> { + self.request(path, Method::Post, handler) + } + + /// Create a new chain handler for the provided path and for PUT requests on that path + pub fn put

(self, path: &'static str, handler: H2) -> ChainHandler> { + self.request(path, Method::Put, handler) + } + + /// Create a new chain handler for the provided path and for DELETE requests on that path + pub fn delete

( + self, + path: &'static str, + handler: H2, + ) -> ChainHandler> { + self.request(path, Method::Delete, handler) + } + + /// Create a new chain handler for the provided path and method + pub fn request

( + self, + path: &'static str, + method: Method, + handler: H2, + ) -> ChainHandler> { + ChainHandler { + path, + method, + handler, + next: self, + } + } +} + +/// The root of a chain of handlers. +/// +/// Returns a 404 response for all requests. +pub struct ChainRoot; + +impl ChainRoot { + /// Create a new chain handler for the provided path and for GET requests on that path + pub fn get

(self, path: &'static str, handler: H2) -> ChainHandler { + self.request(path, Method::Get, handler) + } + + /// Create a new chain handler for the provided path and for POST requests on that path + pub fn post

(self, path: &'static str, handler: H2) -> ChainHandler { + self.request(path, Method::Post, handler) + } + + /// Create a new chain handler for the provided path and for PUT requests on that path + pub fn put

(self, path: &'static str, handler: H2) -> ChainHandler { + self.request(path, Method::Put, handler) + } + + /// Create a new chain handler for the provided path and for DELETE requests on that path + pub fn delete

(self, path: &'static str, handler: H2) -> ChainHandler { + self.request(path, Method::Delete, handler) + } + + /// Create a new chain handler for the provided path and method + pub fn request

( + self, + path: &'static str, + method: Method, + handler: H2, + ) -> ChainHandler { + ChainHandler { + path, + method, + handler, + next: ChainRoot, + } + } +} + +impl Default for ChainRoot { + fn default() -> Self { + ChainRoot + } +} + +impl Handler for ChainRoot { + type Error + = Error + where + E: Debug; + + async fn handle( + &self, + task_id: impl Display + Copy, + connection: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write, + { + let headers = connection.headers().ok(); + + if let Some(headers) = headers { + warn!( + "[Task {task_id}]: No handler found for path: {} and method: {}", + headers.path, headers.method + ); + } + + connection.initiate_response(404, None, &[]).await + } +} + +#[derive(Debug)] +pub enum ChainHandlerError { + First(E1), + Second(E2), +} + +impl Handler for ChainHandler +where + H: Handler, + Q: Handler, +{ + type Error + = ChainHandlerError, Q::Error> + where + T: Debug; + + async fn handle( + &self, + task_id: impl Display + Copy, + connection: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write, + { + let headers = connection.headers().ok(); + + if let Some(headers) = headers { + if headers.path == self.path && headers.method == self.method { + return self + .handler + .handle(task_id, connection) + .await + .map_err(ChainHandlerError::First); + } + } + + self.next + .handle(task_id, connection) + .await + .map_err(ChainHandlerError::Second) + } +} diff --git a/edge-http/src/lib.rs b/edge-http/src/lib.rs index 6fe9546..c86ee8b 100644 --- a/edge-http/src/lib.rs +++ b/edge-http/src/lib.rs @@ -734,7 +734,7 @@ impl RequestHeaders<'_, N> { } } -impl<'b, const N: usize> Default for RequestHeaders<'b, N> { +impl Default for RequestHeaders<'_, N> { #[inline(always)] fn default() -> Self { Self::new() @@ -795,7 +795,7 @@ impl ResponseHeaders<'_, N> { } } -impl<'b, const N: usize> Default for ResponseHeaders<'b, N> { +impl Default for ResponseHeaders<'_, N> { #[inline(always)] fn default() -> Self { Self::new() diff --git a/edge-ws/README.md b/edge-ws/README.md index 5bbf20a..cfa575b 100644 --- a/edge-ws/README.md +++ b/edge-ws/README.md @@ -148,7 +148,7 @@ where ### Websocket echo server ```rust -use core::fmt::Display; +use core::fmt::{Debug, Display}; use edge_http::io::server::{Connection, DefaultServer, Handler}; use edge_http::io::Error; @@ -187,29 +187,32 @@ pub async fn run(server: &mut DefaultServer) -> Result<(), anyhow::Error> { #[derive(Debug)] enum WsHandlerError { - ConnectionError(C), - WsError(W), + Connection(C), + Ws(W), } impl From for WsHandlerError { fn from(e: C) -> Self { - Self::ConnectionError(e) + Self::Connection(e) } } struct WsHandler; -impl<'b, T, const N: usize> Handler<'b, T, N> for WsHandler -where - T: Read + Write, -{ - type Error = WsHandlerError, edge_ws::Error>; +impl Handler for WsHandler { + type Error + = WsHandlerError, edge_ws::Error> + where + E: Debug; - async fn handle( + async fn handle( &self, _task_id: impl Display + Clone, - conn: &mut Connection<'b, T, N>, - ) -> Result<(), Self::Error> { + conn: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write, + { let headers = conn.headers()?; if headers.method != Method::Get { @@ -241,11 +244,11 @@ where loop { let mut header = FrameHeader::recv(&mut socket) .await - .map_err(WsHandlerError::WsError)?; + .map_err(WsHandlerError::Ws)?; let payload = header .recv_payload(&mut socket, &mut buf) .await - .map_err(WsHandlerError::WsError)?; + .map_err(WsHandlerError::Ws)?; match header.frame_type { FrameType::Text(_) => { @@ -276,14 +279,11 @@ where info!("Echoing back as {header}"); - header - .send(&mut socket) - .await - .map_err(WsHandlerError::WsError)?; + header.send(&mut socket).await.map_err(WsHandlerError::Ws)?; header .send_payload(&mut socket, payload) .await - .map_err(WsHandlerError::WsError)?; + .map_err(WsHandlerError::Ws)?; } } diff --git a/examples/http_client.rs b/examples/http_client.rs index 30b9fcc..75f0efe 100644 --- a/examples/http_client.rs +++ b/examples/http_client.rs @@ -43,8 +43,8 @@ where Ok(()) } -async fn request<'b, const N: usize, T: TcpConnect>( - conn: &mut Connection<'b, T, N>, +async fn request( + conn: &mut Connection<'_, T, N>, uri: &str, ) -> Result<(), Error> { conn.initiate_request(true, Method::Get, uri, &[("Host", "httpbin.org")]) diff --git a/examples/http_server.rs b/examples/http_server.rs index 8923506..e242c15 100644 --- a/examples/http_server.rs +++ b/examples/http_server.rs @@ -1,4 +1,4 @@ -use core::fmt::Display; +use core::fmt::{Debug, Display}; use edge_http::io::server::{Connection, DefaultServer, Handler}; use edge_http::io::Error; @@ -35,17 +35,20 @@ pub async fn run(server: &mut DefaultServer) -> Result<(), anyhow::Error> { struct HttpHandler; -impl<'b, T, const N: usize> Handler<'b, T, N> for HttpHandler -where - T: Read + Write, -{ - type Error = Error; +impl Handler for HttpHandler { + type Error + = Error + where + E: Debug; - async fn handle( + async fn handle( &self, _task_id: impl Display + Copy, - conn: &mut Connection<'b, T, N>, - ) -> Result<(), Self::Error> { + conn: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write, + { let headers = conn.headers()?; if headers.method != Method::Get { diff --git a/examples/ws_server.rs b/examples/ws_server.rs index e0f2f6d..2d7df68 100644 --- a/examples/ws_server.rs +++ b/examples/ws_server.rs @@ -1,4 +1,4 @@ -use core::fmt::Display; +use core::fmt::{Debug, Display}; use edge_http::io::server::{Connection, DefaultServer, Handler}; use edge_http::io::Error; @@ -37,29 +37,32 @@ pub async fn run(server: &mut DefaultServer) -> Result<(), anyhow::Error> { #[derive(Debug)] enum WsHandlerError { - ConnectionError(C), - WsError(W), + Connection(C), + Ws(W), } impl From for WsHandlerError { fn from(e: C) -> Self { - Self::ConnectionError(e) + Self::Connection(e) } } struct WsHandler; -impl<'b, T, const N: usize> Handler<'b, T, N> for WsHandler -where - T: Read + Write, -{ - type Error = WsHandlerError, edge_ws::Error>; +impl Handler for WsHandler { + type Error + = WsHandlerError, edge_ws::Error> + where + E: Debug; - async fn handle( + async fn handle( &self, _task_id: impl Display + Clone, - conn: &mut Connection<'b, T, N>, - ) -> Result<(), Self::Error> { + conn: &mut Connection<'_, T, N>, + ) -> Result<(), Self::Error> + where + T: Read + Write, + { let headers = conn.headers()?; if headers.method != Method::Get { @@ -91,11 +94,11 @@ where loop { let mut header = FrameHeader::recv(&mut socket) .await - .map_err(WsHandlerError::WsError)?; + .map_err(WsHandlerError::Ws)?; let payload = header .recv_payload(&mut socket, &mut buf) .await - .map_err(WsHandlerError::WsError)?; + .map_err(WsHandlerError::Ws)?; match header.frame_type { FrameType::Text(_) => { @@ -126,14 +129,11 @@ where info!("Echoing back as {header}"); - header - .send(&mut socket) - .await - .map_err(WsHandlerError::WsError)?; + header.send(&mut socket).await.map_err(WsHandlerError::Ws)?; header .send_payload(&mut socket, payload) .await - .map_err(WsHandlerError::WsError)?; + .map_err(WsHandlerError::Ws)?; } } From 71c08587934a98ed7c5ff3f6bef67a2c70f3e56e Mon Sep 17 00:00:00 2001 From: ivmarkov Date: Sun, 3 Nov 2024 09:52:33 +0000 Subject: [PATCH 2/2] embedded-svc compat --- edge-http/src/io/client.rs | 4 +- edge-http/src/io/server.rs | 81 ++++------- edge-http/src/io/server/registration.rs | 180 ------------------------ edge-http/src/lib.rs | 10 +- 4 files changed, 38 insertions(+), 237 deletions(-) delete mode 100644 edge-http/src/io/server/registration.rs diff --git a/edge-http/src/io/client.rs b/edge-http/src/io/client.rs index 0379025..59b612e 100644 --- a/edge-http/src/io/client.rs +++ b/edge-http/src/io/client.rs @@ -473,7 +473,7 @@ mod embedded_svc_compat { use embedded_svc::http::client::asynch::{Connection, Headers, Method, Status}; - impl<'b, T, const N: usize> Headers for super::Connection<'b, T, N> + impl Headers for super::Connection<'_, T, N> where T: TcpConnect, { @@ -484,7 +484,7 @@ mod embedded_svc_compat { } } - impl<'b, T, const N: usize> Status for super::Connection<'b, T, N> + impl Status for super::Connection<'_, T, N> where T: TcpConnect, { diff --git a/edge-http/src/io/server.rs b/edge-http/src/io/server.rs index f1b2003..0521c49 100644 --- a/edge-http/src/io/server.rs +++ b/edge-http/src/io/server.rs @@ -23,8 +23,6 @@ pub use embedded_svc_compat::*; pub const DEFAULT_HANDLER_TASKS_COUNT: usize = 4; pub const DEFAULT_BUF_SIZE: usize = 2048; -pub mod registration; - const COMPLETION_BUF_SIZE: usize = 64; /// A connection state machine for handling HTTP server requests-response cycles. @@ -680,14 +678,11 @@ mod embedded_svc_compat { use embedded_io_async::{Read, Write}; use embedded_svc::http::server::asynch::{Connection, Headers, Query}; - use embedded_svc::utils::http::server::registration::{ChainHandler, ChainRoot}; use crate::io::Body; use crate::RequestHeaders; - use super::*; - - impl<'b, T, const N: usize> Headers for super::Connection<'b, T, N> + impl Headers for super::Connection<'_, T, N> where T: Read + Write, { @@ -699,7 +694,7 @@ mod embedded_svc_compat { } } - impl<'b, T, const N: usize> Query for super::Connection<'b, T, N> + impl Query for super::Connection<'_, T, N> where T: Read + Write, { @@ -755,47 +750,33 @@ mod embedded_svc_compat { } } - impl<'b, T, const N: usize> Handler<'b, T, N> for ChainRoot - where - T: Read + Write, - { - type Error = Error; - - async fn handle( - &self, - _task_id: impl core::fmt::Display + Copy, - connection: &mut super::Connection<'b, T, N>, - ) -> Result<(), Self::Error> { - connection.initiate_response(404, None, &[]).await - } - } - - impl<'b, const N: usize, T, H, Q> Handler<'b, T, N> for ChainHandler - where - H: embedded_svc::http::server::asynch::Handler>, - Q: Handler<'b, T, N>, - Q::Error: Into, - T: Read + Write, - { - type Error = H::Error; - - async fn handle( - &self, - task_id: impl core::fmt::Display + Copy, - connection: &mut super::Connection<'b, T, N>, - ) -> Result<(), Self::Error> { - let headers = connection.headers().ok(); - - if let Some(headers) = headers { - if headers.path == self.path && headers.method == self.method.into() { - return self.handler.handle(connection).await; - } - } - - self.next - .handle(task_id, connection) - .await - .map_err(Into::into) - } - } + // NOTE: Currently, the `edge-http` and the `embedded-svc` Handler traits are + // incompatible, in that the `edge-http` async `Handler`'s `handle` method is generic, + // while the `embedded-svc` `Handler`'s `handle` method is not. + // + // Code below is commented out until `embedded-svc`'s `Handler` signature is changed + // to match the `edge-http` `Handler` signature. + + // pub struct SvcHandler(H); + + // impl<'b, T, const N: usize, H> Handler for SvcHandler + // where + // H: embedded_svc::http::server::asynch::Handler>, + // T: Read + Write, + // { + // type Error = Error where E: Debug; + + // async fn handle( + // &self, + // _task_id: impl core::fmt::Display + Copy, + // connection: &mut super::Connection<'_, T, N>, + // ) -> Result<(), Self::Error> + // where + // T: Read + Write, + // { + // self.0.handle(connection).await.unwrap(); + + // Ok(()) + // } + // } } diff --git a/edge-http/src/io/server/registration.rs b/edge-http/src/io/server/registration.rs deleted file mode 100644 index 7ff81f9..0000000 --- a/edge-http/src/io/server/registration.rs +++ /dev/null @@ -1,180 +0,0 @@ -use core::fmt::{Debug, Display}; - -use embedded_io_async::{Read, Write}; - -use log::warn; - -use crate::{io::Error, Method}; - -use super::{Connection, Handler}; - -/// A chain of handlers that can be used to route requests to different handlers based on the path and method. -pub struct ChainHandler { - /// The path that this handler should handle. - pub path: &'static str, - /// The method that this handler should handle. - pub method: Method, - /// The handler that should be called if the path and method match. - pub handler: H, - /// The next handler in the chain. - pub next: N, -} - -impl ChainHandler { - /// Create a new chain handler for the provided path and for GET requests on that path - pub fn get

(self, path: &'static str, handler: H2) -> ChainHandler> { - self.request(path, Method::Get, handler) - } - - /// Create a new chain handler for the provided path and for POST requests on that path - pub fn post

(self, path: &'static str, handler: H2) -> ChainHandler> { - self.request(path, Method::Post, handler) - } - - /// Create a new chain handler for the provided path and for PUT requests on that path - pub fn put

(self, path: &'static str, handler: H2) -> ChainHandler> { - self.request(path, Method::Put, handler) - } - - /// Create a new chain handler for the provided path and for DELETE requests on that path - pub fn delete

( - self, - path: &'static str, - handler: H2, - ) -> ChainHandler> { - self.request(path, Method::Delete, handler) - } - - /// Create a new chain handler for the provided path and method - pub fn request

( - self, - path: &'static str, - method: Method, - handler: H2, - ) -> ChainHandler> { - ChainHandler { - path, - method, - handler, - next: self, - } - } -} - -/// The root of a chain of handlers. -/// -/// Returns a 404 response for all requests. -pub struct ChainRoot; - -impl ChainRoot { - /// Create a new chain handler for the provided path and for GET requests on that path - pub fn get

(self, path: &'static str, handler: H2) -> ChainHandler { - self.request(path, Method::Get, handler) - } - - /// Create a new chain handler for the provided path and for POST requests on that path - pub fn post

(self, path: &'static str, handler: H2) -> ChainHandler { - self.request(path, Method::Post, handler) - } - - /// Create a new chain handler for the provided path and for PUT requests on that path - pub fn put

(self, path: &'static str, handler: H2) -> ChainHandler { - self.request(path, Method::Put, handler) - } - - /// Create a new chain handler for the provided path and for DELETE requests on that path - pub fn delete

(self, path: &'static str, handler: H2) -> ChainHandler { - self.request(path, Method::Delete, handler) - } - - /// Create a new chain handler for the provided path and method - pub fn request

( - self, - path: &'static str, - method: Method, - handler: H2, - ) -> ChainHandler { - ChainHandler { - path, - method, - handler, - next: ChainRoot, - } - } -} - -impl Default for ChainRoot { - fn default() -> Self { - ChainRoot - } -} - -impl Handler for ChainRoot { - type Error - = Error - where - E: Debug; - - async fn handle( - &self, - task_id: impl Display + Copy, - connection: &mut Connection<'_, T, N>, - ) -> Result<(), Self::Error> - where - T: Read + Write, - { - let headers = connection.headers().ok(); - - if let Some(headers) = headers { - warn!( - "[Task {task_id}]: No handler found for path: {} and method: {}", - headers.path, headers.method - ); - } - - connection.initiate_response(404, None, &[]).await - } -} - -#[derive(Debug)] -pub enum ChainHandlerError { - First(E1), - Second(E2), -} - -impl Handler for ChainHandler -where - H: Handler, - Q: Handler, -{ - type Error - = ChainHandlerError, Q::Error> - where - T: Debug; - - async fn handle( - &self, - task_id: impl Display + Copy, - connection: &mut Connection<'_, T, N>, - ) -> Result<(), Self::Error> - where - T: Read + Write, - { - let headers = connection.headers().ok(); - - if let Some(headers) = headers { - if headers.path == self.path && headers.method == self.method { - return self - .handler - .handle(task_id, connection) - .await - .map_err(ChainHandlerError::First); - } - } - - self.next - .handle(task_id, connection) - .await - .map_err(ChainHandlerError::Second) - } -} diff --git a/edge-http/src/lib.rs b/edge-http/src/lib.rs index c86ee8b..2994d74 100644 --- a/edge-http/src/lib.rs +++ b/edge-http/src/lib.rs @@ -1411,7 +1411,7 @@ mod embedded_svc_compat { } } - impl<'b, const N: usize> embedded_svc::http::Query for super::RequestHeaders<'b, N> { + impl embedded_svc::http::Query for super::RequestHeaders<'_, N> { fn uri(&self) -> &'_ str { self.path } @@ -1421,13 +1421,13 @@ mod embedded_svc_compat { } } - impl<'b, const N: usize> embedded_svc::http::Headers for super::RequestHeaders<'b, N> { + impl embedded_svc::http::Headers for super::RequestHeaders<'_, N> { fn header(&self, name: &str) -> Option<&'_ str> { self.headers.get(name) } } - impl<'b, const N: usize> embedded_svc::http::Status for super::ResponseHeaders<'b, N> { + impl embedded_svc::http::Status for super::ResponseHeaders<'_, N> { fn status(&self) -> u16 { self.code } @@ -1437,13 +1437,13 @@ mod embedded_svc_compat { } } - impl<'b, const N: usize> embedded_svc::http::Headers for super::ResponseHeaders<'b, N> { + impl embedded_svc::http::Headers for super::ResponseHeaders<'_, N> { fn header(&self, name: &str) -> Option<&'_ str> { self.headers.get(name) } } - impl<'b, const N: usize> embedded_svc::http::Headers for super::Headers<'b, N> { + impl embedded_svc::http::Headers for super::Headers<'_, N> { fn header(&self, name: &str) -> Option<&'_ str> { self.get(name) }