feat(sdk): conversation management — DM/group lifecycle, outbox
This commit is contained in:
76
crates/quicproquo-sdk/src/outbox.rs
Normal file
76
crates/quicproquo-sdk/src/outbox.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
//! Offline outbox — queue messages for deferred delivery.
|
||||
|
||||
use bytes::Bytes;
|
||||
use prost::Message;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use quicproquo_proto::method_ids;
|
||||
use quicproquo_proto::qpq::v1::{EnqueueRequest, EnqueueResponse};
|
||||
use quicproquo_rpc::client::RpcClient;
|
||||
|
||||
use crate::conversation::{ConversationId, ConversationStore};
|
||||
use crate::error::SdkError;
|
||||
|
||||
/// Queue a message for sending when connectivity is restored.
|
||||
pub fn queue_outbox(
|
||||
conv_store: &ConversationStore,
|
||||
conv_id: &ConversationId,
|
||||
recipient_key: &[u8],
|
||||
payload: &[u8],
|
||||
) -> Result<(), SdkError> {
|
||||
conv_store
|
||||
.enqueue_outbox(conv_id, recipient_key, payload)
|
||||
.map_err(|e| SdkError::Storage(format!("enqueue outbox: {e}")))
|
||||
}
|
||||
|
||||
/// Process all pending outbox entries — send them to the server.
|
||||
///
|
||||
/// Returns the number of entries successfully sent.
|
||||
pub async fn flush_outbox(
|
||||
rpc: &RpcClient,
|
||||
conv_store: &ConversationStore,
|
||||
) -> Result<usize, SdkError> {
|
||||
let entries = conv_store
|
||||
.load_pending_outbox()
|
||||
.map_err(|e| SdkError::Storage(format!("load outbox: {e}")))?;
|
||||
|
||||
let mut sent = 0usize;
|
||||
for entry in &entries {
|
||||
let req = EnqueueRequest {
|
||||
recipient_key: entry.recipient_key.clone(),
|
||||
payload: entry.payload.clone(),
|
||||
channel_id: Vec::new(),
|
||||
ttl_secs: 0,
|
||||
};
|
||||
match rpc
|
||||
.call(method_ids::ENQUEUE, Bytes::from(req.encode_to_vec()))
|
||||
.await
|
||||
{
|
||||
Ok(resp_bytes) => {
|
||||
if let Err(e) = EnqueueResponse::decode(resp_bytes) {
|
||||
warn!(outbox_id = entry.id, "decode enqueue response: {e}");
|
||||
}
|
||||
conv_store
|
||||
.mark_outbox_sent(entry.id)
|
||||
.map_err(|e| SdkError::Storage(format!("mark_outbox_sent: {e}")))?;
|
||||
sent += 1;
|
||||
debug!(outbox_id = entry.id, "outbox entry sent");
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(outbox_id = entry.id, "outbox send failed: {e}");
|
||||
conv_store
|
||||
.mark_outbox_failed(entry.id, entry.retry_count + 1)
|
||||
.map_err(|e| SdkError::Storage(format!("mark_outbox_failed: {e}")))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(sent)
|
||||
}
|
||||
|
||||
/// Get the number of pending outbox entries.
|
||||
pub fn outbox_count(conv_store: &ConversationStore) -> Result<usize, SdkError> {
|
||||
conv_store
|
||||
.count_pending_outbox()
|
||||
.map_err(|e| SdkError::Storage(format!("count outbox: {e}")))
|
||||
}
|
||||
Reference in New Issue
Block a user