chie_shared/utils/
network.rs1#[must_use]
30pub fn extract_peer_id_from_multiaddr(multiaddr: &str) -> Option<String> {
31 multiaddr
32 .split('/')
33 .skip_while(|&s| s != "p2p" && s != "ipfs")
34 .nth(1)
35 .map(ToString::to_string)
36}
37
38#[must_use]
41pub fn is_valid_peer_id_format(peer_id: &str) -> bool {
42 if peer_id.is_empty() {
43 return false;
44 }
45
46 let valid_prefix = peer_id.starts_with("Qm") || peer_id.starts_with("12D3") || peer_id.starts_with("bafz"); let valid_length = (30..=100).contains(&peer_id.len());
53
54 valid_prefix && valid_length && peer_id.chars().all(|c| c.is_alphanumeric())
55}
56
57pub fn parse_bandwidth_str(s: &str) -> Option<u64> {
78 let s = s.trim().to_lowercase();
79 let parts: Vec<&str> = s.split_whitespace().collect();
80
81 if parts.len() != 2 {
82 return None;
83 }
84
85 let value: f64 = parts[0].parse().ok()?;
86 let multiplier = match parts[1] {
87 "bps" => 1.0,
88 "kbps" => 1_000.0,
89 "mbps" => 1_000_000.0,
90 "gbps" => 1_000_000_000.0,
91 _ => return None,
92 };
93
94 Some((value * multiplier) as u64)
95}
96
97pub fn generate_session_id() -> String {
99 uuid::Uuid::new_v4().to_string()
100}
101
102pub fn chunk_vec<T: Clone>(items: &[T], chunk_size: usize) -> Vec<Vec<T>> {
105 if chunk_size == 0 {
106 return vec![];
107 }
108
109 items
110 .chunks(chunk_size)
111 .map(|chunk| chunk.to_vec())
112 .collect()
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_extract_peer_id_from_multiaddr() {
121 assert_eq!(
122 extract_peer_id_from_multiaddr("/ip4/127.0.0.1/tcp/4001/p2p/QmPeerId"),
123 Some("QmPeerId".to_string())
124 );
125 assert_eq!(
126 extract_peer_id_from_multiaddr("/ip4/192.168.1.1/tcp/4001/ipfs/QmTest123"),
127 Some("QmTest123".to_string())
128 );
129 assert_eq!(
130 extract_peer_id_from_multiaddr("/ip4/127.0.0.1/tcp/4001"),
131 None
132 );
133 assert_eq!(
134 extract_peer_id_from_multiaddr("/p2p/QmSimple"),
135 Some("QmSimple".to_string())
136 );
137 }
138
139 #[test]
140 fn test_is_valid_peer_id_format() {
141 assert!(is_valid_peer_id_format(
143 "QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5N"
144 ));
145
146 assert!(is_valid_peer_id_format(
148 "12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN"
149 ));
150
151 assert!(is_valid_peer_id_format(
153 "bafzbeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"
154 ));
155
156 assert!(!is_valid_peer_id_format(
158 "Xm1234567890123456789012345678901234567890"
159 ));
160
161 assert!(!is_valid_peer_id_format("QmShort"));
163
164 assert!(!is_valid_peer_id_format(""));
166
167 assert!(!is_valid_peer_id_format(
169 "Qm12345678901234567890123456789012345678-invalid"
170 ));
171 }
172
173 #[test]
174 fn test_parse_bandwidth_str() {
175 assert_eq!(parse_bandwidth_str("100 bps"), Some(100));
176 assert_eq!(parse_bandwidth_str("10 Kbps"), Some(10_000));
177 assert_eq!(parse_bandwidth_str("100 Mbps"), Some(100_000_000));
178 assert_eq!(parse_bandwidth_str("1 Gbps"), Some(1_000_000_000));
179 assert_eq!(parse_bandwidth_str("invalid"), None);
180 assert_eq!(parse_bandwidth_str("100"), None);
181 }
182
183 #[test]
184 fn test_generate_session_id() {
185 let id1 = generate_session_id();
186 let id2 = generate_session_id();
187 assert_ne!(id1, id2);
188 assert!(uuid::Uuid::parse_str(&id1).is_ok());
189 }
190
191 #[test]
192 fn test_chunk_vec() {
193 let items = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
194 let chunks = chunk_vec(&items, 3);
195 assert_eq!(chunks.len(), 3);
196 assert_eq!(chunks[0], vec![1, 2, 3]);
197 assert_eq!(chunks[1], vec![4, 5, 6]);
198 assert_eq!(chunks[2], vec![7, 8, 9]);
199
200 let chunks = chunk_vec(&items, 4);
201 assert_eq!(chunks.len(), 3);
202 assert_eq!(chunks[0], vec![1, 2, 3, 4]);
203 assert_eq!(chunks[1], vec![5, 6, 7, 8]);
204 assert_eq!(chunks[2], vec![9]);
205
206 let chunks = chunk_vec(&items, 0);
207 assert_eq!(chunks.len(), 0);
208
209 let empty: Vec<i32> = vec![];
210 let chunks = chunk_vec(&empty, 3);
211 assert_eq!(chunks.len(), 0);
212 }
213}