Files
quicproquo/crates/quicproquo-sdk/src/outbox.rs

77 lines
2.5 KiB
Rust

//! 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}")))
}