use std::sync::Arc;
use super::{
ConsumerCursor, DurabilityError, DurableChannel, DurableConversation, DurableStore,
MessageEnvelope, head_checkpoint::recover_partition_head, replay_from,
};
#[cfg(test)]
mod tests;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RecoveredCursor {
pub cursor: ConsumerCursor,
pub replayed_messages: Vec<MessageEnvelope>,
}
pub async fn recover_partition_sequences(
channel_id: &str,
partition_count: usize,
store: &dyn DurableStore,
) -> Result<Vec<u64>, DurabilityError> {
let mut next_sequences = Vec::with_capacity(partition_count);
for partition_index in 0..partition_count {
let stream_key = partition_stream_key(channel_id, partition_index);
next_sequences.push(recover_partition_head(store, &stream_key).await?);
}
Ok(next_sequences)
}
pub async fn recover_durable_channel(
channel_id: impl Into<String>,
partition_count: usize,
store: Arc<dyn DurableStore>,
) -> Result<DurableChannel, DurabilityError> {
let channel_id = channel_id.into();
let next_sequences =
recover_partition_sequences(&channel_id, partition_count, store.as_ref()).await?;
DurableChannel::from_recovered_sequences(channel_id, partition_count, store, next_sequences)
}
pub async fn recover_conversation(
conversation_id: impl Into<String>,
store: Arc<dyn DurableStore>,
) -> Result<DurableConversation, DurabilityError> {
DurableConversation::recover(conversation_id, store).await
}
pub async fn recover_cursor(
consumer_id: impl Into<String>,
partition_key: impl Into<String>,
store: &dyn DurableStore,
) -> Result<ConsumerCursor, DurabilityError> {
ConsumerCursor::resume(consumer_id, partition_key, store).await
}
pub async fn recover_cursor_with_replay(
consumer_id: impl Into<String>,
partition_key: impl Into<String>,
store: &dyn DurableStore,
) -> Result<RecoveredCursor, DurabilityError> {
let cursor = recover_cursor(consumer_id, partition_key, store).await?;
let replayed_messages =
replay_from(store, cursor.partition_key(), cursor.current_offset()).await?;
Ok(RecoveredCursor {
cursor,
replayed_messages,
})
}
fn partition_stream_key(channel_id: &str, partition_index: usize) -> String {
format!("{channel_id}:{partition_index}")
}