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

Add support for RecordingStream::serve #2815

Merged
merged 9 commits into from
Jul 26, 2023
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
14 changes: 13 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions crates/re_sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,26 @@ glam = ["re_components/glam"]
## Integration with the [`image`](https://crates.io/crates/image/) crate, plus JPEG support..
image = ["re_components/image"]

## Support serving a web viewer over HTTP.
##
## Enabling this inflates the binary size quite a bit, since it embeds the viewer wasm.
##
## For faster & easier builds, the web-player build comes bundled with the crate.
## Enabling this feature will embed this pre-built web-player.
##
## However, when building from source in the repository, this feature adds quite a bit
## to the compile time since it requires compiling and bundling the viewer as wasm.
## You also need to install some additional tools, which you can do by running
## [`scripts/setup_web.sh`](https://github.com/rerun-io/rerun/blob/main/scripts/setup_web.sh).
web_viewer = [
"dep:re_smart_channel",
"dep:re_web_viewer_server",
"dep:re_ws_comms",
"dep:anyhow",
"dep:webbrowser",
"re_ws_comms?/server",
]


[dependencies]
re_build_info.workspace = true
Expand All @@ -48,6 +68,15 @@ once_cell.workspace = true
parking_lot.workspace = true
thiserror.workspace = true

# Optional dependencies

re_smart_channel = { workspace = true, optional = true }
re_ws_comms = { workspace = true, optional = true }
re_web_viewer_server = { workspace = true, optional = true }

anyhow = { workspace = true, optional = true }
webbrowser = { version = "0.8", optional = true }


[dev-dependencies]
re_components = { workspace = true, features = ["arrow_datagen"] }
Expand Down
4 changes: 4 additions & 0 deletions crates/re_sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ pub mod experimental {
pub use re_types::{archetypes, components, datatypes, Archetype, Component, Datatype};
}

/// Methods for spawning the web viewer and streaming the SDK log stream to it.
#[cfg(feature = "web_viewer")]
pub mod web_viewer;

/// Re-exports of other crates.
pub mod external {
pub use re_log;
Expand Down
56 changes: 56 additions & 0 deletions crates/re_sdk/src/recording_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ use re_log_types::{
TimePoint, TimeType, Timeline, TimelineName,
};

#[cfg(feature = "web_viewer")]
use re_web_viewer_server::WebViewerServerPort;
#[cfg(feature = "web_viewer")]
use re_ws_comms::RerunServerPort;

use crate::sink::{LogSink, MemorySinkStorage};

// ---
Expand All @@ -31,6 +36,10 @@ pub enum RecordingStreamError {
name: &'static str,
err: Box<dyn std::error::Error + Send + Sync>,
},

#[cfg(feature = "web_viewer")]
#[error(transparent)]
WebSink(anyhow::Error),
}

pub type RecordingStreamResult<T> = Result<T, RecordingStreamError>;
Expand Down Expand Up @@ -259,6 +268,53 @@ impl RecordingStreamBuilder {
}
}

/// Creates a new [`RecordingStream`] that is pre-configured to stream the data through to a
/// web-based Rerun viewer via WebSockets.
///
/// This method needs to be called in a context where a Tokio runtime is already running (see
/// example below).
///
/// If the `open_browser` argument is `true`, your default browser will be opened with a
/// connected web-viewer.
///
/// If not, you can connect to this server using the `rerun` binary (`cargo install rerun-cli`).
///
/// ## Example
///
/// ```ignore
/// // Ensure we have a running tokio runtime.
/// let mut tokio_runtime = None;
/// let tokio_runtime_handle = if let Ok(handle) = tokio::runtime::Handle::try_current() {
/// handle
/// } else {
/// let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime");
/// tokio_runtime.get_or_insert(rt).handle().clone()
/// };
/// let _tokio_runtime_guard = tokio_runtime_handle.enter();
///
/// let rec_stream = re_sdk::RecordingStreamBuilder::new("my_app")
/// .serve("0.0.0.0", Default::default(), Default::default(), true)?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
#[cfg(feature = "web_viewer")]
pub fn serve(
self,
bind_ip: &str,
web_port: WebViewerServerPort,
ws_port: RerunServerPort,
open_browser: bool,
) -> RecordingStreamResult<RecordingStream> {
let (enabled, store_info, batcher_config) = self.into_args();
if enabled {
let sink = crate::web_viewer::new_sink(open_browser, bind_ip, web_port, ws_port)
.map_err(RecordingStreamError::WebSink)?;
RecordingStream::new(store_info, batcher_config, sink)
} else {
re_log::debug!("Rerun disabled - call to serve() ignored");
Ok(RecordingStream::disabled())
}
}

/// Returns whether or not logging is enabled, a [`StoreInfo`] and the associated batcher
/// configuration.
///
Expand Down
File renamed without changes.
21 changes: 9 additions & 12 deletions crates/rerun/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,15 @@ sdk = ["dep:re_sdk"]
## Support serving a web viewer over HTTP.
##
## Enabling this inflates the binary size quite a bit, since it embeds the viewer wasm.
# When building from source (in the repository), this feature adds quite a bit
# to the compile time since it requires compiling and bundling the viewer as wasm.
#
# You also need to install some additional tools, which you can do by running
# [`scripts/setup_web.sh`](https://github.com/rerun-io/rerun/blob/main/scripts/setup_web.sh).
web_viewer = [
"dep:re_web_viewer_server",
"dep:webbrowser",
"re_ws_comms/server",
]
##
## For faster & easier builds, the web-player build comes bundled with the crate.
## Enabling this feature will embed this pre-built web-player.
##
## However, when building from source in the repository, this feature adds quite a bit
## to the compile time since it requires compiling and bundling the viewer as wasm.
## You also need to install some additional tools, which you can do by running
## [`scripts/setup_web.sh`](https://github.com/rerun-io/rerun/blob/main/scripts/setup_web.sh).
web_viewer = ["dep:re_web_viewer_server", "re_sdk?/web_viewer"]

[dependencies]
re_build_info.workspace = true
Expand All @@ -88,8 +87,6 @@ re_sdk_comms = { workspace = true, optional = true }
re_viewer = { workspace = true, optional = true }
re_web_viewer_server = { workspace = true, optional = true }

webbrowser = { version = "0.8", optional = true }

# Native dependencies:
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
clap = { workspace = true, features = ["derive"] }
Expand Down
10 changes: 3 additions & 7 deletions crates/rerun/src/clap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
use std::{net::SocketAddr, path::PathBuf};

use re_sdk::RecordingStream;
#[cfg(feature = "web_viewer")]
use re_web_viewer_server::WebViewerServerPort;
#[cfg(feature = "web_viewer")]
use re_ws_comms::RerunServerPort;

// ---

Expand Down Expand Up @@ -113,11 +109,11 @@ impl RerunArgs {
#[cfg(feature = "web_viewer")]
RerunBehavior::Serve => {
let open_browser = true;
crate::web_viewer::new_sink(
re_sdk::web_viewer::new_sink(
open_browser,
&self.bind,
WebViewerServerPort::default(),
RerunServerPort::default(),
Default::default(),
Default::default(),
)?
}

Expand Down
4 changes: 0 additions & 4 deletions crates/rerun/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,6 @@ pub mod clap;
#[cfg(all(feature = "sdk", feature = "native_viewer"))]
pub mod native_viewer;

/// Methods for spawning the web viewer and streaming the SDK log stream to it.
#[cfg(all(feature = "sdk", feature = "web_viewer"))]
pub mod web_viewer;

pub use run::{run, CallSource};

// NOTE: Have a look at `re_sdk/src/lib.rs` for an accurate listing of all these symbols.
Expand Down
6 changes: 3 additions & 3 deletions crates/rerun/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ use re_smart_channel::{Receiver, SmartMessagePayload};

use anyhow::Context as _;
use clap::Subcommand;

#[cfg(feature = "web_viewer")]
use re_sdk::web_viewer::host_web_viewer;
#[cfg(feature = "web_viewer")]
use re_web_viewer_server::WebViewerServerPort;
#[cfg(feature = "web_viewer")]
use re_ws_comms::RerunServerPort;

#[cfg(feature = "web_viewer")]
use crate::web_viewer::host_web_viewer;

// Note the extra blank lines between the point-lists below: it is required by `clap`.

/// The Rerun Viewer and Server
Expand Down
2 changes: 1 addition & 1 deletion docs/content/reference/sdk-operating-modes.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Use [`rr.serve`](https://ref.rerun.io/docs/python/latest/package/rerun/__init__/

#### `Rust`

[TODO(#2232)](https://github.com/rerun-io/rerun/issues/2232): This is not available for the time being.
[`RecordingStream::serve`](https://docs.rs/rerun/latest/rerun/struct.RecordingStream.html#method.serve)

## Save

Expand Down
11 changes: 11 additions & 0 deletions examples/rust/minimal_serve/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "minimal_serve"
version = "0.8.0-alpha.7"
edition = "2021"
rust-version = "1.69"
license = "MIT OR Apache-2.0"
publish = false

[dependencies]
rerun = { path = "../../../crates/rerun", features = ["web_viewer"] }
tokio = "1.0"
19 changes: 19 additions & 0 deletions examples/rust/minimal_serve/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
Wumpf marked this conversation as resolved.
Show resolved Hide resolved
title: Minimal `serve` example
rust: https://github.com/rerun-io/rerun/tree/latest/examples/rust/minimal_serve/src/main.rs
thumbnail: https://static.rerun.io/92a1f80b5cf2cd2c04a10d8ced35849da8f1c0ed_minimal_480w.png
---

<picture>
<source media="(max-width: 480px)" srcset="https://static.rerun.io/92a1f80b5cf2cd2c04a10d8ced35849da8f1c0ed_minimal_480w.png">
<source media="(max-width: 768px)" srcset="https://static.rerun.io/d78037f2306ed02505859adbae9f72d4ab2945d1_minimal_768w.png">
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/cf926c580c8ca8b39fd844f6adf4b19972b5111e_minimal_1024w.png">
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/8f03efd9e918f43b5e6d9257d0f1a3cb962b3889_minimal_1200w.png">
<img src="https://static.rerun.io/0e47ac513ab25d56cf2b493128097d499a07e5e8_minimal_full.png" alt="Minimal example screenshot">
</picture>

The simplest example of how to use Rerun with its Web-based UI, showing how to log a point cloud.

```bash
cargo run --release
```
39 changes: 39 additions & 0 deletions examples/rust/minimal_serve/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! Demonstrates the most barebone usage of the Rerun SDK.

use rerun::{
components::{ColorRGBA, Point3D, Radius},
demo_util::grid,
external::glam,
MsgSender, RecordingStreamBuilder,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
// `serve()` requires to have a running Tokio runtime in the current context.
let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime");
let _guard = rt.enter();

let rec_stream = RecordingStreamBuilder::new("minimal_serve_rs").serve(
"0.0.0.0",
Default::default(),
Default::default(),
true,
)?;

let points = grid(glam::Vec3::splat(-10.0), glam::Vec3::splat(10.0), 10)
.map(Point3D::from)
.collect::<Vec<_>>();
let colors = grid(glam::Vec3::ZERO, glam::Vec3::splat(255.0), 10)
.map(|v| ColorRGBA::from_rgb(v.x as u8, v.y as u8, v.z as u8))
.collect::<Vec<_>>();

MsgSender::new("my_points")
.with_component(&points)?
.with_component(&colors)?
.with_splat(Radius(0.5))?
.send(&rec_stream)?;

eprintln!("Check your browser!");
std::thread::sleep(std::time::Duration::from_secs(100000));

Ok(())
}