Skip to content

Commit 38503a8

Browse files
committed
feat(data-stream): abort_all_streams / abort_streams_from on incoming FFI
Add an AbortAllStreams input event to the incoming data-stream backend and expose abort_all_streams() / abort_streams_from(identity) on the UniFFI IncomingDataStreamManager, so the host can fail open readers on disconnect or participant-leave instead of letting them hang (which would also stall an ordered topic's queue). Also fix the constructor to take Option<u64> (UniFFI can't lift usize) and drop the stale reserved_topics argument to Manager::new.
1 parent 76f1e16 commit 38503a8

3 files changed

Lines changed: 33 additions & 3 deletions

File tree

livekit-data-stream/src/incoming/events.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ pub enum InputEvent {
3939
PacketReceived(PacketReceived),
4040
/// Abort every open stream sent by this participant (they disconnected mid-send).
4141
AbortStreamsFrom(ParticipantIdentity),
42+
/// Abort every open stream (e.g. the local connection is going away). Unlike
43+
/// [`InputEvent::Shutdown`], the run loop keeps going so streams opened later are still handled.
44+
AbortAllStreams,
4245
/// Stop the run loop.
4346
Shutdown,
4447
}

livekit-data-stream/src/incoming/manager.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ impl Manager {
234234
}
235235
}
236236
InputEvent::AbortStreamsFrom(identity) => self.handle_abort(identity),
237+
InputEvent::AbortAllStreams => self.handle_abort_all(),
237238
InputEvent::Shutdown => break,
238239
}
239240
}
@@ -518,6 +519,16 @@ impl Manager {
518519
}
519520
});
520521
}
522+
523+
/// Aborts every open stream, erroring each reader with [`StreamError::AbnormalEnd`]. Unlike
524+
/// [`Self::handle_abort`] this isn't scoped to one participant; the host calls it when the
525+
/// connection is torn down so no reader hangs waiting for chunks that will never arrive.
526+
/// The run loop keeps going, so streams opened after (e.g. a reconnect) are still handled.
527+
fn handle_abort_all(&mut self) {
528+
self.inner.close_matching_streams_with_error(|_id, _descriptor| {
529+
Err(StreamError::AbnormalEnd("Data stream connection closed".to_string()))
530+
});
531+
}
521532
}
522533

523534
impl ManagerInner {

livekit-uniffi/src/data_stream/incoming.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,13 @@ pub trait IncomingDataStreamManagerDelegate: Send + Sync {
5252
#[uniffi::export]
5353
impl IncomingDataStreamManager {
5454
#[uniffi::constructor]
55-
pub fn new(delegate: Arc<dyn IncomingDataStreamManagerDelegate>, max_payload_byte_length: Option<usize>) -> Arc<Self> {
55+
pub fn new(
56+
delegate: Arc<dyn IncomingDataStreamManagerDelegate>,
57+
max_payload_byte_length: Option<u64>,
58+
) -> Arc<Self> {
5659
let token = CancellationToken::new();
57-
// No reserved topics: RPC routing is a concern of the `livekit` crate, not this FFI layer.
58-
let (manager, input, output) = ds::incoming::Manager::new(vec![], max_payload_byte_length);
60+
let (manager, input, output) =
61+
ds::incoming::Manager::new(max_payload_byte_length.map(|n| n as usize));
5962

6063
let rt = crate::runtime::runtime();
6164
rt.spawn(shutdown_forward_task(input.clone(), token.clone()));
@@ -75,6 +78,19 @@ impl IncomingDataStreamManager {
7578
let _ = self.input.send(event.into());
7679
}
7780
}
81+
82+
/// Aborts all open incoming streams so their readers error instead of hanging (e.g. on
83+
/// disconnect). Handler wiring on the foreign side survives, so streams that arrive later
84+
/// (e.g. after a reconnect) are still processed.
85+
pub fn abort_all_streams(&self) {
86+
let _ = self.input.send(ds::incoming::InputEvent::AbortAllStreams);
87+
}
88+
89+
/// Aborts open incoming streams sent by `identity` (e.g. when that participant disconnects
90+
/// mid-send), so their readers error instead of hanging.
91+
pub fn abort_streams_from(&self, identity: String) {
92+
let _ = self.input.send(ds::incoming::InputEvent::AbortStreamsFrom(identity.into()));
93+
}
7894
}
7995

8096
/// Reader for an incoming byte data stream.

0 commit comments

Comments
 (0)