Always refetch /orphans (and fix the web client's stale cache roots)
The clients cache library listings except for server-mutable folder roots. /orphans is recomputed from the store on every visit, so a cached listing froze the orphan set until a client restart. Add /orphans to the TUI's mutable-roots list so entering the provider always re-walks. The web client's list was also stale from the store refactor — it still named the removed /captures, /queues, /bookmarks providers and omitted /crabidy, so /crabidy (and now /orphans) listings went stale there too. Reset it to the real mutable roots: /crabidy, /fs, /orphans. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cd33b790b5
commit
3a03114cb9
|
|
@ -87,12 +87,13 @@ pub struct RpcClient {
|
||||||
///
|
///
|
||||||
/// The server-side folder providers mutate behind the client's back —
|
/// The server-side folder providers mutate behind the client's back —
|
||||||
/// saves and captures appear under `/crabidy` (`w`/`W`), files change on
|
/// saves and captures appear under `/crabidy` (`w`/`W`), files change on
|
||||||
/// disk under `/fs` — so a cached listing turns freshly captured content
|
/// disk under `/fs`, and `/orphans` is recomputed from the store on every
|
||||||
/// invisible until a restart. Their listings are cheap local directory
|
/// visit — so a cached listing turns freshly captured content (or a changed
|
||||||
|
/// orphan set) invisible until a restart. Their listings are cheap local
|
||||||
/// walks on the server; always refetch them. Remote provider nodes (tidal,
|
/// walks on the server; always refetch them. Remote provider nodes (tidal,
|
||||||
/// youtube) keep the cache that makes back-navigation instant.
|
/// youtube) keep the cache that makes back-navigation instant.
|
||||||
fn is_cacheable(path: &str) -> bool {
|
fn is_cacheable(path: &str) -> bool {
|
||||||
const MUTABLE_ROOTS: [&str; 2] = ["/crabidy", "/fs"];
|
const MUTABLE_ROOTS: [&str; 3] = ["/crabidy", "/fs", "/orphans"];
|
||||||
!MUTABLE_ROOTS.iter().any(|root| {
|
!MUTABLE_ROOTS.iter().any(|root| {
|
||||||
path == *root || (path.starts_with(root) && path.as_bytes().get(root.len()) == Some(&b'/'))
|
path == *root || (path.starts_with(root) && path.as_bytes().get(root.len()) == Some(&b'/'))
|
||||||
})
|
})
|
||||||
|
|
@ -398,6 +399,8 @@ mod tests {
|
||||||
"/crabidy/current",
|
"/crabidy/current",
|
||||||
"/crabidy/road trip",
|
"/crabidy/road trip",
|
||||||
"/fs/music",
|
"/fs/music",
|
||||||
|
"/orphans",
|
||||||
|
"/orphans/stray.flac",
|
||||||
] {
|
] {
|
||||||
assert!(!is_cacheable(path), "{path}");
|
assert!(!is_cacheable(path), "{path}");
|
||||||
}
|
}
|
||||||
|
|
@ -408,5 +411,6 @@ mod tests {
|
||||||
// …and prefix look-alikes are not swept up.
|
// …and prefix look-alikes are not swept up.
|
||||||
assert!(is_cacheable("/fsdy"));
|
assert!(is_cacheable("/fsdy"));
|
||||||
assert!(is_cacheable("/crabidystore"));
|
assert!(is_cacheable("/crabidystore"));
|
||||||
|
assert!(is_cacheable("/orphansaurus"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,12 @@ pub fn delete_needs_confirmation(path: &str) -> bool {
|
||||||
|
|
||||||
/// Whether a library listing may be cached client-side — same rule as
|
/// Whether a library listing may be cached client-side — same rule as
|
||||||
/// the TUI (`cbd-tui/src/rpc.rs`): server-side folder providers mutate
|
/// the TUI (`cbd-tui/src/rpc.rs`): server-side folder providers mutate
|
||||||
/// behind the client's back and are cheap to re-list.
|
/// behind the client's back and are cheap to re-list. `/crabidy` (saves and
|
||||||
|
/// captures), `/fs` (files on disk), and `/orphans` (recomputed from the
|
||||||
|
/// store on every visit) all change server-side, so their listings are
|
||||||
|
/// always refetched.
|
||||||
pub fn is_cacheable(path: &str) -> bool {
|
pub fn is_cacheable(path: &str) -> bool {
|
||||||
const MUTABLE_ROOTS: [&str; 4] = ["/captures", "/queues", "/bookmarks", "/fs"];
|
const MUTABLE_ROOTS: [&str; 3] = ["/crabidy", "/fs", "/orphans"];
|
||||||
!MUTABLE_ROOTS.iter().any(|root| {
|
!MUTABLE_ROOTS.iter().any(|root| {
|
||||||
path == *root || (path.starts_with(root) && path.as_bytes().get(root.len()) == Some(&b'/'))
|
path == *root || (path.starts_with(root) && path.as_bytes().get(root.len()) == Some(&b'/'))
|
||||||
})
|
})
|
||||||
|
|
@ -465,10 +468,21 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mutable_roots_are_never_cacheable() {
|
fn mutable_roots_are_never_cacheable() {
|
||||||
for path in ["/captures", "/queues/x", "/bookmarks", "/fs/music"] {
|
for path in [
|
||||||
|
"/crabidy",
|
||||||
|
"/crabidy/faves",
|
||||||
|
"/fs/music",
|
||||||
|
"/orphans",
|
||||||
|
"/orphans/stray.flac",
|
||||||
|
] {
|
||||||
assert!(!is_cacheable(path), "{path}");
|
assert!(!is_cacheable(path), "{path}");
|
||||||
}
|
}
|
||||||
for path in ["/tidal/playlists", "/youtube/search", "/capturesque"] {
|
for path in [
|
||||||
|
"/tidal/playlists",
|
||||||
|
"/youtube/search",
|
||||||
|
"/crabidystore",
|
||||||
|
"/orphansaurus",
|
||||||
|
] {
|
||||||
assert!(is_cacheable(path), "{path}");
|
assert!(is_cacheable(path), "{path}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue