ckb_network/peer_store/
peer_store_db.rs1use crate::{
2 errors::{Error, PeerStoreError},
3 peer_store::{
4 PeerStore,
5 addr_manager::AddrManager,
6 anchors::Anchors,
7 ban_list::BanList,
8 types::{AddrInfo, BannedAddr},
9 },
10};
11use ckb_logger::{debug, error};
12use p2p::multiaddr::Multiaddr;
13use std::path::Path;
14use std::{
15 fs::{File, OpenOptions, copy, create_dir_all, remove_file, rename},
16 io::{Read, Write},
17};
18
19const DEFAULT_ADDR_MANAGER_DB: &str = "addr_manager.db";
20const DEFAULT_BAN_LIST_DB: &str = "ban_list.db";
21const DEFAULT_ANCHORS_DB: &str = "anchors.db";
22
23impl AddrManager {
24 pub fn load<R: Read>(r: R) -> Result<Self, Error> {
26 let addrs: Vec<AddrInfo> = serde_json::from_reader(r).map_err(PeerStoreError::Serde)?;
27 let mut addr_manager = AddrManager::default();
28 addrs.into_iter().for_each(|addr| addr_manager.add(addr));
29 Ok(addr_manager)
30 }
31
32 pub fn dump(&self, mut file: File) -> Result<(), Error> {
34 let addrs: Vec<_> = self.addrs_iter().collect();
35 debug!("Dump {} addrs", addrs.len());
36 file.set_len(0)
38 .and_then(|_| serde_json::to_string(&addrs).map_err(Into::into))
39 .and_then(|json_string| file.write_all(json_string.as_bytes()))
40 .and_then(|_| file.sync_all())
41 .map_err(Into::into)
42 }
43
44 #[cfg(target_family = "wasm")]
45 pub fn dump_data(&self) -> Vec<u8> {
46 let addrs: Vec<_> = self.addrs_iter().collect();
47 serde_json::to_string(&addrs).unwrap().into_bytes()
48 }
49}
50
51impl BanList {
52 pub fn load<R: Read>(r: R) -> Result<Self, Error> {
54 let banned_addrs: Vec<BannedAddr> =
55 serde_json::from_reader(r).map_err(PeerStoreError::Serde)?;
56 let mut ban_list = BanList::default();
57 banned_addrs
58 .into_iter()
59 .for_each(|banned_addr| ban_list.ban(banned_addr));
60 Ok(ban_list)
61 }
62
63 pub fn dump(&self, mut file: File) -> Result<(), Error> {
65 let banned_addrs = self.get_banned_addrs();
66 debug!("Dump {} banned addrs", banned_addrs.len());
67 file.set_len(0)
69 .and_then(|_| serde_json::to_string(&banned_addrs).map_err(Into::into))
70 .and_then(|json_string| file.write_all(json_string.as_bytes()))
71 .and_then(|_| file.sync_all())
72 .map_err(Into::into)
73 }
74
75 #[cfg(target_family = "wasm")]
76 pub fn dump_data(&self) -> Vec<u8> {
77 let banned_addrs = self.get_banned_addrs();
78 serde_json::to_string(&banned_addrs).unwrap().into_bytes()
79 }
80}
81
82impl Anchors {
83 pub fn load<R: Read>(r: R) -> Result<Self, Error> {
85 let addrs: Vec<Multiaddr> = serde_json::from_reader(r).map_err(PeerStoreError::Serde)?;
86 let mut anchors = Anchors::default();
87 addrs.into_iter().for_each(|addr| anchors.add(addr));
88 Ok(anchors)
89 }
90
91 pub fn dump(&self, mut file: File) -> Result<(), Error> {
93 let addrs: Vec<_> = self.dump_iter().collect();
94 debug!("Anchors dump {} addrs", addrs.len());
95 file.set_len(0)
97 .and_then(|_| serde_json::to_string(&addrs).map_err(Into::into))
98 .and_then(|json_string| file.write_all(json_string.as_bytes()))
99 .and_then(|_| file.sync_all())
100 .map_err(Into::into)
101 }
102
103 #[cfg(target_family = "wasm")]
104 pub fn dump_data(&self) -> Vec<u8> {
105 let addrs: Vec<_> = self.dump_iter().collect();
106 serde_json::to_string(&addrs).unwrap().into_bytes()
107 }
108}
109
110impl PeerStore {
111 pub fn load_from_dir_or_default<P: AsRef<Path>>(path: P) -> Self {
113 let addr_manager_path = path.as_ref().join(DEFAULT_ADDR_MANAGER_DB);
114 let ban_list_path = path.as_ref().join(DEFAULT_BAN_LIST_DB);
115 let anchors_path = path.as_ref().join(DEFAULT_ANCHORS_DB);
116
117 let addr_manager = open_read(&addr_manager_path)
118 .map_err(|err| {
119 debug!(
120 "Failed to open AddrManager db, file: {:?}, error: {:?}",
121 addr_manager_path, err
122 )
123 })
124 .and_then(|reader| {
125 AddrManager::load(reader).map_err(|err| {
126 error!(
127 "Failed to load AddrManager db, file: {:?}, error: {:?}",
128 addr_manager_path, err
129 );
130 })
131 })
132 .unwrap_or_default();
133
134 let ban_list = open_read(&ban_list_path)
135 .map_err(|err| {
136 debug!(
137 "Failed to open BanList db, file: {:?}, error: {:?}",
138 ban_list_path, err
139 )
140 })
141 .and_then(|reader| {
142 BanList::load(reader).map_err(|err| {
143 error!(
144 "Failed to load BanList db, file: {:?}, error: {:?}",
145 ban_list_path, err
146 )
147 })
148 })
149 .unwrap_or_default();
150
151 let anchors = open_read(&anchors_path)
152 .map_err(|err| {
153 debug!(
154 "Failed to open Anchors db, file: {:?}, error: {:?}",
155 anchors_path, err
156 )
157 })
158 .and_then(|reader| {
159 Anchors::load(reader).map_err(|err| {
160 error!(
161 "Failed to load Anchors db, file: {:?}, error: {:?}",
162 anchors_path, err
163 )
164 })
165 })
166 .unwrap_or_default();
167
168 PeerStore::new(addr_manager, ban_list, anchors)
169 }
170
171 #[cfg(target_family = "wasm")]
172 pub async fn load_from_idb<P: AsRef<Path>>(path: P) -> Self {
173 use crate::peer_store::browser::get_db;
174
175 let addr_manager_path = path
176 .as_ref()
177 .join(DEFAULT_ADDR_MANAGER_DB)
178 .to_str()
179 .unwrap()
180 .to_owned()
181 .into_bytes();
182 let ban_list_path = path
183 .as_ref()
184 .join(DEFAULT_BAN_LIST_DB)
185 .to_str()
186 .unwrap()
187 .to_owned()
188 .into_bytes();
189 let anchors_path = path
190 .as_ref()
191 .join(DEFAULT_ANCHORS_DB)
192 .to_str()
193 .unwrap()
194 .to_owned()
195 .into_bytes();
196
197 let db = get_db(path).await;
198
199 let addr_manager = db
200 .get(&addr_manager_path)
201 .await
202 .map_err(|err| debug!("Failed to get indexdb value, error: {:?}", err))
203 .and_then(|data| {
204 AddrManager::load(std::io::Cursor::new(data.unwrap_or_default()))
205 .map_err(|err| debug!("Failed to load peer store value, error: {:?}", err))
206 })
207 .unwrap_or_default();
208
209 let ban_list = db
210 .get(&ban_list_path)
211 .await
212 .map_err(|err| debug!("Failed to get indexdb value, error: {:?}", err))
213 .and_then(|data| {
214 BanList::load(std::io::Cursor::new(data.unwrap_or_default()))
215 .map_err(|err| debug!("Failed to load BanList value, error: {:?}", err))
216 })
217 .unwrap_or_default();
218
219 let anchors = db
220 .get(&anchors_path)
221 .await
222 .map_err(|err| debug!("Failed to get indexdb value, error: {:?}", err))
223 .and_then(|data| {
224 Anchors::load(std::io::Cursor::new(data.unwrap_or_default()))
225 .map_err(|err| debug!("Failed to load Anchors value, error: {:?}", err))
226 })
227 .unwrap_or_default();
228
229 PeerStore::new(addr_manager, ban_list, anchors)
230 }
231
232 pub fn dump_to_dir<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
234 create_dir_all(&path)?;
236 let tmp_dir = path.as_ref().join("tmp");
238 create_dir_all(&tmp_dir)?;
239 let tmp_addr_manager = tmp_dir.join(DEFAULT_ADDR_MANAGER_DB);
240 let tmp_ban_list = tmp_dir.join(DEFAULT_BAN_LIST_DB);
241 let tmp_anchors_list = tmp_dir.join(DEFAULT_ANCHORS_DB);
242 self.addr_manager().dump(dump_open(&tmp_addr_manager)?)?;
243 move_file(
244 tmp_addr_manager,
245 path.as_ref().join(DEFAULT_ADDR_MANAGER_DB),
246 )?;
247 self.ban_list().dump(dump_open(&tmp_ban_list)?)?;
248 move_file(tmp_ban_list, path.as_ref().join(DEFAULT_BAN_LIST_DB))?;
249 self.anchors().dump(dump_open(&tmp_anchors_list)?)?;
250 move_file(tmp_anchors_list, path.as_ref().join(DEFAULT_ANCHORS_DB))?;
251 Ok(())
252 }
253
254 #[cfg(target_family = "wasm")]
255 pub fn dump_to_idb<P: AsRef<Path>>(
256 &self,
257 path: P,
258 ) -> impl std::future::Future<Output = ()> + use<P> {
259 use crate::peer_store::browser::get_db;
260 let ban_list = self.ban_list().dump_data();
261 let addr_manager = self.addr_manager().dump_data();
262 let anchors = self.anchors().dump_data();
263
264 let addr_manager_path = path
265 .as_ref()
266 .join(DEFAULT_ADDR_MANAGER_DB)
267 .to_str()
268 .unwrap()
269 .to_owned();
270 let ban_list_path = path
271 .as_ref()
272 .join(DEFAULT_BAN_LIST_DB)
273 .to_str()
274 .unwrap()
275 .to_owned();
276 let anchors_path = path
277 .as_ref()
278 .join(DEFAULT_ANCHORS_DB)
279 .to_str()
280 .unwrap()
281 .to_owned();
282 async {
283 let db = get_db(path).await;
284
285 let _ignore = db.put(addr_manager_path.into_bytes(), addr_manager).await;
286 let _ignore = db.put(ban_list_path.into_bytes(), ban_list).await;
287 let _ignore = db.put(anchors_path.into_bytes(), anchors).await;
288 }
289 }
290}
291
292fn move_file<P: AsRef<Path>>(src: P, dst: P) -> Result<(), Error> {
295 if rename(&src, &dst).is_err() {
296 copy(&src, &dst)?;
297 remove_file(&src)?;
298 }
299 Ok(())
300}
301
302fn open_read<P: AsRef<Path>>(path: P) -> std::io::Result<std::io::BufReader<File>> {
303 File::open(path.as_ref()).map(std::io::BufReader::new)
304}
305
306fn dump_open<P: AsRef<Path>>(path: P) -> std::io::Result<File> {
307 OpenOptions::new()
308 .write(true)
309 .create(true)
310 .truncate(true)
311 .append(false)
312 .open(path.as_ref())
313}