Process an RRD session file by extracting its contents. Extracts poses, LiDAR, camera, and GPS data from the .rrd file and writes them to an extracted/ directory alongside it.
(
state: SharedState,
rrd_path: PathBuf,
)
| 340 | /// Extracts poses, LiDAR, camera, and GPS data from the .rrd file |
| 341 | /// and writes them to an extracted/ directory alongside it. |
| 342 | async fn process_rrd_session( |
| 343 | state: SharedState, |
| 344 | rrd_path: PathBuf, |
| 345 | ) -> Result<(), MapperError> { |
| 346 | // Check if already skipped (in-memory state, persisted to maps volume) |
| 347 | { |
| 348 | let s = state.read().await; |
| 349 | if s.skipped_sessions.contains(&rrd_path) { |
| 350 | debug!(path = %rrd_path.display(), "Previously skipped, not reprocessing"); |
| 351 | return Ok(()); |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | info!(path = %rrd_path.display(), "Processing RRD session"); |
| 356 | |
| 357 | // Determine output directory |
| 358 | let extract_dir = if rrd_path.file_name().map(|n| n == "session.rrd").unwrap_or(false) { |
| 359 | rrd_path.parent().unwrap().join("extracted") |
| 360 | } else { |
| 361 | rrd_path.with_extension("extracted") |
| 362 | }; |
| 363 | |
| 364 | // Check if already extracted on disk |
| 365 | if extract_dir.exists() { |
| 366 | debug!(path = %rrd_path.display(), "Already extracted, skipping"); |
| 367 | return Ok(()); |
| 368 | } |
| 369 | |
| 370 | // Check if file is still being written (wait for stable mtime) |
| 371 | let metadata = tokio::fs::metadata(&rrd_path).await?; |
| 372 | let mtime = metadata.modified()?; |
| 373 | tokio::time::sleep(Duration::from_secs(2)).await; |
| 374 | let new_metadata = tokio::fs::metadata(&rrd_path).await?; |
| 375 | if new_metadata.modified()? != mtime { |
| 376 | debug!(path = %rrd_path.display(), "File still being written, skipping"); |
| 377 | return Ok(()); |
| 378 | } |
| 379 | |
| 380 | // Extract data from RRD file |
| 381 | let rrd_path_clone = rrd_path.clone(); |
| 382 | let extract_dir_clone = extract_dir.clone(); |
| 383 | let extraction_result = tokio::task::spawn_blocking(move || { |
| 384 | let result = rrd_extractor::extract_from_rrd(&rrd_path_clone)?; |
| 385 | |
| 386 | // If we have LiDAR data, write extracted data |
| 387 | if !result.lidar_frames.is_empty() { |
| 388 | rrd_extractor::write_extracted_data(&result, &extract_dir_clone) |
| 389 | .map_err(|e| MapperError::ProcessingFailed(e.to_string()))?; |
| 390 | } |
| 391 | |
| 392 | Ok::<_, MapperError>(result) |
| 393 | }) |
| 394 | .await |
| 395 | .map_err(|e| MapperError::ProcessingFailed(format!("Task join error: {}", e)))??; |
| 396 | |
| 397 | // No LiDAR data — record skip in state (persisted to writable maps volume) |
| 398 | if extraction_result.lidar_frames.is_empty() { |
| 399 | warn!(path = %rrd_path.display(), "No LiDAR data in RRD, marking as skipped"); |
no test coverage detected