mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-04 00:47:00 +01:00
fix(core,app,android): refresh an expired visitor session on the desktop too
The age check and the one retry behind a refresh (B22) lived only in the Android bridge. The desktop opened streams, offline copies and crawls against whatever session the share was opened with, so a window left open for a few hours failed to play or recrawl until it was restarted. The logic moves to pstr-core as SessionAges, owned by SharedLibrary and reached through SharedLibrary::reauthenticating. Both engines go through it for play, warm, offline copy and (desktop) crawl.
This commit is contained in:
1 parent
ce02bbc35a
commit
9e53a9bbdb
3 files changed
+209
-63
No files matched your search
@@ -949,12 +949,6 @@ pub struct AndroidEngine {
|
||||
share_generation: AtomicU64,
|
||||
/// How many Proton thumbnails may be in flight at once.
|
||||
thumbnails: tokio::sync::Semaphore,
|
||||
/// When each share's visitor session was last refreshed.
|
||||
///
|
||||
/// Sessions are short-lived and the app is routinely backgrounded for hours
|
||||
/// between one episode and the next, so age — not just a share-store
|
||||
/// mutation — is a reason to reauthenticate before opening anything.
|
||||
session_refreshed: Mutex<HashMap<String, std::time::Instant>>,
|
||||
/// The streaming cache's budget in bytes, for the next connection and,
|
||||
/// through [`AndroidEngine::set_stream_cache_budget`], the open one.
|
||||
cache_budget: AtomicU64,
|
||||
@@ -982,13 +976,6 @@ const OFFLINE_DOWNLOAD_CONCURRENCY: usize = 2;
|
||||
/// How often a download waiting for a slot asks whether it was cancelled.
|
||||
const DOWNLOAD_WAIT_POLL: std::time::Duration = std::time::Duration::from_millis(500);
|
||||
|
||||
/// How long a visitor session is assumed good for without a refresh.
|
||||
///
|
||||
/// A refresh costs one round trip. Not refreshing costs an authentication
|
||||
/// failure that, before this, the viewer could only clear with a manual
|
||||
/// pull-to-refresh.
|
||||
const SESSION_FRESH_FOR: std::time::Duration = std::time::Duration::from_secs(5 * 60);
|
||||
|
||||
#[uniffi::export]
|
||||
impl AndroidEngine {
|
||||
#[uniffi::constructor]
|
||||
@@ -1034,7 +1021,6 @@ impl AndroidEngine {
|
||||
share_publication: Mutex::new(()),
|
||||
share_generation: AtomicU64::new(0),
|
||||
thumbnails: tokio::sync::Semaphore::new(THUMBNAIL_CONCURRENCY),
|
||||
session_refreshed: Mutex::new(HashMap::new()),
|
||||
cache_budget: AtomicU64::new(DiskCacheConfig::DEFAULT_BUDGET_BYTES),
|
||||
download_permits: Arc::new(tokio::sync::Semaphore::new(OFFLINE_DOWNLOAD_CONCURRENCY)),
|
||||
accounts,
|
||||
@@ -2281,7 +2267,6 @@ impl AndroidEngine {
|
||||
}
|
||||
}
|
||||
drop(reusable);
|
||||
self.session_refreshed.lock().remove(share_id);
|
||||
self.share_generation.fetch_add(1, Ordering::AcqRel);
|
||||
}
|
||||
|
||||
@@ -2445,39 +2430,17 @@ impl AndroidEngine {
|
||||
uid: &NodeUid,
|
||||
copy: bool,
|
||||
) -> Result<VideoStream, BridgeError> {
|
||||
let open = || async {
|
||||
if copy {
|
||||
connection.source.open_for_copy(share_id, uid).await
|
||||
} else {
|
||||
connection.source.open(share_id, uid).await
|
||||
}
|
||||
};
|
||||
let stale = self
|
||||
.session_refreshed
|
||||
.lock()
|
||||
.get(share_id)
|
||||
.is_none_or(|at| at.elapsed() >= SESSION_FRESH_FOR);
|
||||
if stale {
|
||||
self.refresh_session(connection, share_id).await;
|
||||
}
|
||||
match open().await {
|
||||
Ok(stream) => Ok(stream),
|
||||
Err(_) if !stale => {
|
||||
self.refresh_session(connection, share_id).await;
|
||||
open().await.map_err(BridgeError::from_display)
|
||||
}
|
||||
Err(error) => Err(BridgeError::from_display(error)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Best-effort: a refresh that fails leaves the open to report the real
|
||||
/// problem, which is more useful than a refresh error standing in for it.
|
||||
async fn refresh_session(&self, connection: &Connection, share_id: &str) {
|
||||
if connection.library.refresh_session(share_id).await.is_ok() {
|
||||
self.session_refreshed
|
||||
.lock()
|
||||
.insert(share_id.to_owned(), std::time::Instant::now());
|
||||
}
|
||||
connection
|
||||
.library
|
||||
.reauthenticating(share_id, || async {
|
||||
if copy {
|
||||
connection.source.open_for_copy(share_id, uid).await
|
||||
} else {
|
||||
connection.source.open(share_id, uid).await
|
||||
}
|
||||
})
|
||||
.await
|
||||
.map_err(BridgeError::from_display)
|
||||
}
|
||||
|
||||
async fn crawl_inner(&self, share_id: Option<String>) -> Result<(), BridgeError> {
|
||||
@@ -2494,9 +2457,6 @@ impl AndroidEngine {
|
||||
.map_err(|error| BridgeError::Failure {
|
||||
reason: format!("refresh session for {id}: {error}"),
|
||||
})?;
|
||||
self.session_refreshed
|
||||
.lock()
|
||||
.insert(id.clone(), std::time::Instant::now());
|
||||
let before = self
|
||||
.catalog
|
||||
.lock()
|
||||
|
||||
Reference in new issue
Block a user