diff --git a/CHANGELOG.md b/CHANGELOG.md index e9f88be0..1c4fc3ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.7.0 +## socketioxide +* Fix [#154](https://github.com/Totodore/socketioxide/issues/154), build was broken when using the `hyper-v1` feature flag because of `hyper-util` dependencie which is not published on crates.io. + # 0.7.0 ## socketioxide * The `extensions` field on sockets has been moved to a separate optional feature flag named `extensions` diff --git a/Cargo.lock b/Cargo.lock index c7027ee2..7460eaec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,7 +84,7 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "angular-todomvc" -version = "0.7.0" +version = "0.7.1" dependencies = [ "axum", "serde", @@ -171,7 +171,7 @@ dependencies = [ [[package]] name = "axum-echo" -version = "0.7.0" +version = "0.7.1" dependencies = [ "axum", "serde_json", @@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "background-task" -version = "0.7.0" +version = "0.7.1" dependencies = [ "axum", "serde", @@ -218,7 +218,7 @@ checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "basic-crud-application" -version = "0.7.0" +version = "0.7.1" dependencies = [ "axum", "serde", @@ -566,7 +566,7 @@ dependencies = [ [[package]] name = "engineio-echo" -version = "0.7.0" +version = "0.7.1" dependencies = [ "hyper 0.14.27", "serde_json", @@ -579,7 +579,7 @@ dependencies = [ [[package]] name = "engineioxide" -version = "0.7.0" +version = "0.7.1" dependencies = [ "async-trait", "base64", @@ -590,7 +590,6 @@ dependencies = [ "http-body 1.0.0-rc.2", "hyper 0.14.27", "hyper 1.0.0-rc.4", - "hyper-util", "memchr", "pin-project", "rand", @@ -607,7 +606,7 @@ dependencies = [ [[package]] name = "engineioxide-e2e" -version = "0.7.0" +version = "0.7.1" dependencies = [ "engineioxide", "hyper 0.14.27", @@ -998,7 +997,7 @@ dependencies = [ [[package]] name = "hyper-echo" -version = "0.7.0" +version = "0.7.1" dependencies = [ "hyper 0.14.27", "serde_json", @@ -1029,7 +1028,7 @@ dependencies = [ [[package]] name = "hyper-v1-echo" -version = "0.7.0" +version = "0.7.1" dependencies = [ "hyper 1.0.0-rc.4", "hyper-util", @@ -1443,7 +1442,7 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "private-messaging" -version = "0.7.0" +version = "0.7.1" dependencies = [ "axum", "serde", @@ -1638,7 +1637,7 @@ dependencies = [ [[package]] name = "salvo-echo" -version = "0.7.0" +version = "0.7.1" dependencies = [ "salvo", "serde_json", @@ -1885,7 +1884,7 @@ dependencies = [ [[package]] name = "socketio-chat" -version = "0.7.0" +version = "0.7.1" dependencies = [ "axum", "serde", @@ -1900,7 +1899,7 @@ dependencies = [ [[package]] name = "socketioxide" -version = "0.7.0" +version = "0.7.1" dependencies = [ "axum", "criterion", @@ -1924,7 +1923,7 @@ dependencies = [ [[package]] name = "socketioxide-e2e" -version = "0.7.0" +version = "0.7.1" dependencies = [ "hyper 0.14.27", "serde_json", @@ -2497,7 +2496,7 @@ dependencies = [ [[package]] name = "whiteboard" -version = "0.7.0" +version = "0.7.1" dependencies = [ "axum", "serde", diff --git a/Cargo.toml b/Cargo.toml index 8272c4c6..c2bfcee4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ hyper-v1 = { package = "hyper", version = "1.0.0-rc.4", features = [ ] } [workspace.package] -version = "0.7.0" +version = "0.7.1" edition = "2021" rust-version = "1.67.0" authors = ["Théodore Prévot <"] diff --git a/engineioxide/Cargo.toml b/engineioxide/Cargo.toml index 85b1f416..a90f8071 100644 --- a/engineioxide/Cargo.toml +++ b/engineioxide/Cargo.toml @@ -39,7 +39,6 @@ unicode-segmentation = { version = "1.10.1", optional = true } # Hyper v1.0 hyper-v1 = { workspace = true, optional = true } http-body-v1 = { workspace = true, optional = true } -hyper-util = { git = "https://github.com/hyperium/hyper-util.git", optional = true, version = "0" } [dev-dependencies] tokio = { workspace = true, features = ["macros", "parking_lot"] } @@ -57,4 +56,4 @@ hyper = { version = "0.14.25", features = [ v3 = ["memchr", "unicode-segmentation"] test-utils = [] tracing = ["dep:tracing"] -hyper-v1 = ["dep:hyper-v1", "dep:http-body-v1", "dep:hyper-util"] +hyper-v1 = ["dep:hyper-v1", "dep:http-body-v1"] diff --git a/engineioxide/src/transport/ws.rs b/engineioxide/src/transport/ws/mod.rs similarity index 98% rename from engineioxide/src/transport/ws.rs rename to engineioxide/src/transport/ws/mod.rs index c0d6a8a1..1f5a0807 100644 --- a/engineioxide/src/transport/ws.rs +++ b/engineioxide/src/transport/ws/mod.rs @@ -34,6 +34,9 @@ use crate::{ DisconnectReason, Socket, }; +#[cfg(feature = "hyper-v1")] +mod tokio_io; + /// Create a response for websocket upgrade fn ws_response(ws_key: &HeaderValue) -> Result>, http::Error> { let derived = derive_accept_key(ws_key.as_bytes()); @@ -82,11 +85,7 @@ pub fn new_req( #[cfg(feature = "hyper-v1")] let res = if hyper_v1 { // Wraps the hyper-v1 upgrade so it implement `AsyncRead` and `AsyncWrite` - Either::Left( - hyper_v1::upgrade::on(req) - .await - .map(hyper_util::rt::TokioIo::new), - ) + Either::Left(hyper_v1::upgrade::on(req).await.map(tokio_io::TokioIo::new)) } else { Either::Right(hyper::upgrade::on(req).await) }; diff --git a/engineioxide/src/transport/ws/tokio_io.rs b/engineioxide/src/transport/ws/tokio_io.rs new file mode 100644 index 00000000..010fec57 --- /dev/null +++ b/engineioxide/src/transport/ws/tokio_io.rs @@ -0,0 +1,163 @@ +#![allow(dead_code)] +//! This mod is a copy of https://github.com/hyperium/hyper-util/blob/master/src/rt/tokio_io.rs +//! Because the hyper-util is not yet published to crates.io +//! +//! It is an adapter from hyper v1 IO traits to tokio's IO traits. +use std::{ + pin::Pin, + task::{Context, Poll}, +}; + +/// A wrapping implementing hyper IO traits for a type that +/// implements Tokio's IO traits. +#[derive(Debug)] +#[pin_project::pin_project] +pub struct TokioIo { + #[pin] + inner: T, +} + +impl TokioIo { + /// Wrap a type implementing Tokio's IO traits. + pub fn new(inner: T) -> Self { + Self { inner } + } + + /// Borrow the inner type. + pub fn inner(&self) -> &T { + &self.inner + } + + /// Consume this wrapper and get the inner type. + pub fn into_inner(self) -> T { + self.inner + } +} + +impl hyper_v1::rt::Read for TokioIo +where + T: tokio::io::AsyncRead, +{ + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + mut buf: hyper_v1::rt::ReadBufCursor<'_>, + ) -> Poll> { + let n = unsafe { + let mut tbuf = tokio::io::ReadBuf::uninit(buf.as_mut()); + match tokio::io::AsyncRead::poll_read(self.project().inner, cx, &mut tbuf) { + Poll::Ready(Ok(())) => tbuf.filled().len(), + other => return other, + } + }; + + unsafe { + buf.advance(n); + } + Poll::Ready(Ok(())) + } +} + +impl hyper_v1::rt::Write for TokioIo +where + T: tokio::io::AsyncWrite, +{ + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + tokio::io::AsyncWrite::poll_write(self.project().inner, cx, buf) + } + + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + tokio::io::AsyncWrite::poll_flush(self.project().inner, cx) + } + + fn poll_shutdown( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + tokio::io::AsyncWrite::poll_shutdown(self.project().inner, cx) + } + + fn is_write_vectored(&self) -> bool { + tokio::io::AsyncWrite::is_write_vectored(&self.inner) + } + + fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[std::io::IoSlice<'_>], + ) -> Poll> { + tokio::io::AsyncWrite::poll_write_vectored(self.project().inner, cx, bufs) + } +} + +impl tokio::io::AsyncRead for TokioIo +where + T: hyper_v1::rt::Read, +{ + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + tbuf: &mut tokio::io::ReadBuf<'_>, + ) -> Poll> { + //let init = tbuf.initialized().len(); + let filled = tbuf.filled().len(); + let sub_filled = unsafe { + let mut buf = hyper_v1::rt::ReadBuf::uninit(tbuf.unfilled_mut()); + + match hyper_v1::rt::Read::poll_read(self.project().inner, cx, buf.unfilled()) { + Poll::Ready(Ok(())) => buf.filled().len(), + other => return other, + } + }; + + let n_filled = filled + sub_filled; + // At least sub_filled bytes had to have been initialized. + let n_init = sub_filled; + unsafe { + tbuf.assume_init(n_init); + tbuf.set_filled(n_filled); + } + + Poll::Ready(Ok(())) + } +} + +impl tokio::io::AsyncWrite for TokioIo +where + T: hyper_v1::rt::Write, +{ + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + hyper_v1::rt::Write::poll_write(self.project().inner, cx, buf) + } + + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + hyper_v1::rt::Write::poll_flush(self.project().inner, cx) + } + + fn poll_shutdown( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + hyper_v1::rt::Write::poll_shutdown(self.project().inner, cx) + } + + fn is_write_vectored(&self) -> bool { + hyper_v1::rt::Write::is_write_vectored(&self.inner) + } + + fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[std::io::IoSlice<'_>], + ) -> Poll> { + hyper_v1::rt::Write::poll_write_vectored(self.project().inner, cx, bufs) + } +} diff --git a/socketioxide/Cargo.toml b/socketioxide/Cargo.toml index cb1ac3be..95ea7432 100644 --- a/socketioxide/Cargo.toml +++ b/socketioxide/Cargo.toml @@ -14,7 +14,7 @@ readme = "../README.md" [dependencies] -engineioxide = { path = "../engineioxide", version = "0.7.0" } +engineioxide = { path = "../engineioxide", version = "0.7.1" } futures.workspace = true tokio = { workspace = true, features = ["rt"] } serde.workspace = true