fix(qconnect): unwrap inner QCloud envelope and defer renderer join

Root cause: server wraps QConnectMessage inside an inner envelope with
fields 1 (correlation_id), 2 (sequence), 3 (actual message bytes).
We were passing the envelope directly to QConnectMessage::decode(),
which silently skipped the unknown wrapper fields and found nothing.

Also restructure bootstrap: controller join first (works without
session_uuid), renderer join deferred until SESSION_STATE (type 81)
arrives with the session_uuid the server requires.
This commit is contained in:
vicrodh committed 2026-02-21 16:12:37 -06:00
1 parent 68f901257d
commit 309da97b8e
2 files changed
+107 -52

No files matched your search

+25 -3
View File
@@ -594,13 +594,23 @@ fn handle_incoming_binary(
},
);
if let Ok(events) = decode_queue_server_events(&inner_payload) {
// The server wraps QConnectMessages inside an inner envelope with:
// field 1 (fixed64): correlation ID
// field 2 (varint): sequence number
// field 3 (bytes): the actual QConnectMessage protobuf
// We must unwrap field 3 before passing to the decoders.
let qconnect_bytes = match QCloudInnerEnvelope::decode(inner_payload.as_slice()) {
Ok(envelope) => envelope.message.unwrap_or_default(),
Err(_) => inner_payload,
};
if let Ok(events) = decode_queue_server_events(&qconnect_bytes) {
for event in events {
emit(events_tx, TransportEvent::InboundQueueServerEvent(event));
}
}
if let Ok(commands) = decode_renderer_server_commands(&inner_payload) {
if let Ok(commands) = decode_renderer_server_commands(&qconnect_bytes) {
for command in commands {
emit(
events_tx,
@@ -609,7 +619,7 @@ fn handle_incoming_binary(
}
}
if let Ok(inbound) = decode_inbound_json(&inner_payload) {
if let Ok(inbound) = decode_inbound_json(&qconnect_bytes) {
emit(events_tx, TransportEvent::InboundReceived(inbound));
}
}
@@ -792,6 +802,18 @@ struct CloudPayload {
pub payload: Option<Vec<u8>>,
}
/// Inner envelope that wraps QConnectMessage inside CloudPayload.payload.
/// The server sends: CloudPayload { payload: QCloudInnerEnvelope { message: QConnectMessage } }
#[derive(Clone, PartialEq, ::prost::Message)]
struct QCloudInnerEnvelope {
#[prost(fixed64, optional, tag = "1")]
pub correlation_id: Option<u64>,
#[prost(uint64, optional, tag = "2")]
pub sequence: Option<u64>,
#[prost(bytes = "vec", optional, tag = "3")]
pub message: Option<Vec<u8>>,
}
#[cfg(test)]
mod tests {
use super::*;