1use sha2::{Digest, Sha256};
2use petname::Generator;
3
4const TOPIC_PREFIX: &str = "libp2p-gossipsub-manager:v1:";
5
6pub fn hash_topic(room_name: &str) -> String {
7 let input = format!("{}{}", TOPIC_PREFIX, room_name);
8 let mut hasher = Sha256::new();
9 hasher.update(input.as_bytes());
10 let result = hasher.finalize();
11 hex::encode(result)
12}
13
14pub fn generate_random_nickname() -> String {
15 use petname::Petnames;
16 let petnames = Petnames::default();
17 petnames.generate_one(2, "-").unwrap_or_else(|| "unknown-user".into())
18}
19
20#[cfg(test)]
21mod tests {
22 use super::*;
23
24 #[test]
25 fn hash_topic_returns_64_char_hex() {
26 let result = hash_topic("test-room");
27 assert!(result.chars().all(|c| c.is_ascii_hexdigit()));
28 assert_eq!(result.len(), 64);
29 assert_eq!(result, result.to_lowercase());
30 }
31
32 #[test]
33 fn hash_topic_is_deterministic() {
34 let r1 = hash_topic("my-room");
35 let r2 = hash_topic("my-room");
36 assert_eq!(r1, r2);
37 }
38
39 #[test]
40 fn hash_topic_differs_for_different_rooms() {
41 let r1 = hash_topic("room-a");
42 let r2 = hash_topic("room-b");
43 assert_ne!(r1, r2);
44 }
45
46 #[test]
47 fn hash_topic_uses_v1_prefix() {
48 let v1 = hash_topic("foo");
49 let v3_legacy = {
50 let input = format!("libp2p-chat-topic:v3:{}", "foo");
51 let mut hasher = Sha256::new();
52 hasher.update(input.as_bytes());
53 let result = hasher.finalize();
54 hex::encode(result)
55 };
56 assert_ne!(v1, v3_legacy);
57 }
58
59 #[test]
60 fn generate_random_nickname_is_non_empty() {
61 let name = generate_random_nickname();
62 assert!(!name.is_empty());
63 }
64
65 #[test]
66 fn generate_random_nickname_is_hyphenated_lowercase() {
67 let name = generate_random_nickname();
68 assert!(name.chars().all(|c| c.is_ascii_lowercase() || c == '-'));
69 assert!(name.contains('-'));
70 }
71
72 #[test]
73 fn generate_random_nickname_returns_different_names() {
74 let name1 = generate_random_nickname();
75 let name2 = generate_random_nickname();
76 assert_ne!(name1, name2);
77 }
78}