pub mod backfill;
pub mod bench_cmd;
pub mod compact;
pub mod diff;
pub mod get;
pub mod history;
pub mod index;
pub mod probe;
pub mod sync;
pub mod typegen;
pub mod verify;
pub mod watch;
use crate::remote::RemoteArchive;
use alloy_primitives::{Address, B256};
use bal_archive::{Archive, ArchiveError, ArchiveStats, HistoryEntry, NotAvailable, StorageValue};
use std::path::PathBuf;
pub struct Ctx {
pub data: PathBuf,
pub json: bool,
pub cfg: crate::config::Config,
}
pub enum Backend {
Local(Archive),
Remote(RemoteArchive),
}
macro_rules! either {
($self:ident, $a:ident => $e:expr) => {
match $self {
Backend::Local($a) => $e,
Backend::Remote($a) => $e,
}
};
}
impl Backend {
pub fn storage_at(
&self,
addr: Address,
slot: B256,
block: u64,
) -> Result<StorageValue, NotAvailable> {
either!(self, a => a.storage_at(addr, slot, block))
}
pub fn history(
&self,
addr: Address,
slot: B256,
range: std::ops::Range<u64>,
) -> Result<Vec<HistoryEntry>, NotAvailable> {
either!(self, a => a.history(addr, slot, range))
}
pub fn changed_slots(&self, addr: Address, block: u64) -> Result<Vec<B256>, NotAvailable> {
either!(self, a => a.changed_slots(addr, block))
}
pub fn stats(&self) -> Result<ArchiveStats, ArchiveError> {
either!(self, a => a.stats())
}
pub fn local(&self) -> Option<&Archive> {
match self {
Backend::Local(a) => Some(a),
Backend::Remote(_) => None,
}
}
pub fn via(&self) -> Option<&str> {
match self {
Backend::Local(_) => None,
Backend::Remote(r) => Some(r.url()),
}
}
}
impl Ctx {
pub fn open_local(&self) -> anyhow::Result<Archive> {
Ok(Archive::open(&self.data)?)
}
pub fn open(&self) -> anyhow::Result<Backend> {
match Archive::open(&self.data) {
Ok(a) => Ok(Backend::Local(a)),
Err(e) if e.to_string().contains("already open") => {
let side = crate::serve::sidecar(&self.data);
let Ok(url) = std::fs::read_to_string(&side) else {
anyhow::bail!(
"{e}\n another process holds {}; run it with `index --serve` to read from here meanwhile",
self.data.display()
);
};
let remote = RemoteArchive::new(url.trim());
match remote.head() {
Ok(_) => Ok(Backend::Remote(remote)),
Err(_) => {
let _ = std::fs::remove_file(&side);
anyhow::bail!(
"{e}\n {} pointed at a server that no longer answers; removed it",
side.display()
)
}
}
}
Err(e) => Err(e.into()),
}
}
}