@@ -2,6 +2,7 @@ use std::cell::RefCell;
22use std:: rc:: Rc ;
33use std:: time:: { Duration , Instant , SystemTime , UNIX_EPOCH } ;
44
5+ use clap:: Parser ;
56use custom_callback:: interaction:: { LcmPublisher , click_event_from_ms} ;
67use rerun:: external:: { eframe, re_crash_handler, re_grpc_server, re_log, re_memory, re_viewer} ;
78
@@ -15,24 +16,61 @@ const LCM_CHANNEL: &str = "/clicked_point#geometry_msgs.PointStamped";
1516const CLICK_DEBOUNCE_MS : u64 = 100 ;
1617/// Maximum rapid clicks to log as warning
1718const RAPID_CLICK_THRESHOLD : usize = 5 ;
19+ /// Default gRPC listen port (9877 to avoid conflict with stock Rerun on 9876)
20+ const DEFAULT_PORT : u16 = 9877 ;
21+
22+ /// DimOS Interactive Viewer — a custom Rerun viewer with LCM click-to-navigate.
23+ ///
24+ /// Accepts the same CLI flags as the stock `rerun` binary so it can be spawned
25+ /// seamlessly via `rerun_bindings.spawn(executable_name="dimos-viewer")`.
26+ #[ derive( Parser , Debug ) ]
27+ #[ command( name = "dimos-viewer" , version, about) ]
28+ struct Args {
29+ /// The gRPC port to listen on for incoming SDK connections.
30+ #[ arg( long, default_value_t = DEFAULT_PORT ) ]
31+ port : u16 ,
32+
33+ /// An upper limit on how much memory the viewer should use.
34+ /// When this limit is reached, the oldest data will be dropped.
35+ /// Examples: "75%", "16GB".
36+ #[ arg( long, default_value = "75%" ) ]
37+ memory_limit : String ,
38+
39+ /// An upper limit on how much memory the gRPC server should use.
40+ /// Examples: "1GiB", "50%".
41+ #[ arg( long, default_value = "1GiB" ) ]
42+ server_memory_limit : String ,
43+
44+ /// Hide the Rerun welcome screen.
45+ #[ arg( long) ]
46+ hide_welcome_screen : bool ,
47+
48+ /// Hint that data will arrive shortly (suppresses "waiting for data" message).
49+ #[ arg( long) ]
50+ expect_data_soon : bool ,
51+ }
1852
1953#[ tokio:: main]
2054async fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
55+ let args = Args :: parse ( ) ;
56+
2157 let main_thread_token = re_viewer:: MainThreadToken :: i_promise_i_am_on_the_main_thread ( ) ;
2258 re_log:: setup_logging ( ) ;
2359 re_crash_handler:: install_crash_handlers ( re_viewer:: build_info ( ) ) ;
2460
2561 // Listen for gRPC connections from Rerun's logging SDKs.
62+ let listen_addr = format ! ( "0.0.0.0:{}" , args. port) ;
63+ re_log:: info!( "Listening for SDK connections on {listen_addr}" ) ;
2664 let rx_log = re_grpc_server:: spawn_with_recv (
27- "0.0.0.0:9877" . parse ( ) ?,
65+ listen_addr . parse ( ) ?,
2866 Default :: default ( ) ,
2967 re_grpc_server:: shutdown:: never ( ) ,
3068 ) ;
3169
3270 // Create LCM publisher for click events
3371 let lcm_publisher = LcmPublisher :: new ( LCM_CHANNEL . to_string ( ) )
3472 . expect ( "Failed to create LCM publisher" ) ;
35- re_log:: info!( "LCM publisher created for channel: {}" , LCM_CHANNEL ) ;
73+ re_log:: info!( "LCM publisher created for channel: {LCM_CHANNEL}" ) ;
3674
3775 // State for debouncing and rapid click detection
3876 let last_click_time = Rc :: new ( RefCell :: new ( Instant :: now ( ) ) ) ;
@@ -108,7 +146,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
108146 ) ;
109147 }
110148 Err ( err) => {
111- re_log:: error!( "Failed to publish LCM click event: {:?}" , err ) ;
149+ re_log:: error!( "Failed to publish LCM click event: {err :?}" ) ;
112150 }
113151 }
114152 }
@@ -121,8 +159,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
121159
122160 if !has_position && no_position_count > 0 {
123161 re_log:: trace!(
124- "Selection change without position data ({} items). This is normal for hover/keyboard navigation." ,
125- no_position_count
162+ "Selection change without position data ({no_position_count } items). \
163+ This is normal for hover/keyboard navigation."
126164 ) ;
127165 }
128166 }
0 commit comments