feat(sdk): wire device_id through messaging and client APIs

Add device_id parameter to fetch, fetch_wait, ack, receive_messages,
and receive_messages_wait SDK functions. QpqClient gains device_id
field with register_device/list_devices/revoke_device convenience
methods. Client REPL passes empty device_id for backwards compat.
This commit is contained in:
2026-03-04 20:19:30 +01:00
parent 799aab68fe
commit fd1accc6dd
3 changed files with 392 additions and 9 deletions

View File

@@ -23,6 +23,10 @@ pub struct QpqClient {
session_token: Option<Vec<u8>>,
/// Local conversation store (SQLCipher).
conv_store: Option<ConversationStore>,
/// Device ID for multi-device support.
/// When set, fetch/peek/ack requests include this device_id so the server
/// scopes them to the correct per-device queue.
device_id: Option<Vec<u8>>,
}
impl QpqClient {
@@ -37,6 +41,7 @@ impl QpqClient {
identity_key: None,
session_token: None,
conv_store: None,
device_id: None,
}
}
@@ -174,6 +179,45 @@ impl QpqClient {
self.session_token.as_deref()
}
// ── Multi-device ─────────────────────────────────────────────────────────
/// Set the device ID for this client. Subsequent fetch/peek/ack calls
/// will include this ID so the server scopes them to the correct queue.
pub fn set_device_id(&mut self, device_id: Vec<u8>) {
self.device_id = Some(device_id);
}
/// Get the current device ID, if set.
pub fn device_id(&self) -> Option<&[u8]> {
self.device_id.as_deref()
}
/// Register this device with the server.
/// Sets the local device_id on success.
pub async fn register_device(
&mut self,
device_id: &[u8],
device_name: &str,
) -> Result<bool, SdkError> {
let rpc = self.rpc.as_ref().ok_or(SdkError::NotConnected)?;
let newly_registered =
crate::devices::register_device(rpc, device_id, device_name).await?;
self.device_id = Some(device_id.to_vec());
Ok(newly_registered)
}
/// List all registered devices for this identity.
pub async fn list_devices(&self) -> Result<Vec<crate::devices::DeviceInfo>, SdkError> {
let rpc = self.rpc.as_ref().ok_or(SdkError::NotConnected)?;
crate::devices::list_devices(rpc).await
}
/// Revoke (remove) a registered device.
pub async fn revoke_device(&self, device_id: &[u8]) -> Result<bool, SdkError> {
let rpc = self.rpc.as_ref().ok_or(SdkError::NotConnected)?;
crate::devices::revoke_device(rpc, device_id).await
}
// ── Moderation (client-side) ────────────────────────────────────────────
/// Block a user locally. Their messages will be hidden from display.