feat(qconnect): queue_hash divergence scaffold + AskForQueueState trigger
Comparison seam joins the existing resync path. Local hash algorithm is a documented BLOCKING open question; stub returns None so detection stays inert (no spurious resyncs) until the Qobuz algorithm is verified. cc
This commit is contained in:
1 file changed
+42
-1
@@ -326,6 +326,14 @@ where
|
||||
) {
|
||||
should_trigger_resync = true;
|
||||
}
|
||||
|
||||
// queue_hash divergence seam. Inert today (local hash algorithm
|
||||
// is a BLOCKING unknown -> compute_local_queue_hash returns None),
|
||||
// so this never fires spurious resyncs. When the algorithm lands,
|
||||
// a mismatch will pull the authoritative QueueState.
|
||||
if queue_hashes_diverge(&state.queue) {
|
||||
should_trigger_resync = true;
|
||||
}
|
||||
}
|
||||
snapshot = state.queue.clone();
|
||||
}
|
||||
@@ -611,6 +619,28 @@ fn infer_buffer_state(playing_state: Option<i32>) -> Option<i32> {
|
||||
}
|
||||
}
|
||||
|
||||
/// BLOCKING OPEN QUESTION: the Qobuz `queue_hash` (field #100) algorithm is
|
||||
/// undocumented. Until it is verified, this returns `None`, which keeps
|
||||
/// `queue_hashes_diverge` inert so it can NOT fire spurious resyncs. Flipping
|
||||
/// this to a real implementation is the single switch that turns on divergence
|
||||
/// detection.
|
||||
fn compute_local_queue_hash(_queue: &QConnectQueueState) -> Option<Vec<u8>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Algorithm-agnostic divergence seam. Only reports divergence when BOTH a
|
||||
/// locally computed hash and a server-reported hash exist and differ. Because
|
||||
/// `compute_local_queue_hash` returns `None` today, this is always `false`.
|
||||
fn queue_hashes_diverge(queue: &QConnectQueueState) -> bool {
|
||||
match (
|
||||
compute_local_queue_hash(queue),
|
||||
queue.last_server_queue_hash.as_ref(),
|
||||
) {
|
||||
(Some(local), Some(server)) => &local != server,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_server_event(event: &QueueServerEvent, current: &QConnectQueueState) -> QueueEvent {
|
||||
let version = event
|
||||
.queue_version
|
||||
@@ -968,7 +998,8 @@ mod tests {
|
||||
|
||||
use crate::{QconnectAppEvent, QconnectEventSink};
|
||||
|
||||
use super::QconnectApp;
|
||||
use super::{queue_hashes_diverge, QconnectApp};
|
||||
use qconnect_core::QConnectQueueState;
|
||||
use qconnect_protocol::{
|
||||
QueueCommandType, QueueEventType, QueueServerEvent, RendererCommandType,
|
||||
RendererServerCommand,
|
||||
@@ -1186,6 +1217,16 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn queue_hashes_diverge_is_inert_without_local_algorithm() {
|
||||
let mut queue = QConnectQueueState::default();
|
||||
queue.last_server_queue_hash = Some(vec![9, 9, 9]);
|
||||
assert!(
|
||||
!queue_hashes_diverge(&queue),
|
||||
"divergence detection must stay inert until the local hash algorithm is known"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn queue_state_event_surfaces_server_queue_hash() {
|
||||
let (app, _sink, _transport, _events_rx) = build_connected_app().await;
|
||||
|
||||
Reference in new issue
Block a user