fix(cli): Racing on playground webserver port binding

This commit is contained in:
Andrew Hlynskyi 2022-11-09 04:55:52 +02:00
parent fb5fbdd787
commit a33e9141a8
2 changed files with 21 additions and 20 deletions

View file

@ -35,7 +35,7 @@ rustc-hash = "1"
semver = "1.0"
serde = { version = "1.0.130", features = ["derive"] }
smallbitvec = "2.5.1"
tiny_http = "0.8"
tiny_http = "0.12.0"
walkdir = "2.3"
webbrowser = "0.5.1"
which = "4.1.0"

View file

@ -45,20 +45,7 @@ fn get_main_html(tree_sitter_dir: &Option<PathBuf>) -> Cow<'static, [u8]> {
}
pub fn serve(grammar_path: &Path, open_in_browser: bool) {
let port = env::var("TREE_SITTER_PLAYGROUND_PORT")
.map(|v| v.parse::<u16>().expect("Invalid port specification"))
.unwrap_or_else(
|_| get_available_port().expect(
"Couldn't find an available port, try providing a port number via the TREE_SITTER_PLAYGROUND_PORT \
environment variable"
)
);
let addr = format!(
"{}:{}",
env::var("TREE_SITTER_PLAYGROUND_ADDR").unwrap_or("127.0.0.1".to_owned()),
port
);
let server = Server::http(&addr).expect("Failed to start web server");
let server = get_server();
let grammar_name = wasm::get_grammar_name(&grammar_path.join("src"))
.with_context(|| "Failed to get wasm filename")
.unwrap();
@ -71,7 +58,7 @@ pub fn serve(grammar_path: &Path, open_in_browser: bool) {
)
})
.unwrap();
let url = format!("http://{}", addr);
let url = format!("http://{}", server.server_addr());
println!("Started playground on: {}", url);
if open_in_browser {
if let Err(_) = webbrowser::open(&url) {
@ -135,10 +122,24 @@ fn response<'a>(data: &'a [u8], header: &Header) -> Response<&'a [u8]> {
.with_header(header.clone())
}
fn get_available_port() -> Option<u16> {
(8000..12000).find(port_is_available)
fn get_server() -> Server {
let addr = env::var("TREE_SITTER_PLAYGROUND_ADDR").unwrap_or("127.0.0.1".to_owned());
let port = env::var("TREE_SITTER_PLAYGROUND_PORT")
.map(|v| v.parse::<u16>().expect("Invalid port specification"))
.ok();
let listener = match port {
Some(port) => bind_to(&*addr, port).expect("Can't bind to the specified port"),
None => {
get_listener_on_available_port(&*addr).expect("Can't find a free port to bind to it")
}
};
Server::from_listener(listener, None).expect("Failed to start web server")
}
fn port_is_available(port: &u16) -> bool {
TcpListener::bind(("127.0.0.1", *port)).is_ok()
fn get_listener_on_available_port(addr: &str) -> Option<TcpListener> {
(8000..12000).find_map(|port| bind_to(addr, port))
}
fn bind_to(addr: &str, port: u16) -> Option<TcpListener> {
TcpListener::bind(format!("{addr}:{port}")).ok()
}