hashiverse_lib/client/post_bundle/
stub_post_bundle_manager.rs1use crate::client::post_bundle::post_bundle_manager::PostBundleManager;
12use crate::protocol::peer::Peer;
13use crate::protocol::posting::encoded_post_bundle::{EncodedPostBundleHeaderV1, EncodedPostBundleV1};
14use crate::tools::buckets::{BucketLocation, BucketType};
15use crate::tools::config;
16use crate::tools::time::{DurationMillis, TimeMillis};
17use crate::tools::types::{Id, Signature};
18use log::{trace, warn};
19use parking_lot::RwLock;
20use std::collections::{HashMap, HashSet};
21use bytes::Bytes;
22
23pub struct StubPostBundleManager {
24 post_bundles: RwLock<HashMap<Id, EncodedPostBundleV1>>,
25 requested_location_ids: RwLock<Vec<Id>>,
26}
27
28impl StubPostBundleManager {
29 pub fn add_random_stub_post_bundle(&self, id: &Id, granularity: DurationMillis, epoch_offset_str: &str, num_posts: u8) -> anyhow::Result<EncodedPostBundleV1> {
30 let bucket_location = BucketLocation::new(BucketType::User, *id, granularity, TimeMillis::from_epoch_offset_str(epoch_offset_str)?)?;
31
32 let mut post_bundle = EncodedPostBundleV1::stub();
33 post_bundle.header.location_id = bucket_location.location_id;
34 post_bundle.header.num_posts = num_posts;
35 for _ in 0..num_posts {
36 post_bundle.header.encoded_post_ids.push(Id::random());
37 post_bundle.header.encoded_post_lengths.push(0);
38 }
39 let result = self.post_bundles.write().insert(bucket_location.location_id, post_bundle.clone());
40 if result.is_some() {
41 warn!("Replaced stub post bundle for location_id: {}", bucket_location.location_id);
42 }
43
44 Ok(post_bundle)
45 }
46
47 pub fn add_stub_post_bundle(&self, id: &Id, granularity: DurationMillis, epoch_offset_str: &str, post_bundle: &EncodedPostBundleV1) -> anyhow::Result<()> {
48 let bucket_location = BucketLocation::new(BucketType::User, *id, granularity, TimeMillis::from_epoch_offset_str(epoch_offset_str)?)?;
49
50 let result = self.post_bundles.write().insert(bucket_location.location_id, post_bundle.clone());
51 if result.is_some() {
52 warn!("Replaced stub post bundle for location_id: {}", bucket_location.location_id);
53 }
54
55 Ok(())
56 }
57
58 pub fn requested_location_ids(&self) -> Vec<Id> {
60 self.requested_location_ids.read().clone()
61 }
62}
63
64impl Default for StubPostBundleManager {
65 fn default() -> Self {
66 Self { post_bundles: RwLock::new(HashMap::new()), requested_location_ids: RwLock::new(Vec::new()) }
67 }
68}
69
70#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
71#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
72impl PostBundleManager for StubPostBundleManager {
73 async fn get_post_bundle(&self, bucket_location: &BucketLocation, time_millis: TimeMillis) -> anyhow::Result<EncodedPostBundleV1> {
74 self.requested_location_ids.write().push(bucket_location.location_id);
75 let post_bundles = self.post_bundles.read();
76 let post_bundle = post_bundles.get(&bucket_location.location_id);
77 let post_bundle = match post_bundle {
78 Some(post_bundle) => {
79 let mut post_bundle = post_bundle.clone();
80 post_bundle.header.time_millis = time_millis;
81 post_bundle.header.overflowed = post_bundle.header.num_posts > config::ENCODED_POST_BUNDLE_V1_OVERFLOWED_NUM_POSTS;
82 post_bundle.header.sealed = bucket_location.is_sealed_at(time_millis, post_bundle.header.overflowed);
83 trace!("Returning stub postbundle: {}", post_bundle);
84 post_bundle
85 }
86 None => {
87 let sealed = bucket_location.is_sealed_at(time_millis, false);
88 let mut post_bundle = EncodedPostBundleV1::stub();
89 post_bundle.header.time_millis = time_millis;
90 post_bundle.header.location_id = bucket_location.location_id;
91 post_bundle.header.sealed = sealed;
92 trace!("Returning phantom postbundle: {}", post_bundle);
93 post_bundle
94 }
95 };
96
97 Ok(post_bundle)
98 }
99}
100
101impl EncodedPostBundleV1 {
102 pub fn stub() -> Self {
103 let header = EncodedPostBundleHeaderV1 {
104 time_millis: TimeMillis::zero(),
105 location_id: Id::zero(),
106 overflowed: false,
107 sealed: false,
108 num_posts: 0,
109 encoded_post_ids: vec![],
110 encoded_post_lengths: vec![],
111 encoded_post_healed: HashSet::new(),
112 peer: Peer::zero(),
113 signature: Signature::zero(),
114 };
115
116 EncodedPostBundleV1 { header, encoded_posts_bytes: Bytes::new() }
117 }
118}