From 718572f537a8f7aabe0adacbc47318e61dc58293 Mon Sep 17 00:00:00 2001 From: Filip Tibell Date: Tue, 13 Feb 2024 17:42:01 +0100 Subject: [PATCH] Start setting up new server --- Cargo.lock | 29 ++++++++++ Cargo.toml | 4 ++ src/lune/builtins/net/config.rs | 2 +- src/lune/builtins/net/mod.rs | 4 +- src/lune/builtins/net/server.rs | 96 +++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 src/lune/builtins/net/server.rs diff --git a/Cargo.lock b/Cargo.lock index 189f4e6..9911fb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1164,6 +1164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" dependencies = [ "bytes", + "futures-channel", "futures-util", "http 1.0.0", "http-body 1.0.0", @@ -1171,6 +1172,9 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1356,8 +1360,10 @@ dependencies = [ "env_logger", "futures-util", "glam", + "http-body-util", "hyper 1.1.0", "hyper-tungstenite", + "hyper-util", "include_dir", "itertools", "lz4_flex", @@ -2805,6 +2811,28 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -2817,6 +2845,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", diff --git a/Cargo.toml b/Cargo.toml index 12fef19..bbdcf08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,10 +109,14 @@ toml = { version = "0.8", features = ["preserve_order"] } ### NET hyper = { version = "1.1", features = ["full"] } +hyper-util = { version = "0.1", features = ["full"] } +http-body-util = { version = "0.1" } hyper-tungstenite = { version = "0.13" } + reqwest = { version = "0.11", default-features = false, features = [ "rustls-tls", ] } + tokio-tungstenite = { version = "0.21", features = ["rustls-tls-webpki-roots"] } ### DATETIME diff --git a/src/lune/builtins/net/config.rs b/src/lune/builtins/net/config.rs index 725305a..5d02d2b 100644 --- a/src/lune/builtins/net/config.rs +++ b/src/lune/builtins/net/config.rs @@ -167,7 +167,7 @@ impl<'lua> FromLua<'lua> for ServeConfig<'lua> { Ok(ServeConfig { handle_request: f.clone(), handle_web_socket: None, - address: DEFAULT_IP_ADDRESS.clone(), + address: DEFAULT_IP_ADDRESS, }) } else if let LuaValue::Table(t) = &value { // Table means custom options diff --git a/src/lune/builtins/net/mod.rs b/src/lune/builtins/net/mod.rs index 8b21472..6253dec 100644 --- a/src/lune/builtins/net/mod.rs +++ b/src/lune/builtins/net/mod.rs @@ -5,6 +5,7 @@ use mlua_luau_scheduler::LuaSpawnExt; mod client; mod config; +mod server; mod util; mod websocket; @@ -13,6 +14,7 @@ use crate::lune::util::TableBuilder; use self::{ client::{NetClient, NetClientBuilder}, config::{RequestConfig, ServeConfig}, + server::serve, util::create_user_agent_header, websocket::NetWebSocket, }; @@ -63,7 +65,7 @@ async fn net_serve<'lua>( lua: &'lua Lua, (port, config): (u16, ServeConfig<'lua>), ) -> LuaResult> { - unimplemented!() + serve(lua, port, config).await } fn net_url_encode<'lua>( diff --git a/src/lune/builtins/net/server.rs b/src/lune/builtins/net/server.rs new file mode 100644 index 0000000..501a5f1 --- /dev/null +++ b/src/lune/builtins/net/server.rs @@ -0,0 +1,96 @@ +use std::{convert::Infallible, net::SocketAddr}; + +use http_body_util::Full; +use hyper_util::rt::TokioIo; +use tokio::{net::TcpListener, spawn, sync::mpsc::channel}; + +use hyper::{ + body::{Bytes, Incoming}, + server::conn::http1, + service::service_fn, + Request, Response, +}; + +use mlua::prelude::*; + +use crate::lune::util::TableBuilder; + +use super::config::ServeConfig; + +const SERVER_IMPL_LUA: &str = r#" +spawn(function() + while true do + local id, request, socket, exit = server:next() + if exit then + break + end + spawn(function() + if socket ~= nil then + local handler = server:getRequestHandler() + local response = handler(request) + server:respond(id, response) + elseif request ~= nil then + local handler = server:getWebsocketHandler() + handler(socket) + end + end) + end +end) +"#; + +pub(super) async fn serve<'lua>( + lua: &'lua Lua, + port: u16, + config: ServeConfig<'lua>, +) -> LuaResult> { + let addr = SocketAddr::from((config.address, port)); + let listener = TcpListener::bind(addr).await.map_err(|e| { + LuaError::external(format!( + "Failed to bind to {addr}\n{}", + e.to_string() + .replace("error creating server listener: ", "> ") + )) + })?; + + // Spawn a new task to accept incoming connections + listening for shutdown + let (shutdown_tx, mut shutdown_rx) = channel::<()>(1); + spawn(async move { + loop { + tokio::select! { + // If we receive a shutdown signal, break the loop + _ = shutdown_rx.recv() => break, + // Each connection gets its own task that forwards to lua + accepted = listener.accept() => { + match accepted { + Err(e) => println!("Error accepting connection: {e}"), + Ok((s, _)) => { + let io = TokioIo::new(s); + spawn(async move { + if let Err(err) = http1::Builder::new() + .serve_connection(io, service_fn(|_| async move { + // TODO: Forward to lua somehow + Ok::<_, Infallible>(Response::new(Full::new(Bytes::from("Hello, World!")))) + })) + .await + { + println!("Error serving connection: {err:?}"); + } + }); + } + } + } + } + } + }); + + // Create a new read-only table that contains methods + // for manipulating server behavior and shutting it down + let handle_stop = move |_, _: ()| match shutdown_tx.try_send(()) { + Err(_) => Err(LuaError::runtime("Server has already been stopped")), + Ok(_) => Ok(()), + }; + + TableBuilder::new(lua)? + .with_function("stop", handle_stop)? + .build_readonly() +}