hashiverse_lib/client/post_bundle/post_bundle_manager.rs
1//! # Post-bundle lookup trait
2//!
3//! One trait — [`PostBundleManager`] — that maps a `(BucketLocation, TimeMillis)` to an
4//! [`EncodedPostBundleV1`]. Implementations decide whether to serve from the local cache,
5//! pull from one peer, or heal from several, but timeline logic
6//! ([`crate::client::timeline`]) only sees the trait. That keeps the walk algorithm
7//! network-free and lets tests plug in deterministic stubs.
8
9use crate::protocol::posting::encoded_post_bundle::EncodedPostBundleV1;
10use crate::tools::buckets::BucketLocation;
11use crate::tools::time::TimeMillis;
12
13/// The abstract lookup from "give me the posts at this (location, time) bucket" to an
14/// [`EncodedPostBundleV1`].
15///
16/// Timeline code above this trait does not care whether the bundle came from the local
17/// cache, from a single network peer, or was stitched together from several peers after a
18/// healing round — it just calls `get_post_bundle`. The production implementation is
19/// [`crate::client::post_bundle::live_post_bundle_manager::LivePostBundleManager`], which
20/// checks local [`ClientStorage`] first, falls back to the best peer from
21/// [`crate::client::peer_tracker::PeerTracker`], and transparently heals missing posts.
22/// Tests swap in stub implementations that return canned bundles so the timeline logic can
23/// be exercised without any network.
24#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
25#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
26pub trait PostBundleManager: Send + Sync {
27 async fn get_post_bundle(&self, bucket_location: &BucketLocation, time_millis: TimeMillis) -> anyhow::Result<EncodedPostBundleV1>;
28}
29