use crate::orderbook::{OrderBookError, OrderBookTracker};
use crate::storage::{StorageManager, StreamKey};
use digdigdig3::core::types::{OrderBook, OrderbookDelta};
#[derive(Debug, Clone)]
pub struct GapInfo {
pub ts_ms: i64,
pub expected: u64,
pub got: u64,
}
pub struct GapDetector<'a> {
storage: &'a StorageManager,
}
impl<'a> GapDetector<'a> {
pub fn new(storage: &'a StorageManager) -> Self {
Self { storage }
}
pub async fn detect(
&self,
key: &StreamKey,
from_ms: i64,
to_ms: i64,
) -> std::io::Result<Vec<GapInfo>> {
let records = self.storage.read_range(key, from_ms, to_ms).await?;
let mut tracker = OrderBookTracker::new("replay");
let mut gaps = Vec::new();
for (ts, payload) in records {
let is_delta = serde_json::from_slice::<serde_json::Value>(&payload)
.ok()
.and_then(|v| v.get("prev_update_id").cloned())
.is_some();
if is_delta {
if let Ok(delta) = serde_json::from_slice::<OrderbookDelta>(&payload) {
if let Err(OrderBookError::SequenceGap { last, got }) =
tracker.apply_delta(&delta)
{
gaps.push(GapInfo {
ts_ms: ts,
expected: last,
got,
});
}
}
} else if let Ok(snapshot) = serde_json::from_slice::<OrderBook>(&payload) {
if let Err(OrderBookError::SequenceGap { last, got }) =
tracker.apply_snapshot(&snapshot)
{
gaps.push(GapInfo {
ts_ms: ts,
expected: last,
got,
});
}
}
}
Ok(gaps)
}
}