Skip to content

Commit

Permalink
Add example of starting a local server and opening a browser
Browse files Browse the repository at this point in the history
Additionally, this demonstrates how to pick an open port, since this is
often relevent for local servers (Jupyter-like applications).

Cc: #751
  • Loading branch information
ilyagr committed Feb 20, 2024
1 parent dbadd19 commit be722a5
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ tracing-subscriber = { version = "0.3.9", features = ["env-filter"] }
serde_json = "1.0.68"
serde = { version = "1.0.140", features = ["derive"] }
mime = "0.3.16"
open = "5.0.1"
futures-util = "0.3.21"
tokio-stream = "0.1.8"
prost = "0.12.0"
11 changes: 11 additions & 0 deletions examples/poem/local-server-with-browser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "local-server-with-browser"
version.workspace = true
edition.workspace = true
publish.workspace = true

[dependencies]
open.workspace = true
poem.workspace = true
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
tracing-subscriber.workspace = true
58 changes: 58 additions & 0 deletions examples/poem/local-server-with-browser/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use poem::{
handler,
listener::{Listener, TcpListener},
Result, Route, Server,
};

#[handler]
fn hello() -> String {
"Hello from poem!\n".to_string()
}

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
let app = Route::new().at("/", poem::get(hello));
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "poem=debug");
}
tracing_subscriber::fmt::init();

// To test port assignment, run two instances of this example at once.
//
// For ports <1024, running with administrator priveleges would be needed on
// Unix. For port 0, the OS would assign a port and we'd need to find out
// what that port's number is.
let (min_port, max_port) = (8080, 8085);
// Using 127.0.0.1 instead of 0.0.0.0 for security; a local server should
// not, generally, be visible from the network.
let hostname = "127.0.0.1";
let mut port = min_port;
let mut error = None;
let acceptor = loop {
if port > max_port {
return Err(error.unwrap());
}
let listener = TcpListener::bind(format!("{hostname}:{}", port));
match listener.into_acceptor().await {
Ok(a) => break a,
Err(err) => {
// Most likely, another application is bound to this port.
eprintln!("Couldn't bind to port {port}.");
error = Some(err)
}
};
port += 1;
};

// Now that the acceptor exists, the browser should be able to connect IIUC.
let http_address = format!("http://{hostname}:{port}/");
eprintln!("Listening at {http_address}.");
eprint!("Trying to launch a browser at {http_address}...");
match open::that(&http_address) {
Ok(_) => eprintln!(" Success!"),
Err(err) => eprintln!("\nFailed to launch a browser: {err}"),
}

Server::new_with_acceptor(acceptor).run(app).await?;
Ok(())
}

0 comments on commit be722a5

Please sign in to comment.