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..59b612e 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, { @@ -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 8b20b61..0521c49 100644 --- a/edge-http/src/io/server.rs +++ b/edge-http/src/io/server.rs @@ -287,7 +287,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 +296,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 +331,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 +442,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 +547,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 +566,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 +616,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 +646,7 @@ impl Server { debug!("Handler task {task_id}: Got connection request"); - handle_connection::( + handle_connection::<_, _, N>( io, unsafe { buf.as_mut() }.unwrap(), task_id, @@ -649,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, { @@ -668,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, { @@ -724,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/lib.rs b/edge-http/src/lib.rs index 6fe9546..2994d74 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() @@ -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) } 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)?; } }