diff --git a/Cargo.toml b/Cargo.toml index a6f5b6e29..87f838a22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -124,5 +124,6 @@ members = [ "examples/websocket-chat", "examples/web-cors/backend", "examples/unix-socket", + "examples/catflap", "tools/wsload/", ] diff --git a/examples/catflap/Cargo.toml b/examples/catflap/Cargo.toml new file mode 100644 index 000000000..0cde544ad --- /dev/null +++ b/examples/catflap/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "catflap" +version = "0.1.0" +authors = ["ivegotasthma "] +workspace = "../.." + +[dependencies] +env_logger = "0.5" +actix = "0.5" +actix-web = { path = "../../" } diff --git a/examples/catflap/README.md b/examples/catflap/README.md new file mode 100644 index 000000000..166332fa7 --- /dev/null +++ b/examples/catflap/README.md @@ -0,0 +1,24 @@ +# catflap + +There is the utility [cargo-watch](https://github.com/passcod/cargo-watch) which rebuilds your project when it notices +there are changed files. This is very useful when writing web server and you want to have a fast edit, compile, run +cycle. + +The problem is that when you're using this for a web server the socket that the server uses might still be in use +from the previous run. This makes `cargo-watch` crash. The solution, from the author of `cargo-watch` is `catflap`. It's +another utility that takes ownership of sockets and passes them the program you're running with cargo watch. + +To be able to use the sockets provided by `catflap` you need to read the file descriptor from the environment variable +`LISTEN_FD`. + +This example will how you how to do that on a hello world. + +By default the server will be running on port `5000`, unless you pass the flag `-p 8080` to catflap. Then it will run on +port `8080` + +## Usage +```bash +cd actix-web/examples/catflap +catflap -- cargo watch -x run +# Started http server: 127.0.0.1:8080 +``` diff --git a/examples/catflap/src/main.rs b/examples/catflap/src/main.rs new file mode 100644 index 000000000..6f2238a53 --- /dev/null +++ b/examples/catflap/src/main.rs @@ -0,0 +1,29 @@ +extern crate actix; +extern crate actix_web; +extern crate env_logger; + +use actix_web::*; + + +fn index(_req: HttpRequest) -> &'static str { + "hello, world" +} + +fn main() { + ::std::env::set_var("RUST_LOG", "actix_web=info"); + let _ = env_logger::init(); + let sys = actix::System::new("catflap-example"); + + let fd = std::env::var("LISTEN_FD").ok() + .and_then(|fd| fd.parse().ok()) + .expect("couldn't get LISTEN_FD env variable"); + + let _addr = HttpServer::new( + || Application::new() + .resource("/", |r| r.f(index))) + .bind_socket(fd).unwrap() + .start(); + + println!("Started http server."); + let _ = sys.run(); +} diff --git a/examples/diesel/README.md b/examples/diesel/README.md index 922ba1e3b..be6872dba 100644 --- a/examples/diesel/README.md +++ b/examples/diesel/README.md @@ -19,7 +19,7 @@ diesel migration run # if ubuntu : sudo apt-get install libsqlite3-dev # if fedora : sudo dnf install libsqlite3x-devel cd actix-web/examples/diesel -cargo run (or ``cargo watch -x run``) +cargo run (or see examples/catflap for rebuilding and redeploying on file change) # Started http server: 127.0.0.1:8080 ``` @@ -40,4 +40,4 @@ sqlite> select * from users; ## Postgresql -You will also find another complete example of diesel+postgresql on [https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix) \ No newline at end of file +You will also find another complete example of diesel+postgresql on [https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix) diff --git a/examples/juniper/README.md b/examples/juniper/README.md index 2ac0eac4e..906460b6f 100644 --- a/examples/juniper/README.md +++ b/examples/juniper/README.md @@ -6,7 +6,7 @@ Juniper integration for Actix web ```bash cd actix-web/examples/juniper -cargo run (or ``cargo watch -x run``) +cargo run (or see examples/catflap for rebuilding and redeploying on file change) # Started http server: 127.0.0.1:8080 ``` diff --git a/examples/multipart/README.md b/examples/multipart/README.md index 348d28687..57d086fa8 100644 --- a/examples/multipart/README.md +++ b/examples/multipart/README.md @@ -8,7 +8,7 @@ Multipart's `Getting Started` guide for Actix web ```bash cd actix-web/examples/multipart -cargo run (or ``cargo watch -x run``) +cargo run (or see examples/catflap for rebuilding and redeploying on file change) # Started http server: 127.0.0.1:8080 ``` diff --git a/examples/template_tera/README.md b/examples/template_tera/README.md index 35829599f..8e926bd4f 100644 --- a/examples/template_tera/README.md +++ b/examples/template_tera/README.md @@ -8,7 +8,7 @@ Minimal example of using the template [tera](https://github.com/Keats/tera) that ```bash cd actix-web/examples/template_tera -cargo run (or ``cargo watch -x run``) +cargo run (or see examples/catflap for rebuilding and redeploying on file change) # Started http server: 127.0.0.1:8080 ``` diff --git a/examples/tls/README.md b/examples/tls/README.md index 1bc9ba3b7..b23edad01 100644 --- a/examples/tls/README.md +++ b/examples/tls/README.md @@ -6,7 +6,7 @@ ```bash cd actix-web/examples/tls -cargo run (or ``cargo watch -x run``) +cargo run (or see examples/catflap for rebuilding and redeploying on file change) # Started http server: 127.0.0.1:8443 ``` diff --git a/src/server/srv.rs b/src/server/srv.rs index 69ff9012f..7b725e100 100644 --- a/src/server/srv.rs +++ b/src/server/srv.rs @@ -18,6 +18,9 @@ use native_tls::TlsAcceptor; #[cfg(feature="alpn")] use openssl::ssl::{AlpnError, SslAcceptorBuilder}; +#[cfg(target_family="unix")] +use std::os::unix::io::{FromRawFd, RawFd}; + use helpers; use super::{IntoHttpHandler, IoStream, KeepAlive}; use super::{PauseServer, ResumeServer, StopServer}; @@ -192,9 +195,22 @@ impl HttpServer where H: IntoHttpHandler + 'static self } + #[cfg(target_family="unix")] + /// The socket to bind to + /// + /// To bind multiple sockets this method can be called multiple times. + pub fn bind_socket(mut self, sock: RawFd) -> io::Result { + unsafe { + let lst = net::TcpListener::from_raw_fd(sock); + self.sockets.insert(lst.local_addr().unwrap(), lst); + } + + Ok(self) + } + /// The socket address to bind /// - /// To mind multiple addresses this method can be call multiple times. + /// To bind multiple addresses this method can be called multiple times. pub fn bind(mut self, addr: S) -> io::Result { let mut err = None; let mut succ = false;