diff --git a/Cargo.lock b/Cargo.lock index d0af380..3deaa64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1831,6 +1831,7 @@ dependencies = [ name = "lune-std-net" version = "0.2.0" dependencies = [ + "async-executor", "async-io", "async-lock", "async-net", @@ -1843,6 +1844,7 @@ dependencies = [ "lune-utils", "mlua", "mlua-luau-scheduler", + "pin-project-lite", "rustls 0.23.26", "rustls-pki-types", "webpki", diff --git a/crates/lune-std-net/Cargo.toml b/crates/lune-std-net/Cargo.toml index e51d9a1..de8b421 100644 --- a/crates/lune-std-net/Cargo.toml +++ b/crates/lune-std-net/Cargo.toml @@ -16,6 +16,7 @@ workspace = true mlua = { version = "0.10.3", features = ["luau"] } mlua-luau-scheduler = { version = "0.1.0", path = "../mlua-luau-scheduler" } +async-executor = "1.13" async-io = "2.4" async-lock = "3.4" async-net = "2.0" @@ -24,6 +25,7 @@ bstr = "1.9" futures-lite = "2.6" futures-rustls = "0.26" hyper = "1.6" +pin-project-lite = "0.2" rustls = "0.23" rustls-pki-types = "1.11" webpki = "0.22" diff --git a/crates/lune-std-net/src/client/hyper.rs b/crates/lune-std-net/src/client/hyper.rs new file mode 100644 index 0000000..5a46e94 --- /dev/null +++ b/crates/lune-std-net/src/client/hyper.rs @@ -0,0 +1,159 @@ +use std::{ + future::Future, + io, + pin::Pin, + slice, + task::{Context, Poll}, + time::{Duration, Instant}, +}; + +use async_io::Timer; +use futures_lite::prelude::*; +use hyper::rt::{self, ReadBufCursor}; +use mlua::prelude::*; +use mlua_luau_scheduler::LuaSpawnExt; + +// Hyper executor that spawns futures onto our Lua scheduler + +#[derive(Debug)] +pub struct HyperExecutor { + lua: Lua, +} + +impl From for HyperExecutor { + fn from(lua: Lua) -> Self { + Self { lua } + } +} + +impl rt::Executor for HyperExecutor +where + Fut::Output: Send + 'static, +{ + fn execute(&self, fut: Fut) { + self.lua.spawn(fut).detach(); + } +} + +// Hyper timer & sleep future wrapper for async-io + +#[derive(Debug)] +pub struct HyperTimer; + +impl rt::Timer for HyperTimer { + fn sleep(&self, duration: Duration) -> Pin> { + Box::pin(HyperSleep::from(Timer::after(duration))) + } + + fn sleep_until(&self, at: Instant) -> Pin> { + Box::pin(HyperSleep::from(Timer::at(at))) + } + + fn reset(&self, sleep: &mut Pin>, new_deadline: Instant) { + if let Some(mut sleep) = sleep.as_mut().downcast_mut_pin::() { + sleep.inner.set_at(new_deadline); + } else { + *sleep = Box::pin(HyperSleep::from(Timer::at(new_deadline))); + } + } +} + +#[derive(Debug)] +pub struct HyperSleep { + inner: Timer, +} + +impl From for HyperSleep { + fn from(inner: Timer) -> Self { + Self { inner } + } +} + +impl Future for HyperSleep { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + match Pin::new(&mut self.inner).poll(cx) { + Poll::Ready(_) => Poll::Ready(()), + Poll::Pending => Poll::Pending, + } + } +} + +impl rt::Sleep for HyperSleep {} + +// Hyper I/O wrapper for futures-lite types + +pin_project_lite::pin_project! { + #[derive(Debug)] + pub struct HyperIo { + #[pin] + inner: T + } +} + +impl From for HyperIo { + fn from(inner: T) -> Self { + Self { inner } + } +} + +impl HyperIo { + pub fn pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { + self.project().inner + } +} + +impl rt::Read for HyperIo { + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + mut buf: ReadBufCursor<'_>, + ) -> Poll> { + // Fill the read buffer with initialized data + let read_slice = unsafe { + let buffer = buf.as_mut(); + buffer.as_mut_ptr().write_bytes(0, buffer.len()); + slice::from_raw_parts_mut(buffer.as_mut_ptr().cast::(), buffer.len()) + }; + + // Read bytes from the underlying source + let n = match self.pin_mut().poll_read(cx, read_slice) { + Poll::Ready(Ok(n)) => n, + Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), + Poll::Pending => return Poll::Pending, + }; + + unsafe { + buf.advance(n); + } + + Poll::Ready(Ok(())) + } +} + +impl rt::Write for HyperIo { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + self.pin_mut().poll_write(cx, buf) + } + + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.pin_mut().poll_flush(cx) + } + + fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.pin_mut().poll_close(cx) + } + + fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[io::IoSlice<'_>], + ) -> Poll> { + self.pin_mut().poll_write_vectored(cx, bufs) + } +} diff --git a/crates/lune-std-net/src/client/mod.rs b/crates/lune-std-net/src/client/mod.rs index 683e0b9..5ae1a78 100644 --- a/crates/lune-std-net/src/client/mod.rs +++ b/crates/lune-std-net/src/client/mod.rs @@ -1 +1,2 @@ +mod hyper; mod stream;