chore: log the three failures that were silently discarded

Volume restore (desktop session and qbzd driver), a playback-thread panic
at stop, and a credentials decrypt failure (now naming the file and the
likely cause, without the inert legacy retry).

cc
This commit is contained in:
vicrodh committed 2026-09-13 03:36:51 -06:00
1 parent aff24e598b
commit 196887534a
4 files changed
+24 -11

No files matched your search

+3 -1
View File
@@ -1171,7 +1171,9 @@ pub async fn restore_session_paused<A: FrontendAdapter + Send + Sync + 'static>(
core.set_queue_with_order(tracks, index, pb.shuffle_enabled, None) core.set_queue_with_order(tracks, index, pb.shuffle_enabled, None)
.await; .await;
core.set_repeat_mode(repeat_from_str(&pb.repeat_mode)).await; core.set_repeat_mode(repeat_from_str(&pb.repeat_mode)).await;
let _ = core.set_volume(pb.volume); if let Err(e) = core.set_volume(pb.volume) {
log::warn!("[qbzd] driver: volume restore failed: {e}");
}
log::info!( log::info!(
"[qbzd] driver: restored {count} queue tracks (index {index:?}), paused; \ "[qbzd] driver: restored {count} queue tracks (index {index:?}), paused; \
saved position {position}s" saved position {position}s"
+3 -1
View File
@@ -453,7 +453,9 @@ pub async fn restore<A: Adapter>(runtime: &Arc<AppRuntime<A>>) -> bool {
.await; .await;
// The queue session carries the authoritative last volume; apply it to the // The queue session carries the authoritative last volume; apply it to the
// player (the slider also seeds from ui_prefs, but this keeps them in step). // player (the slider also seeds from ui_prefs, but this keeps them in step).
let _ = runtime.core().set_volume(pb_sess.volume); if let Err(e) = runtime.core().set_volume(pb_sess.volume) {
log::warn!("[session] persist: volume restore failed: {e}");
}
if RESUME_POSITION.load(Ordering::Relaxed) && position > 0 && current_track_id != 0 { if RESUME_POSITION.load(Ordering::Relaxed) && position > 0 && current_track_id != 0 {
PENDING_RESUME.store(position, Ordering::Relaxed); PENDING_RESUME.store(position, Ordering::Relaxed);
PENDING_RESUME_TRACK.store(current_track_id, Ordering::Relaxed); PENDING_RESUME_TRACK.store(current_track_id, Ordering::Relaxed);
+9 -6
View File
@@ -596,12 +596,15 @@ fn load_from_fallback() -> Result<Option<QobuzCredentials>, String> {
Ok(Some(creds)) Ok(Some(creds))
} }
Err(e) => { Err(e) => {
log::warn!("Failed to decrypt credentials: {}", e); // A new-format file that fails to decrypt is a key mismatch
// Try legacy format as fallback // (machine-id / install salt / portal secret changed — see the
if let Ok(Some(creds)) = load_legacy_credentials(&path) { // daemon hazard on `PortalKey`) or a corrupt file; the legacy
log::info!("Loaded from legacy format, will re-encrypt on next save"); // loader cannot succeed on JSON, so it is not tried. A fresh
return Ok(Some(creds)); // login rewrites the file.
} log::warn!(
"Failed to decrypt credentials at {}: {e} (key derivation inputs changed or the file is corrupt; log in again to rewrite it)",
path.display()
);
Err(e) Err(e)
} }
} }
@@ -568,7 +568,9 @@ impl PlaybackEngine {
is_playing.store(false, Ordering::SeqCst); is_playing.store(false, Ordering::SeqCst);
if let Some(handle) = playback_thread.take() { if let Some(handle) = playback_thread.take() {
let _ = handle.join(); if handle.join().is_err() {
log::error!("[{label}] playback thread panicked before stop completed");
}
} }
if let Err(e) = stream.stop() { if let Err(e) = stream.stop() {
@@ -589,7 +591,9 @@ impl PlaybackEngine {
should_stop.store(true, Ordering::SeqCst); should_stop.store(true, Ordering::SeqCst);
is_playing.store(false, Ordering::SeqCst); is_playing.store(false, Ordering::SeqCst);
if let Some(handle) = feeder_thread.take() { if let Some(handle) = feeder_thread.take() {
let _ = handle.join(); if handle.join().is_err() {
log::error!("[JACK Engine] feeder thread panicked before stop completed");
}
} }
// JackStream's Drop deactivates the client + unregisters the ports. // JackStream's Drop deactivates the client + unregisters the ports.
} }
@@ -608,7 +612,9 @@ impl PlaybackEngine {
should_stop.store(true, Ordering::SeqCst); should_stop.store(true, Ordering::SeqCst);
is_playing.store(false, Ordering::SeqCst); is_playing.store(false, Ordering::SeqCst);
if let Some(handle) = writer_thread.take() { if let Some(handle) = writer_thread.take() {
let _ = handle.join(); if handle.join().is_err() {
log::error!("[DoP Engine] writer thread panicked before stop completed");
}
} }
if let Err(e) = stream.stop() { if let Err(e) = stream.stop() {
log::warn!("[DoP Engine] Stop failed: {}", e); log::warn!("[DoP Engine] Stop failed: {}", e);