use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CursorState {
pub last_slot: u64,
pub slots_ingested: u64,
pub slots_skipped: u64,
}
impl Default for CursorState {
fn default() -> Self {
Self {
last_slot: 0,
slots_ingested: 0,
slots_skipped: 0,
}
}
}
pub fn load_cursor(path: &str) -> CursorState {
let p = Path::new(path);
if !p.exists() {
return CursorState::default();
}
match std::fs::read_to_string(p) {
Ok(data) => match serde_json::from_str::<CursorState>(&data) {
Ok(cursor) => {
tracing::info!(
"Loaded cursor: last_slot={}, ingested={}, skipped={}",
cursor.last_slot,
cursor.slots_ingested,
cursor.slots_skipped
);
cursor
}
Err(e) => {
tracing::warn!("Cursor file corrupt ({}), starting fresh", e);
CursorState::default()
}
},
Err(e) => {
tracing::warn!("Cannot read cursor file ({}), starting fresh", e);
CursorState::default()
}
}
}
pub fn save_cursor(path: &str, state: &CursorState) -> Result<()> {
let json = serde_json::to_string_pretty(state)?;
let tmp = format!("{}.tmp", path);
std::fs::write(&tmp, &json)?;
std::fs::rename(&tmp, path)?;
Ok(())
}