From 8bbe3402e14dc5ddd8736242d68725593ce941f2 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 30 Sep 2024 18:59:23 +0200 Subject: [PATCH] Replace `host_web_viewer` method with `WebViewerConfig::host_web_viewer` --- crates/top/re_sdk/src/web_viewer.rs | 128 +++++++++++++++----- crates/top/rerun/src/commands/entrypoint.rs | 35 +++--- 2 files changed, 116 insertions(+), 47 deletions(-) diff --git a/crates/top/re_sdk/src/web_viewer.rs b/crates/top/re_sdk/src/web_viewer.rs index 8322619802c3..44b35bf42577 100644 --- a/crates/top/re_sdk/src/web_viewer.rs +++ b/crates/top/re_sdk/src/web_viewer.rs @@ -106,41 +106,107 @@ impl Drop for WebViewerSink { // ---------------------------------------------------------------------------- -/// Helper to spawn an instance of the [`WebViewerServer`]. -/// This serves the HTTP+Wasm+JS files that make up the web-viewer. -/// -/// Optionally opens a browser with the web-viewer and connects to the provided `target_url`. -/// This url could be a hosted RRD file or a `ws://` url to a running [`re_ws_comms::RerunServer`]. -/// -/// Note: this does not include the websocket server. -/// -/// - `force_wgpu_backend` is an optional string to force a specific backend, either `webgl` or `webgpu`. +/// Helper to spawn an instance of the [`WebViewerServer`] and configure a webviewer url. #[cfg(feature = "web_viewer")] -pub fn host_web_viewer( - bind_ip: &str, - web_port: WebViewerServerPort, - force_wgpu_backend: Option, - video_decoder: Option, - open_browser: bool, - source_url: &str, -) -> anyhow::Result { - let web_server = WebViewerServer::new(bind_ip, web_port)?; - let http_web_viewer_url = web_server.server_url(); - - let mut viewer_url = format!("{http_web_viewer_url}?url={source_url}"); - if let Some(force_graphics) = force_wgpu_backend { - viewer_url = format!("{viewer_url}&renderer={force_graphics}"); - } - if let Some(video_decoder) = video_decoder { - viewer_url = format!("{viewer_url}&video_decoder={video_decoder}"); - } +pub struct WebViewerConfig { + /// Ip to which the http server is bound. + /// + /// Defaults to 0.0.0.0 + pub bind_ip: String, + + /// The port to which the webviewer should bind. + /// + /// Defaults to [`WebViewerServerPort::AUTO`]. + pub web_port: WebViewerServerPort, + + /// The url from which a spawned webviewer should source + /// + /// This url could be a hosted RRD file or a `ws://` url to a running [`re_ws_comms::RerunServer`]. + /// Has no effect if [`Self::open_browser`] is false. + pub source_url: Option, + + /// If set, adjusts the browser url to force a specific backend, either `webgl` or `webgpu`. + /// + /// Has no effect if [`Self::open_browser`] is false. + pub force_wgpu_backend: Option, + + /// If set, adjusts the browser url to set the video decoder setting, either `auto`, `prefer_software` or `prefer_hardware`. + /// + /// Has no effect if [`Self::open_browser`] is false. + pub video_decoder: Option, + + /// If set to `true`, opens the default browser after hosting the webviewer. + /// + /// Defaults to `true`. + pub open_browser: bool, +} - re_log::info!("Hosting a web-viewer at {viewer_url}"); - if open_browser { - webbrowser::open(&viewer_url).ok(); +#[cfg(feature = "web_viewer")] +impl Default for WebViewerConfig { + fn default() -> Self { + Self { + bind_ip: "0.0.0.0".to_owned(), + web_port: WebViewerServerPort::AUTO, + source_url: None, + force_wgpu_backend: None, + video_decoder: None, + open_browser: true, + } } +} - Ok(web_server) +#[cfg(feature = "web_viewer")] +impl WebViewerConfig { + /// Helper to spawn an instance of the [`WebViewerServer`]. + /// This serves the HTTP+Wasm+JS files that make up the web-viewer. + /// + /// The server will immediately start listening for incoming connections + /// and stop doing so when the returned [`WebViewerServer`] is dropped. + /// + /// Note: this does not include the websocket server. + pub fn host_web_viewer(self) -> Result { + let Self { + bind_ip, + source_url, + web_port, + force_wgpu_backend, + video_decoder, + open_browser, + } = self; + + let web_server = WebViewerServer::new(&bind_ip, web_port)?; + let http_web_viewer_url = web_server.server_url(); + + let mut viewer_url = http_web_viewer_url; + + let mut first_arg = true; + let mut append_argument = |arg| { + let arg_delimiter = if first_arg { + first_arg = false; + "?" + } else { + "&" + }; + viewer_url = format!("{viewer_url}{arg_delimiter}{arg}"); + }; + + if let Some(source_url) = source_url { + append_argument(format!("url={source_url}")); + } + if let Some(force_graphics) = force_wgpu_backend { + append_argument(format!("renderer={force_graphics}")); + } + if let Some(video_decoder) = video_decoder { + append_argument(format!("video_decoder={video_decoder}")); + } + + re_log::info!("Hosting a web-viewer at {viewer_url}"); + if open_browser { + webbrowser::open(&viewer_url).ok(); + } + + Ok(web_server) + } } // ---------------------------------------------------------------------------- diff --git a/crates/top/rerun/src/commands/entrypoint.rs b/crates/top/rerun/src/commands/entrypoint.rs index d204090198b5..8254809ea4e1 100644 --- a/crates/top/rerun/src/commands/entrypoint.rs +++ b/crates/top/rerun/src/commands/entrypoint.rs @@ -8,7 +8,7 @@ use re_smart_channel::{ReceiveSet, Receiver, SmartMessagePayload}; use crate::{commands::RrdCommands, CallSource}; #[cfg(feature = "web_viewer")] -use re_sdk::web_viewer::host_web_viewer; +use re_sdk::web_viewer::WebViewerConfig; #[cfg(feature = "web_viewer")] use re_web_viewer_server::WebViewerServerPort; #[cfg(feature = "server")] @@ -680,14 +680,16 @@ fn run_impl( if let DataSource::WebSocketAddr(rerun_server_ws_url) = data_sources[0].clone() { // Special case! We are connecting a web-viewer to a web-socket address. // Instead of piping, just host a web-viewer that connects to the web-socket directly: - host_web_viewer( - &args.bind, - args.web_viewer_port, - args.renderer, - args.video_decoder, - true, - &rerun_server_ws_url, - )? + + WebViewerConfig { + bind_ip: args.bind, + web_port: args.web_viewer_port, + source_url: Some(rerun_server_ws_url), + force_wgpu_backend: args.renderer, + video_decoder: args.video_decoder, + open_browser: true, + } + .host_web_viewer()? .block(); return Ok(()); @@ -755,14 +757,15 @@ fn run_impl( let open_browser = args.web_viewer; // This is the server that serves the Wasm+HTML: - host_web_viewer( - &args.bind, - args.web_viewer_port, - args.renderer, - args.video_decoder, + WebViewerConfig { + bind_ip: args.bind, + web_port: args.web_viewer_port, + source_url: Some(_ws_server.server_url()), + force_wgpu_backend: args.renderer, + video_decoder: args.video_decoder, open_browser, - &_ws_server.server_url(), - )? + } + .host_web_viewer()? .block(); // dropping should stop the server }