use std::fs;
use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize};
use tokio::task::{spawn_blocking, JoinHandle};
use cuprate_p2p_core::{services::ZoneSpecificPeerListEntryBase, NetZoneAddress, NetworkZone};
use crate::{peer_list::PeerList, AddressBookConfig};
// TODO: store anchor and ban list.
#[derive(BorshSerialize)]
struct SerPeerDataV1<'a, A: NetZoneAddress> {
white_list: Vec<&'a ZoneSpecificPeerListEntryBase>,
gray_list: Vec<&'a ZoneSpecificPeerListEntryBase>,
}
#[derive(BorshDeserialize)]
struct DeserPeerDataV1 {
white_list: Vec>,
gray_list: Vec>,
}
pub fn save_peers_to_disk(
cfg: &AddressBookConfig,
white_list: &PeerList,
gray_list: &PeerList,
) -> JoinHandle> {
// maybe move this to another thread but that would require cloning the data ... this
// happens so infrequently that it's probably not worth it.
let data = to_vec(&SerPeerDataV1 {
white_list: white_list.peers.values().collect::>(),
gray_list: gray_list.peers.values().collect::>(),
})
.unwrap();
let file = cfg.peer_store_file.clone();
spawn_blocking(move || fs::write(&file, &data))
}
pub async fn read_peers_from_disk(
cfg: &AddressBookConfig,
) -> Result<
(
Vec>,
Vec>,
),
std::io::Error,
> {
let file = cfg.peer_store_file.clone();
let data = spawn_blocking(move || fs::read(file)).await.unwrap()?;
let de_ser: DeserPeerDataV1 = from_slice(&data)?;
Ok((de_ser.white_list, de_ser.gray_list))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::peer_list::{tests::make_fake_peer_list, PeerList};
use cuprate_test_utils::test_netzone::{TestNetZone, TestNetZoneAddr};
#[test]
fn ser_deser_peer_list() {
let white_list = make_fake_peer_list(0, 50);
let gray_list = make_fake_peer_list(50, 100);
let data = to_vec(&SerPeerDataV1 {
white_list: white_list.peers.values().collect::>(),
gray_list: gray_list.peers.values().collect::>(),
})
.unwrap();
let de_ser: DeserPeerDataV1 = from_slice(&data).unwrap();
let white_list_2: PeerList> =
PeerList::new(de_ser.white_list);
let gray_list_2: PeerList> = PeerList::new(de_ser.gray_list);
assert_eq!(white_list.peers.len(), white_list_2.peers.len());
assert_eq!(gray_list.peers.len(), gray_list_2.peers.len());
for addr in white_list.peers.keys() {
assert!(white_list_2.contains_peer(addr));
}
for addr in gray_list.peers.keys() {
assert!(gray_list_2.contains_peer(addr));
}
}
}