refactor(qconnect): relocate session topology types to qconnect-app (slice 2+4)
Move QconnectSessionState, QconnectRendererInfo, and QconnectSessionRendererState from the Tauri adapter into the frontend-agnostic qconnect-app::session module, re-exporting them from the Tauri qconnect module so all existing super:: references and the command surface compile unchanged. Field visibility widened to pub for cross-crate access; serialized shape is unchanged. First step of hoisting the QConnect session/liveness layer up so both the Tauri adapter and a future Slint adapter share one session model. qconnect crates + src-tauri qconnect tests green. cc
This commit is contained in:
3 files changed
+60
-38
No files matched your search
@@ -17,7 +17,8 @@ pub use events::{NoOpEventSink, QconnectAppEvent, QconnectEventSink};
|
||||
pub use session::{
|
||||
compute_connection_state, deferred_join_reason, quality_from_max_audio_quality,
|
||||
should_arm_renderer_watchdog, should_reask_queue_state, ConnectionDecision,
|
||||
QconnectLifecycleState, RendererStatus, ServerActiveState,
|
||||
QconnectLifecycleState, QconnectRendererInfo, QconnectSessionRendererState,
|
||||
QconnectSessionState, RendererStatus, ServerActiveState,
|
||||
JOIN_SESSION_REASON_CONTROLLER_REQUEST, JOIN_SESSION_REASON_RECONNECTION,
|
||||
QCONNECT_RENDERER_LOST_TIMEOUT_MS,
|
||||
};
|
||||
|
||||
@@ -186,6 +186,57 @@ pub fn quality_from_max_audio_quality(level: Option<i32>) -> Quality {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Session topology types (relocated from the Tauri adapter — slice 2+4).
|
||||
//
|
||||
// These are pure data describing who is in a QConnect session and the cloud's
|
||||
// per-renderer view. They move here (frontend-agnostic) so both the Tauri and
|
||||
// Slint adapters share one session-topology model under a single lock. Field
|
||||
// visibility is widened to `pub` because the adapters access these fields
|
||||
// across the crate boundary; serialized shape is unchanged.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Per-renderer cached state derived from session-management events
|
||||
/// (RENDERER_STATE_UPDATED etc.): the cloud's latest view of one renderer.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct QconnectSessionRendererState {
|
||||
pub active: Option<bool>,
|
||||
pub playing_state: Option<i32>,
|
||||
pub current_position_ms: Option<u64>,
|
||||
pub current_queue_item_id: Option<u64>,
|
||||
pub volume: Option<i32>,
|
||||
pub muted: Option<bool>,
|
||||
pub max_audio_quality: Option<i32>,
|
||||
pub loop_mode: Option<i32>,
|
||||
pub shuffle_mode: Option<bool>,
|
||||
pub updated_at_ms: u64,
|
||||
}
|
||||
|
||||
/// Session topology — stored from session management events (types 81-87):
|
||||
/// who is in the session, who is active, and which renderer is us.
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct QconnectSessionState {
|
||||
pub session_uuid: Option<String>,
|
||||
pub active_renderer_id: Option<i32>,
|
||||
pub local_renderer_id: Option<i32>,
|
||||
pub renderers: Vec<QconnectRendererInfo>,
|
||||
}
|
||||
|
||||
/// One renderer registered in the QConnect session.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct QconnectRendererInfo {
|
||||
pub renderer_id: i32,
|
||||
pub device_uuid: Option<String>,
|
||||
pub friendly_name: Option<String>,
|
||||
pub brand: Option<String>,
|
||||
pub model: Option<String>,
|
||||
pub device_type: Option<i32>,
|
||||
/// capabilities.volume_remote_control. 1 == ALLOWED. None == not advertised
|
||||
/// (treated as allowed to avoid regressing renderers that omit it).
|
||||
#[serde(default)]
|
||||
pub volume_remote_control: Option<i32>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
use qconnect_app::{QConnectQueueState, QConnectRendererState};
|
||||
use qconnect_core::QueueItem;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::queue_resolution::{
|
||||
find_cursor_index_by_queue_item_id, normalize_current_queue_item_id_from_queue_state,
|
||||
@@ -25,6 +25,12 @@ use super::{
|
||||
/// is not named directly on the Tauri side; it lives in `qconnect_app`.)
|
||||
pub(super) use qconnect_app::{compute_connection_state, ServerActiveState};
|
||||
|
||||
/// Session topology types now live in the frontend-agnostic `qconnect_app::session`
|
||||
/// module (slice 2+4). Re-exported here so existing `super::session::…` /
|
||||
/// `super::…` references inside this module compile unchanged, and so the Tauri
|
||||
/// command surface keeps the same serialized shape.
|
||||
pub use qconnect_app::{QconnectRendererInfo, QconnectSessionRendererState, QconnectSessionState};
|
||||
|
||||
pub(super) fn queue_item_snapshot_for_cursor(
|
||||
queue: &QConnectQueueState,
|
||||
cursor: QconnectOrderedQueueCursor,
|
||||
@@ -40,20 +46,6 @@ pub(super) fn queue_item_snapshot_for_cursor(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub(crate) struct QconnectSessionRendererState {
|
||||
pub(super) active: Option<bool>,
|
||||
pub(super) playing_state: Option<i32>,
|
||||
pub(super) current_position_ms: Option<u64>,
|
||||
pub(super) current_queue_item_id: Option<u64>,
|
||||
pub(super) volume: Option<i32>,
|
||||
pub(super) muted: Option<bool>,
|
||||
pub(super) max_audio_quality: Option<i32>,
|
||||
pub(super) loop_mode: Option<i32>,
|
||||
pub(super) shuffle_mode: Option<bool>,
|
||||
pub(super) updated_at_ms: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) struct QconnectFileAudioQualitySnapshot {
|
||||
pub(super) sampling_rate: i32,
|
||||
@@ -62,14 +54,6 @@ pub(crate) struct QconnectFileAudioQualitySnapshot {
|
||||
pub(super) audio_quality: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct QconnectSessionState {
|
||||
pub session_uuid: Option<String>,
|
||||
pub active_renderer_id: Option<i32>,
|
||||
pub local_renderer_id: Option<i32>,
|
||||
pub renderers: Vec<QconnectRendererInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub(crate) struct QconnectRendererReportDebugEvent {
|
||||
pub(super) requested_current_queue_item_id: Option<i32>,
|
||||
@@ -87,20 +71,6 @@ pub(crate) struct QconnectRendererReportDebugEvent {
|
||||
pub(super) resolution_strategy: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct QconnectRendererInfo {
|
||||
pub renderer_id: i32,
|
||||
pub device_uuid: Option<String>,
|
||||
pub friendly_name: Option<String>,
|
||||
pub brand: Option<String>,
|
||||
pub model: Option<String>,
|
||||
pub device_type: Option<i32>,
|
||||
/// capabilities.volume_remote_control. 1 == ALLOWED. None == not advertised
|
||||
/// (treated as allowed to avoid regressing renderers that omit it).
|
||||
#[serde(default)]
|
||||
pub volume_remote_control: Option<i32>,
|
||||
}
|
||||
|
||||
/// Whether the active renderer permits remote volume control. Absent capability
|
||||
/// (None) defaults to allowed; only an explicit non-ALLOWED value disables.
|
||||
pub(super) fn renderer_allows_remote_volume(info: &QconnectRendererInfo) -> bool {
|
||||
|
||||
Reference in new issue
Block a user