interstice_core/persistence/
peer_tokens.rs1use crate::error::IntersticeError;
2use crate::node::NodeId;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::path::{Path, PathBuf};
6use uuid::Uuid;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9struct PeerTokenFile {
10 local_token: String,
11 peers: HashMap<String, String>,
12}
13
14pub struct PeerTokenStore {
15 path: Option<PathBuf>,
16 local_token: String,
17 peers: HashMap<String, String>,
18}
19
20impl PeerTokenStore {
21 pub fn load_or_create<P: AsRef<Path>>(path: P) -> Result<Self, IntersticeError> {
22 let path = path.as_ref().to_path_buf();
23 if path.exists() {
24 let contents = std::fs::read_to_string(&path).map_err(|err| {
25 IntersticeError::Internal(format!(
26 "Failed to read peer token store {}: {err}",
27 path.display()
28 ))
29 })?;
30 let file: PeerTokenFile = if contents.trim().is_empty() {
31 PeerTokenFile {
32 local_token: Self::generate_token(),
33 peers: HashMap::new(),
34 }
35 } else {
36 toml::from_str(&contents).map_err(|err| {
37 IntersticeError::Internal(format!(
38 "Failed to parse peer token store {}: {err}",
39 path.display()
40 ))
41 })?
42 };
43 let loaded_local_token = file.local_token.clone();
44 let mut store = Self {
45 path: Some(path),
46 local_token: file.local_token,
47 peers: file.peers,
48 };
49 if store.local_token.trim().is_empty() {
50 store.local_token = Self::generate_token();
51 }
52 if contents.trim().is_empty() || store.local_token != loaded_local_token {
53 store.save()?;
54 }
55 Ok(store)
56 } else {
57 let store = Self {
58 path: Some(path),
59 local_token: Self::generate_token(),
60 peers: HashMap::new(),
61 };
62 store.save()?;
63 Ok(store)
64 }
65 }
66
67 pub fn new_in_memory() -> Self {
68 Self {
69 path: None,
70 local_token: Self::generate_token(),
71 peers: HashMap::new(),
72 }
73 }
74
75 pub fn local_token(&self) -> String {
76 self.local_token.clone()
77 }
78
79 pub fn get_peer_token(&self, peer_id: &NodeId) -> Option<String> {
80 self.peers.get(&peer_id.to_string()).cloned()
81 }
82
83 pub fn set_peer_token(
84 &mut self,
85 peer_id: &NodeId,
86 token: String,
87 ) -> Result<(), IntersticeError> {
88 self.peers.insert(peer_id.to_string(), token);
89 self.save()
90 }
91
92 pub fn save(&self) -> Result<(), IntersticeError> {
93 let Some(path) = &self.path else {
94 return Ok(());
95 };
96 let file = PeerTokenFile {
97 local_token: self.local_token.clone(),
98 peers: self.peers.clone(),
99 };
100 let contents = toml::to_string_pretty(&file).map_err(|err| {
101 IntersticeError::Internal(format!("Failed to serialize peer token store: {err}"))
102 })?;
103 std::fs::write(path, contents).map_err(|err| {
104 IntersticeError::Internal(format!(
105 "Failed to write peer token store {}: {err}",
106 path.display()
107 ))
108 })?;
109 Ok(())
110 }
111
112 fn generate_token() -> String {
113 Uuid::new_v4().to_string()
114 }
115}