fix: centralize SESSION_REVOKED sentinel and add retry delay

Signed-off-by: Steve3184 <77789906+Steve3184@users.noreply.github.com>
This commit is contained in:
Steve3184 2026-02-28 15:44:06 +08:00
parent 6796c5d023
commit cac4961595
2 changed files with 20 additions and 5 deletions

View file

@ -163,6 +163,17 @@ impl std::fmt::Display for GStreamerError {
impl Error for GStreamerError {}
#[derive(Debug)]
pub struct SessionRevokedError;
impl std::fmt::Display for SessionRevokedError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SESSION_REVOKED")
}
}
impl Error for SessionRevokedError {}
#[derive(Clone)]
pub struct PipeWireCapturable {
// connection needs to be kept alive for recording
@ -328,17 +339,19 @@ impl PipeWireRecorder {
let _ = pipeline.set_state(gst::State::Null);
let is_revoked = if !is_server_running() {
// remote_desktop_portal: always treat sync failure as revocation.
// remote_desktop_portal: the portal opened the fd, so a PLAYING failure
// means the underlying PipeWire node is gone -> session revoked.
true
} else {
// screencast_portal: only treat as revocation when a stale token exists.
// screencast_portal: only treat as revoked when a persisted restore token
// exists, meaning we were trying to resume a prior session.
!config::LocalConfig::get_option(RESTORE_TOKEN_CONF_KEY).is_empty()
};
if is_revoked {
warn!("[gstreamer] Failed to set PLAYING state, session was likely revoked: {:?}", e);
config::LocalConfig::set_option(RESTORE_TOKEN_CONF_KEY.to_owned(), "".to_owned());
return Err(hbb_common::anyhow::Error::msg(format!("SESSION_REVOKED: GStreamer failed: {:?}", e)));
return Err(hbb_common::anyhow::Error::new(SessionRevokedError));
} else {
warn!(
"[gstreamer] Failed to set PLAYING state on a fresh screencast session \
@ -368,11 +381,11 @@ impl PipeWireRecorder {
capturable.fd.as_raw_fd(), result, state, pending
);
if let Err(err) = result {
if let Err(_) = result {
warn!("[gstreamer] Async pipeline error detected. Session was likely terminated, clearing XDP token...");
config::LocalConfig::set_option(RESTORE_TOKEN_CONF_KEY.to_owned(), "".to_owned());
let _ = pipeline.set_state(gst::State::Null);
return Err(hbb_common::anyhow::Error::msg(format!("SESSION_REVOKED: GStreamer pipeline failed: {:?}", err)));
return Err(hbb_common::anyhow::Error::new(SessionRevokedError));
}
}
}

View file

@ -261,6 +261,8 @@ pub(super) async fn check_init() -> ResultType<()> {
if let Err(ref e) = result {
if format!("{:?}", e).contains("SESSION_REVOKED") && retry_count < MAX_RETRIES {
retry_count += 1;
// Brief pause before re-requesting the portal permission dialog, to avoid back-to-back prompts firing immediately.
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
continue;
}
}