diff --git a/Cargo.lock b/Cargo.lock index 5fc749a..9b44f96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,6 +55,45 @@ dependencies = [ "version_check", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + [[package]] name = "hermit-abi" version = "0.2.6" @@ -64,18 +103,93 @@ dependencies = [ "libc", ] +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951dfc2e32ac02d67c90c0d65bd27009a635dc9b381a2cc7d284ab01e3a0150d" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92445bc9cc14bfa0a3ce56817dc3b5bcc227a168781a356b702410789cec0d10" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "1.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "289cfdbf735dea222b0ec6a10224b4d9552c7662bb451d4589cbfda3d407d1a3" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "tokio", + "tracing", + "want", +] + [[package]] name = "inlinable_string" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + [[package]] name = "lavina" version = "0.1.0" dependencies = [ "anyhow", "figment", + "http-body-util", + "hyper", "serde", "tokio", "tracing", @@ -215,6 +329,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "proc-macro2" version = "1.0.49" @@ -433,6 +553,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + [[package]] name = "uncased" version = "0.9.7" @@ -460,6 +586,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 68efc6f..3637219 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,8 @@ path = "src/main.rs" [dependencies] anyhow = "1.0.68" # error utils figment = { version = "0.10.8", features = ["env", "toml"] } # configuration files +hyper = { version = "1.0.0-rc.2", features = ["server", "http1"] } # http server +http-body-util = "0.1.0-rc.2" serde = { version = "1.0.152", features = ["rc", "serde_derive"] } tokio = { version = "1.24.1", features = ["full"] } # async runtime tracing = "0.1.37" # logging & tracing api diff --git a/src/http.rs b/src/http.rs new file mode 100644 index 0000000..1b6b906 --- /dev/null +++ b/src/http.rs @@ -0,0 +1,62 @@ +use crate::prelude::*; + +use http_body_util::Full; +use hyper::server::conn::http1; +use hyper::{body::Bytes, service::service_fn, Request, Response}; +use std::convert::Infallible; +use tokio::sync::oneshot::{Receiver, Sender}; +use tokio::task::JoinHandle; + +use tokio::net::TcpListener; + +pub struct HttpServerActor { + terminator: Sender<()>, + fiber: JoinHandle>, +} +impl HttpServerActor { + pub async fn launch(listener: TcpListener) -> Result { + let (terminator, receiver) = tokio::sync::oneshot::channel::<()>(); + let fiber = tokio::task::spawn(Self::main_loop(listener, receiver)); + Ok(HttpServerActor { terminator, fiber }) + } + + pub async fn terminate(self) -> Result<()> { + match self.terminator.send(()) { + Ok(_) => {} + Err(_) => failure("wat")?, + } + self.fiber.await??; + Ok(()) + } + + async fn hello( + _: Request, + ) -> std::result::Result>, Infallible> { + Ok(Response::new(Full::new(Bytes::from("Hello World!")))) + } + + async fn main_loop(listener: TcpListener, termination: impl Future) -> Result<()> { + log::info!("Starting the http server"); + pin!(termination); + + loop { + select! { + _ = &mut termination => { + log::info!("Terminating the http server"); + return Ok(()) + }, + result = listener.accept() => { + let (stream, _) = result?; + tokio::task::spawn(async move { + if let Err(err) = http1::Builder::new() + .serve_connection(stream, service_fn(HttpServerActor::hello)) + .await + { + tracing::error!("Error serving connection: {:?}", err); + } + }); + }, + } + } + } +} diff --git a/src/main.rs b/src/main.rs index 50971d8..81816e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,7 @@ -type Result = std::result::Result; +mod http; +mod prelude; + +use crate::prelude::*; use std::collections::HashMap; use std::future::Future; @@ -39,12 +42,16 @@ async fn main() -> Result<()> { dbg!(config); tracing::info!("Booting up"); let listener = TcpListener::bind("127.0.0.1:3721").await?; + let listener_http = TcpListener::bind("127.0.0.1:8080").await?; + let http_server_actor = http::HttpServerActor::launch(listener_http).await?; + tracing::info!("Started"); run(listener, sleep).await?; // sleep.await; tracing::info!("Begin shutdown"); + http_server_actor.terminate().await?; tracing::info!("Shutdown complete"); Ok(()) } diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..cb55e65 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,14 @@ +pub use tokio::pin; +pub use tokio::select; + +pub mod log { + pub use tracing::{debug, error, info, warn}; +} + +pub type Result = std::result::Result; + +pub fn failure(explain: &str) -> Result<()> { + panic!() +} + +pub use std::future::Future;