use std::path::PathBuf;
use re_sdk::{RecordingStream, RecordingStreamBuilder};
#[derive(Debug, Clone, PartialEq, Eq)]
enum RerunBehavior {
Connect(String),
Save(PathBuf),
Stdout,
#[cfg(feature = "web_viewer")]
Serve,
Spawn,
}
#[derive(Clone, Debug, clap::Args)]
#[clap(author, version, about)]
pub struct RerunArgs {
#[clap(long, default_value = "true")]
spawn: bool,
#[clap(long)]
save: Option<PathBuf>,
#[clap(long, short = 'o')]
stdout: bool,
#[clap(long)]
#[expect(clippy::option_option)]
connect: Option<Option<String>>,
#[cfg(feature = "web_viewer")]
#[clap(long)]
serve: bool,
#[clap(long, default_value = "25%")]
server_memory_limit: String,
#[clap(long)]
newest_first: bool,
#[clap(long, default_value = "0.0.0.0")]
bind: String,
}
#[doc(hidden)]
#[derive(Default)]
pub struct ServeGuard {
block_on_drop: bool,
}
impl Drop for ServeGuard {
fn drop(&mut self) {
if self.block_on_drop {
eprintln!("Sleeping indefinitely while serving web viewer… Press ^C when done.");
std::thread::sleep(std::time::Duration::from_secs(u64::MAX));
}
}
}
impl RerunArgs {
#[track_caller] pub fn init(&self, application_id: &str) -> anyhow::Result<(RecordingStream, ServeGuard)> {
match self.to_behavior()? {
RerunBehavior::Stdout => Ok((
RecordingStreamBuilder::new(application_id).stdout()?,
Default::default(),
)),
RerunBehavior::Connect(url) => Ok((
RecordingStreamBuilder::new(application_id).connect_grpc_opts(url)?,
Default::default(),
)),
RerunBehavior::Save(path) => Ok((
RecordingStreamBuilder::new(application_id).save(path)?,
Default::default(),
)),
RerunBehavior::Spawn => Ok((
RecordingStreamBuilder::new(application_id).spawn()?,
Default::default(),
)),
#[cfg(feature = "web_viewer")]
RerunBehavior::Serve => {
let server_options = re_sdk::ServerOptions {
playback_behavior: re_sdk::PlaybackBehavior::from_newest_first(
self.newest_first,
),
memory_limit: re_sdk::MemoryLimit::parse(&self.server_memory_limit)
.map_err(|err| anyhow::format_err!("Bad --server-memory-limit: {err}"))?,
};
let rec = RecordingStreamBuilder::new("rerun_example_minimal_serve")
.serve_grpc_opts(&self.bind, crate::DEFAULT_SERVER_PORT, server_options)?;
crate::serve_web_viewer(crate::web_viewer::WebViewerConfig {
open_browser: true,
connect_to: vec!["rerun+http://localhost:9876/proxy".to_owned()],
..Default::default()
})?
.detach();
let sleep_guard = ServeGuard {
block_on_drop: true,
};
Ok((rec, sleep_guard))
}
}
}
#[expect(clippy::unnecessary_wraps)] fn to_behavior(&self) -> anyhow::Result<RerunBehavior> {
if self.stdout {
return Ok(RerunBehavior::Stdout);
}
if let Some(path) = self.save.as_ref() {
return Ok(RerunBehavior::Save(path.clone()));
}
#[cfg(feature = "web_viewer")]
if self.serve {
return Ok(RerunBehavior::Serve);
}
match &self.connect {
Some(Some(url)) => return Ok(RerunBehavior::Connect(url.clone())),
Some(None) => {
return Ok(RerunBehavior::Connect(
re_sdk::DEFAULT_CONNECT_URL.to_owned(),
));
}
None => {}
}
Ok(RerunBehavior::Spawn)
}
}