diff --git a/Cargo.lock b/Cargo.lock index 5cb714f..28a309b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1178,6 +1178,17 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "listenfd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0500463acd96259d219abb05dc57e5a076ef04b2db9a2112846929b5f174c96" +dependencies = [ + "libc", + "uuid", + "winapi", +] + [[package]] name = "litemap" version = "0.7.3" @@ -1514,6 +1525,7 @@ dependencies = [ "futures-util", "image", "libwebp-sys", + "listenfd", "mimalloc", "once_cell", "qstring", @@ -2372,6 +2384,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" + [[package]] name = "v_frame" version = "0.3.8" @@ -2511,6 +2529,28 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 91444eb..c8af211 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ regex = "1.10.4" blake3 = { version = "1.5.1", optional = true } bytes = "1.6.0" futures-util = "0.3.30" +listenfd = "1.0.1" [features] default = ["webp", "mimalloc", "reqwest-rustls", "qhash"] diff --git a/src/main.rs b/src/main.rs index 9f00aa9..5ad870a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,12 +3,15 @@ mod utils; use actix_web::http::{Method, StatusCode}; use actix_web::{web, App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer}; +use listenfd::ListenFd; use once_cell::sync::Lazy; use qstring::QString; use regex::Regex; use reqwest::{Body, Client, Request, Url}; use std::error::Error; use std::io::ErrorKind; +use std::net::TcpListener; +use std::os::unix::net::UnixListener; use std::{env, io}; #[cfg(not(any(feature = "reqwest-native-tls", feature = "reqwest-rustls")))] @@ -23,27 +26,68 @@ use ump_stream::UmpTransformStream; #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +fn try_get_fd_listeners() -> (Option, Option) { + let mut fd = ListenFd::from_env(); + + let unix_listener = env::var("FD_UNIX").ok().map(|fd_unix| { + let fd_pos = fd_unix.parse().expect("FD_UNIX is not a number"); + println!("Trying to take Unix socket at position {}", fd_pos); + fd.take_unix_listener(fd_pos) + .expect(format!("fd {} is not a Unix socket", fd_pos).as_str()) + .expect(format!("fd {} has already been used", fd_pos).as_str()) + }); + + let tcp_listener = env::var("FD_TCP").ok().map(|fd_tcp| { + let fd_pos = fd_tcp.parse().expect("FD_TCP is not a number"); + println!("Trying to take TCP listener at position {}", fd_pos); + fd.take_tcp_listener(fd_pos) + .expect(format!("fd {} is not a TCP listener", fd_pos).as_str()) + .expect(format!("fd {} has already been used", fd_pos).as_str()) + }); + + (unix_listener, tcp_listener) +} + #[actix_web::main] async fn main() -> std::io::Result<()> { println!("Running server!"); - let server = HttpServer::new(|| { + let mut server = HttpServer::new(|| { // match all requests App::new().default_service(web::to(index)) }); - // get socket/port from env - // backwards compat when only UDS is set - if utils::get_env_bool("UDS") { - let socket_path = - env::var("BIND_UNIX").unwrap_or_else(|_| "./socket/actix.sock".to_string()); - server.bind_uds(socket_path)? - } else { - let bind = env::var("BIND").unwrap_or_else(|_| "0.0.0.0:8080".to_string()); - server.bind(bind)? + let fd_listeners = try_get_fd_listeners(); + + if let Some(unix_listener) = fd_listeners.0 { + server = server + .listen_uds(unix_listener) + .expect("Error while trying to listen on Unix socket passed by fd"); + println!("Listening on Unix socket passed by fd."); } - .run() - .await + + if let Some(tcp_listener) = fd_listeners.1 { + server = server + .listen(tcp_listener) + .expect("Error while trying to listen on TCP listener passed by fd"); + println!("Listening on TCP listener passed by fd."); + } + + // Only bind manually if there is not already a listener + if server.addrs().is_empty() { + // get socket/port from env + // backwards compat when only UDS is set + server = if utils::get_env_bool("UDS") { + let socket_path = + env::var("BIND_UNIX").unwrap_or_else(|_| "./socket/actix.sock".to_string()); + server.bind_uds(socket_path)? + } else { + let bind = env::var("BIND").unwrap_or_else(|_| "0.0.0.0:8080".to_string()); + server.bind(bind)? + }; + } + + server.run().await } static RE_DOMAIN: Lazy =