Skip to content

Add data stream progress events and file rendering#30

Open
1egoman wants to merge 1 commit into
mainfrom
add-data-stream-progress
Open

Add data stream progress events and file rendering#30
1egoman wants to merge 1 commit into
mainfrom
add-data-stream-progress

Conversation

@1egoman

@1egoman 1egoman commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Warning

This change relies on the rust data streams v2 implementation. This cannot be merged until that is merged first. This is also why CI is failing.

Add logic to handle rendering data streams with names and/or mime types associated as a special "file" state. I am assuming that these will be relatively large so files are buffered in tempfiles rather than in memory. And then also, add a "save" button which can be used to save files to arbitrary locations for inspection.

Untitled.mov

I will say, design wise, I think this side panel is starting to break down a little bit now that there is a card rendered within a card. I can try some more stuff here but also I'm not an egui expert so I would be interested in some ideas before investigating anything.

Add logic to handle rendering data streams with names and/or mime types
associated as a special "file" state. I am assuming that these will be
relatively large so files are buffered in tempfiles rather than in
memory. And then also, add a "save" button which can be used to save
files to arbitrary locations for inspection.
@1egoman
1egoman marked this pull request as ready for review July 16, 2026 20:58
@1egoman
1egoman requested a review from ladvoc as a code owner July 16, 2026 20:58
Comment thread src/room/data_streams.rs
Comment on lines +639 to +661
/// Streams every chunk of a byte reader into an anonymous temp file, returning the open
/// handle. The file is unlinked at creation (`tempfile`), so the OS reclaims it when the
/// handle is dropped or the process exits — including on a panic/abort, where `Drop` would
/// not run (the release profile sets `panic = "abort"`).
async fn stream_to_temp_file(
reader: &mut ByteStreamReader,
entry: &Arc<Mutex<TopicEntry>>,
n: u64,
total: Option<u64>,
) -> Result<std::fs::File, String> {
use tokio::io::AsyncWriteExt;
let std_file = tempfile::tempfile_in(std::env::temp_dir()).map_err(|e| e.to_string())?;
let mut file = tokio::fs::File::from_std(std_file);
let mut processed = 0u64;
while let Some(chunk) = reader.next().await {
let chunk = chunk.map_err(|e| e.to_string())?;
file.write_all(&chunk).await.map_err(|e| e.to_string())?;
processed += chunk.len() as u64;
update_progress(entry, n, processed, total);
}
file.flush().await.map_err(|e| e.to_string())?;
Ok(file.into_std().await)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to any reviewers - this maybe could make sense as an extension to ByteStreamReader?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, sounds generally useful! Also note in the Swift implementation, I had the equivalent method use the temporary directory by default and return the path to the written file.

@1egoman
1egoman requested review from MaxHeimbrock and xianshijing-lk and removed request for xianshijing-lk July 16, 2026 21:00
@1egoman
1egoman marked this pull request as draft July 16, 2026 21:01
@MaxHeimbrock

Copy link
Copy Markdown
Contributor

Logs flood the console for me.

Screenshot 2026-07-17 at 09 21 55

@MaxHeimbrock

MaxHeimbrock commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Logs flood the console for me.

Screenshot 2026-07-17 at 09 21 55

I see it comes from here: https://github.com/livekit/rust-sdks/pull/1192/changes#diff-b27b5fab061a986aea2fd0654f77f4640c712b4eec98f54b14c84fe61a1aced0R2366

The event is marked as deprecated, is this still there on purpose?

@MaxHeimbrock

Copy link
Copy Markdown
Contributor

Otherwise it looks good to me, works as expected.

@1egoman
1egoman marked this pull request as ready for review July 17, 2026 13:10
Comment thread Cargo.toml
image = "0.25"
log = "0.4"
parking_lot = { version = "0.12", features = ["deadlock_detection"] }
rfd = "0.15"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Nice, didn't know about this crate!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Is there a reason you didn't use the latest version (0.17.x)?

Comment thread src/room/data_streams.rs
Some(p) => format!("{} ({}%)", format_size(r.size), (p * 100.0).round() as i64),
None => format_size(r.size),
};
let meta = format!(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue(non-blocking): This is a relatively expensive operation in the render path (format is allocating).

Comment thread src/room/data_streams.rs
if r.is_file {
show_file_box(ui, service, entry, r);
} else if let Some(StreamContent::Preview(preview)) = &r.content {
ui.add(egui::Label::new(RichText::new(preview).monospace()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(non-blocking): Consider how this will render for a long string and possibly use Label::wrap().

@ladvoc

ladvoc commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

One other issue I noticed, but it was pre-existing so this might not be the right place to fix it. In DataStreamsUiState::subscription_cards, the guard on the entry is held across widget closures; ideally, the lock should be held for the shorted time possible.

@1egoman

1egoman commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

@MaxHeimbrock

The event is marked as deprecated, is this still there on purpose?

Yes, it exists in the implementation on main today, so I didn't want to remove it and break downstream consumers as part of data streams v2. I'm not exactly sure the history of why it was deprecated though and I'm opening to removing it if there's a good reason and the breaking change is acceptable.

Comment thread src/room/data_streams.rs

/// A single received stream, rendered as a row (metadata line + preview/file box).
/// A row is created as soon as the stream opens and updated live from the read task.
struct ReceivedStream {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curiously, do you think some customers might want to implement a "cancel" feature for the large file since they will show a progress bar now ?

and do we support such "cancel" feature ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Today, no, this is not supported. However, we've got a ticket to implement "cancellation tokens" (the rust idiomatic way to handle cancellation, very similar to like an AbortController in the web) sdk-wide as part of the rust sdk project(s) this quarter, and as part of this it will definitely be added to this api (alongside send_text and send_bytes too most likely).

cc @ladvoc

Comment thread src/room/data_streams.rs
struct ReceivedStream {
n: u64,
sender: String,
received_at: SystemTime,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this received_at ? is it the first chunk of data received timestamp ? or last chunk of data?

should we be able to store both values ?

Comment thread src/room/data_streams.rs
enum StreamStatus {
InProgress,
Complete,
Error(String),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curiously , I wonder if we will have cancelled, paused, for the long term ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep probably, but IMO out of scope for now. More info here: #30 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants