From 4c9fd0d302b2212cba8d06473f477899007f4c25 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Fri, 19 Oct 2018 16:33:11 +0200 Subject: [PATCH] Do not panic if something is already bound to 1111 in serve --- CHANGELOG.md | 1 + components/site/src/lib.rs | 7 +++++-- components/utils/src/net.rs | 6 +++--- src/cmd/serve.rs | 6 +++--- src/main.rs | 25 ++++++++++++++++++++++++- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbc2068..7741f6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ sections up to the index to be used with the `get_section` Tera function - Add a `load_data` Tera function to load local CSV/TOML/JSON files - Add `relative_path` to pages and sections in templates - Do not have a trailing slash for the RSS permalinks +- `serve` will now try to find other ports than 1111 rather than panicking ## 0.4.2 (2018-09-03) diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index 778f4df..f2a6f0e 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -146,8 +146,11 @@ impl Site { self.content_path.join("_index.md") } - pub fn enable_live_reload(&mut self) { - self.live_reload = get_available_port(); + /// We avoid the port the server is going to use as it's not bound yet + /// when calling this function and we could end up having tried to bind + /// both http and websocket server to the same port + pub fn enable_live_reload(&mut self, port_to_avoid: u16) { + self.live_reload = get_available_port(port_to_avoid); } /// Get all the orphan (== without section) pages in the site diff --git a/components/utils/src/net.rs b/components/utils/src/net.rs index 29c9376..6868ef0 100644 --- a/components/utils/src/net.rs +++ b/components/utils/src/net.rs @@ -1,12 +1,12 @@ use std::net::TcpListener; -pub fn get_available_port() -> Option { +pub fn get_available_port(avoid: u16) -> Option { (1000..9000) - .find(|port| port_is_available(*port)) + .find(|port| *port != avoid && port_is_available(*port)) } -fn port_is_available(port: u16) -> bool { +pub fn port_is_available(port: u16) -> bool { match TcpListener::bind(("127.0.0.1", port)) { Ok(_) => true, Err(_) => false, diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 6d7f888..adc948b 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -108,7 +108,7 @@ fn rebuild_done_handling(broadcaster: &Sender, res: Result<()>, reload_path: &st } } -fn create_new_site(interface: &str, port: &str, output_dir: &str, base_url: &str, config_file: &str) -> Result<(Site, String)> { +fn create_new_site(interface: &str, port: u16, output_dir: &str, base_url: &str, config_file: &str) -> Result<(Site, String)> { let mut site = Site::new(env::current_dir().unwrap(), config_file)?; let base_address = format!("{}:{}", base_url, port); @@ -122,7 +122,7 @@ fn create_new_site(interface: &str, port: &str, output_dir: &str, base_url: &str site.set_base_url(base_url); site.set_output_path(output_dir); site.load()?; - site.enable_live_reload(); + site.enable_live_reload(port); console::notify_site_size(&site); console::warn_about_ignored_pages(&site); site.build()?; @@ -147,7 +147,7 @@ fn handle_directory<'a, 'b>(dir: &'a fs::Directory, req: &'b HttpRequest) -> io: fs::NamedFile::open(path)?.respond_to(req) } -pub fn serve(interface: &str, port: &str, output_dir: &str, base_url: &str, config_file: &str) -> Result<()> { +pub fn serve(interface: &str, port: u16, output_dir: &str, base_url: &str, config_file: &str) -> Result<()> { let start = Instant::now(); let (mut site, address) = create_new_site(interface, port, output_dir, base_url, config_file)?; console::report_elapsed_time(start); diff --git a/src/main.rs b/src/main.rs index 9a11ab0..a09ce1f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,8 @@ extern crate rebuild; use std::time::Instant; +use utils::net::{get_available_port, port_is_available}; + mod cmd; mod console; mod cli; @@ -55,7 +57,28 @@ fn main() { }, ("serve", Some(matches)) => { let interface = matches.value_of("interface").unwrap_or("127.0.0.1"); - let port = matches.value_of("port").unwrap_or("1111"); + let mut port: u16 = match matches.value_of("port").unwrap().parse() { + Ok(x) => x, + Err(_) => { + console::error("The request port needs to be an integer"); + ::std::process::exit(1); + } + }; + // Default one + if port != 1111 && !port_is_available(port) { + console::error("The requested port is not available"); + ::std::process::exit(1); + } + + if !port_is_available(port) { + port = if let Some(p) = get_available_port(1111) { + p + } else { + console::error("No port available."); + ::std::process::exit(1); + } + } + let output_dir = matches.value_of("output_dir").unwrap(); let base_url = matches.value_of("base_url").unwrap(); console::info("Building site...");