ant_bootstrap/cache_store/
cache_data_v0.rs1use std::{
10 fs::{self, OpenOptions},
11 io::{Read, Write},
12 path::{Path, PathBuf},
13 time::SystemTime,
14};
15
16use atomic_write_file::AtomicWriteFile;
17use libp2p::{Multiaddr, PeerId};
18use serde::{Deserialize, Serialize};
19
20use crate::Error;
21
22use super::cache_data_v1;
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct BootstrapAddr {
27 pub addr: Multiaddr,
29 pub success_count: u32,
31 pub failure_count: u32,
33 pub last_seen: SystemTime,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct BootstrapAddresses(pub Vec<BootstrapAddr>);
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct CacheData {
43 pub peers: std::collections::HashMap<PeerId, BootstrapAddresses>,
44 pub last_updated: SystemTime,
45 pub network_version: String,
46}
47
48impl From<&cache_data_v1::CacheData> for CacheData {
49 fn from(data: &cache_data_v1::CacheData) -> Self {
50 let mut peers = std::collections::HashMap::new();
51 for (peer_id, addrs) in &data.peers {
52 let addrs = addrs
53 .iter()
54 .map(|addr| BootstrapAddr {
55 addr: addr.clone(),
56 success_count: 0,
57 failure_count: 0,
58 last_seen: SystemTime::now(),
59 })
60 .collect();
61 peers.insert(*peer_id, BootstrapAddresses(addrs));
62 }
63
64 Self {
65 peers,
66 last_updated: data.last_updated,
67 network_version: data.network_version.clone(),
68 }
69 }
70}
71
72impl From<CacheData> for cache_data_v1::CacheData {
73 fn from(val: CacheData) -> Self {
74 let peers = val
75 .peers
76 .into_iter()
77 .map(|(peer_id, addrs)| {
78 let addrs = addrs.0.into_iter().map(|addr| addr.addr).collect();
79 (peer_id, addrs)
80 })
81 .collect();
82
83 cache_data_v1::CacheData {
84 peers,
85 last_updated: val.last_updated,
86 network_version: val.network_version,
87 cache_version: cache_data_v1::CacheData::CACHE_DATA_VERSION.to_string(),
88 }
89 }
90}
91
92impl CacheData {
93 pub fn read_from_file(cache_dir: &Path, file_name: &str) -> Result<Self, Error> {
94 let file_path = Self::cache_file_path(cache_dir, file_name);
95 let mut file = OpenOptions::new()
97 .read(true)
98 .open(&file_path)
99 .inspect_err(|err| warn!("Failed to open cache file at {file_path:?} : {err}",))?;
100
101 let mut contents = String::new();
103 file.read_to_string(&mut contents).inspect_err(|err| {
104 warn!("Failed to read cache file: {err}");
105 })?;
106
107 let data = serde_json::from_str::<Self>(&contents).map_err(|err| {
109 warn!("Failed to parse cache data: {err}");
110 Error::FailedToParseCacheData
111 })?;
112
113 Ok(data)
114 }
115
116 pub fn write_to_file(&self, cache_dir: &Path, file_name: &str) -> Result<(), Error> {
117 let file_path = Self::cache_file_path(cache_dir, file_name);
118
119 if let Some(parent) = file_path.parent() {
121 fs::create_dir_all(parent)?;
122 }
123
124 let mut file = AtomicWriteFile::options()
125 .open(&file_path)
126 .inspect_err(|err| {
127 error!("Failed to open cache file at {file_path:?} using AtomicWriteFile: {err}");
128 })?;
129
130 let data = serde_json::to_string_pretty(&self).inspect_err(|err| {
131 error!("Failed to serialize cache data: {err}");
132 })?;
133 writeln!(file, "{data}")?;
134 file.commit().inspect_err(|err| {
135 error!("Failed to commit atomic write: {err}");
136 })?;
137
138 info!("Cache written to disk: {:?}", file_path);
139
140 Ok(())
141 }
142
143 pub fn cache_file_path(cache_dir: &Path, file_name: &str) -> PathBuf {
144 cache_dir.join(file_name)
145 }
146}