Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(cli): Racing on playground webserver port binding #1953

Merged
merged 1 commit into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
39 changes: 20 additions & 19 deletions cli/src/playground.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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) {
Expand Down Expand Up @@ -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 get_listener_on_available_port(addr: &str) -> Option<TcpListener> {
(8000..12000).find_map(|port| bind_to(addr, port))
ahlinc marked this conversation as resolved.
Show resolved Hide resolved
}

fn port_is_available(port: &u16) -> bool {
TcpListener::bind(("127.0.0.1", *port)).is_ok()
fn bind_to(addr: &str, port: u16) -> Option<TcpListener> {
TcpListener::bind(format!("{addr}:{port}")).ok()
}