Skip to content

Commit

Permalink
SDK DataLoaders 9: polish, docs, etc (#5388)
Browse files Browse the repository at this point in the history
I guess that's good enough 🤷. I don't know, my brain has been
completely friend by C++ non-sense all day.

This includes a fix to make sure that a viewer that was spawned from the
python SDK is still allowed to spawn dataloaders implemented in python
(`RERUN_APP_ONLY` shenaniganeries).

- Fixes #4526 

---

Part of series of PR to expose configurable `DataLoader`s to our SDKs:
- #5327 
- #5328 
- #5330
- #5337
- #5351
- #5355
- #5379
- #5361
- #5388
  • Loading branch information
teh-cmc authored Mar 6, 2024
1 parent 203730d commit 8ebb5df
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 15 deletions.
3 changes: 3 additions & 0 deletions crates/re_data_source/src/data_loader/loader_external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ impl crate::DataLoader for ExternalLoader {
re_tracing::profile_function!(exe.to_string_lossy());

let child = Command::new(exe)
// Make sure the child dataloader doesn't think it's a Rerun Viewer, otherwise
// it's never gonna be able to log anything.
.env_remove("RERUN_APP_ONLY")
.arg(filepath.clone())
.args(args)
.stdout(Stdio::piped())
Expand Down
4 changes: 4 additions & 0 deletions docs/code-examples/all/log-file/example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const auto rec = rerun::RecordingStream("rerun_example_log_file");
rec.spawn().exit_on_failure();

rec.log_file_from_path(argv[1]);
7 changes: 7 additions & 0 deletions docs/code-examples/all/log-file/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import sys

import rerun as rr

rr.init("rerun_example_log_file", spawn=True)

rr.log_file_from_path(sys.argv[1])
5 changes: 5 additions & 0 deletions docs/code-examples/all/log-file/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let args = std::env::args().collect::<Vec<_>>();

let rec = rerun::RecordingStreamBuilder::new("rerun_example_log_file").spawn()?;

rec.log_file_from_path(&args[1], None /* prefix */, true /* timeless */)?;
32 changes: 20 additions & 12 deletions docs/content/howto/open-any-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ title: Open any file
order: -10
---

The Rerun Viewer has built-in support for opening many kinds of files, and can be extended to open any other file type without needing to modify the Rerun codebase itself.
The Rerun Viewer and SDK have built-in support for opening many kinds of files, and can be extended to support any other file type without needing to modify the Rerun codebase itself.

The viewer can load files in 3 different ways:
The Viewer can load files in 3 different ways:
- via CLI arguments (e.g. `rerun myfile.jpeg`),
- using drag-and-drop,
- using the open dialog in the Rerun Viewer.
Expand All @@ -14,27 +14,35 @@ All these file loading methods support loading a single file, many files at once

⚠ Drag-and-drop of folders does [not yet work](https://github.com/rerun-io/rerun/issues/4528) on the web version of the Rerun Viewer ⚠

The following file types have built-in support in the Rerun Viewer:
The following file types have built-in support in the Rerun Viewer and SDK:
- Native Rerun files: `rrd`
- 3D models: `gltf`, `glb`, `obj`
- 3D models: `gltf`, `glb`, `obj`, `stl`
- Images: `avif`, `bmp`, `dds`, `exr`, `farbfeld`, `ff`, `gif`, `hdr`, `ico`, `jpeg`, `jpg`, `pam`, `pbm`, `pgm`, `png`, `ppm`, `tga`, `tif`, `tiff`, `webp`.
- Point clouds: `ply`.
- Text files: `md`, `txt`.

With the exception of `rrd` files that can be streamed from an HTTP URL (e.g. `rerun https://demo.rerun.io/version/latest/examples/dna/data.rrd`), we only support loading files from the local filesystem for now, with [plans to make this generic over any URI and protocol in the future](https://github.com/rerun-io/rerun/issues/4525).

## Logging file contents from the SDK

To log the contents of a file from the SDK you can use the `log_file_from_path` and `log_file_from_contents` methods ([C++](https://ref.rerun.io/docs/cpp/stable/classrerun_1_1RecordingStream.html#SOME_HASH_TBD?speculative-link), [Python](https://ref.rerun.io/docs/python/stable/common/other_classes_and_functions/#rerun.log_file_from_path?speculative-link), [Rust](https://docs.rs/rerun/latest/rerun/struct.RecordingStream.html#method.log_file_from_path)) and the associated examples ([C++](https://github.com/rerun-io/rerun/blob/main/examples/cpp/log_file/main.cpp), [Python](https://github.com/rerun-io/rerun/blob/main/examples/python/log_file/main.py), [Rust](https://github.com/rerun-io/rerun/blob/main/examples/rust/log_file/src/main.rs)).

Note: when calling these APIs from the SDK, the data will be loaded by the process running the SDK, not the Viewer!

code-example: log-file

## Adding support for arbitrary filetypes

Internally, the [`DataLoader`](https://docs.rs/re_data_source/latest/re_data_source/trait.DataLoader.html) trait takes care of loading files into the Viewer.
Internally, the [`DataLoader`](https://docs.rs/re_data_source/latest/re_data_source/trait.DataLoader.html) trait takes care of loading files into the Viewer and/or SDK.

There are 3 broad kinds of `DataLoader`s: _builtin_, _external_ and _custom_.
_External_ and _custom_ are the two ways of extending the file loading system that we'll describe below.

When a user attempts to open a file in the Viewer, **all** known `DataLoader`s are notified of the path to be opened, unconditionally.
When a user attempts to open a file in the Viewer/SDK, **all** known `DataLoader`s are notified of the path to be opened, unconditionally.
This gives `DataLoader`s maximum flexibility to decide what files they are interested in, as opposed to e.g. only being able to look at a file's extension.

Once notified, a `DataLoader` can return a [`DataLoaderError::Incompatible`](https://docs.rs/re_data_source/latest/re_data_source/enum.DataLoaderError.html#variant.Incompatible) error to indicate that it doesn't support a given file type.
If, and only if, all loaders known to the Viewer return an `Incompatible` error code, then an error message is shown to the user indicating that this file type is not (_yet_) supported.
If, and only if, all loaders known to the Viewer/SDK return an `Incompatible` error code, then an error message is shown to the user indicating that this file type is not (_yet_) supported.

In these instances of unsupported files, we expose two ways of implementing and registering your `DataLoader`s, explained below.

Expand All @@ -43,10 +51,10 @@ In these instances of unsupported files, we expose two ways of implementing and
The easiest way to create your own `DataLoader` is by implementing what we call an "external loader": a stand alone executable written in any language that the Rerun SDK ships for. Any executable on your `$PATH` with a name that starts with `rerun-loader-` will be treated as a `DataLoader`.

This executable takes a file path as a command line argument and outputs Rerun logs on `stdout`.
It will be called by the Rerun Viewer when the user opens a file, and be passed the path to that file.
It will be called by the Rerun Viewer/SDK when the user opens a file, and be passed the path to that file.
From there, it can log data as usual, using the [`stdout` logging sink](../reference/sdk-operating-modes.md#standard-inputoutput).

The Rerun Viewer will then automatically load the data streamed to the external loader's standard output.
The Rerun Viewer/SDK will then automatically load the data streamed to the external loader's standard output.

<picture>
<img src="https://static.rerun.io/data-loader-external-overview/97e978000c709b78290f50d52c229a91f7543648/full.png" alt="">
Expand All @@ -61,10 +69,10 @@ To indicate that it does not support a given file, the loader has to exit with a

Check out our examples for [C++](https://github.com/rerun-io/rerun/tree/main/examples/cpp/external_data_loader), [Python](https://github.com/rerun-io/rerun/tree/main/examples/python/external_data_loader) and [Rust](https://github.com/rerun-io/rerun/tree/main/examples/rust/external_data_loader) that cover every steps in details.

### Custom data-loaders
### Custom Rust data-loaders

Another Rust-specific approach is to implement the `DataLoader` trait yourself and register it in the Rerun Viewer.
Another Rust-specific approach is to implement the `DataLoader` trait yourself and register it in the Rerun Viewer/SDK.

To do so, you'll need to import `rerun` as a library, register your `DataLoader` and then start the viewer from code.
To do so, you'll need to import `rerun` as a library, register your `DataLoader` and then start the Viewer/SDK from code.

Check out our [example](https://github.com/rerun-io/rerun/tree/main/examples/rust/custom_data_loader) that cover all these steps in details.
3 changes: 0 additions & 3 deletions examples/rust/log_file/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ fn main() -> anyhow::Result<()> {
}

fn run(rec: &rerun::RecordingStream, args: &Args) -> anyhow::Result<()> {
let mut settings = rerun::DataLoaderSettings::recommended(rec.store_info().unwrap().store_id);
settings.entity_path_prefix = Some("log_file_example".into());

let prefix = Some("log_file_example".into());

for filepath in &args.filepaths {
Expand Down

0 comments on commit 8ebb5df

Please sign in to comment.