Rust · 4523 bytes Raw Blame History
1 use anyhow::Result;
2 use libp2p::{
3 identify, mdns, ping,
4 swarm::NetworkBehaviour,
5 identity,
6 PeerId,
7 };
8 use tracing::info;
9
10 use crate::config::Config;
11
12 /// ZephyrBehaviour combines multiple LibP2P behaviours for secure P2P networking
13 ///
14 /// Safety: All behaviours are configured with security-first defaults
15 /// Privacy: mDNS can be disabled for privacy-sensitive deployments
16 /// Transparency: All behaviour events are exposed for logging and monitoring
17 #[derive(NetworkBehaviour)]
18 pub struct ZephyrBehaviour {
19 /// Ping for basic connectivity testing and RTT measurement
20 pub ping: ping::Behaviour,
21
22 /// Identify for peer capability discovery
23 pub identify: identify::Behaviour,
24
25 /// mDNS for local network discovery
26 pub mdns: mdns::tokio::Behaviour,
27 }
28
29 impl ZephyrBehaviour {
30 /// Create a new ZephyrBehaviour with security-focused configuration
31 ///
32 /// Safety: All protocols use secure defaults
33 /// Privacy: mDNS respects privacy configuration
34 pub async fn new(config: &Config, local_peer_id: PeerId, local_key: &identity::Keypair) -> Result<Self> {
35 info!("Initializing ZephyrBehaviour for peer: {}", local_peer_id);
36
37 // Configure ping behaviour for connection health monitoring
38 let ping = ping::Behaviour::new(
39 ping::Config::new().with_interval(std::time::Duration::from_secs(30))
40 );
41
42 // Configure identify behaviour for peer capability discovery
43 // Safety: Only expose necessary information, no sensitive data
44 let identify = identify::Behaviour::new(
45 identify::Config::new("zephyrfs/1.0.0".into(), local_key.public())
46 .with_agent_version("zephyrfs-node/0.1.0".into())
47 .with_push_listen_addr_updates(true)
48 .with_interval(std::time::Duration::from_secs(300)) // 5 minutes
49 );
50
51 // Configure mDNS for local discovery (can be disabled for privacy)
52 let mdns = if config.network.enable_mdns {
53 info!("Enabling mDNS for local peer discovery");
54 mdns::tokio::Behaviour::new(
55 mdns::Config::default(),
56 local_peer_id,
57 )?
58 } else {
59 info!("mDNS disabled for privacy");
60 mdns::tokio::Behaviour::new(
61 mdns::Config::default(),
62 local_peer_id,
63 )?
64 };
65
66 Ok(Self {
67 ping,
68 identify,
69 mdns,
70 })
71 }
72 }
73
74 #[cfg(test)]
75 mod tests {
76 use super::*;
77 use crate::config::{Config, NetworkConfig};
78 use libp2p::identity;
79
80 #[tokio::test]
81 async fn test_behaviour_creation() {
82 let config = Config::default();
83 let keypair = identity::Keypair::generate_ed25519();
84 let peer_id = PeerId::from(keypair.public());
85
86 let behaviour = ZephyrBehaviour::new(&config, peer_id, &keypair).await;
87 assert!(behaviour.is_ok(), "Should create behaviour successfully");
88 }
89
90 #[tokio::test]
91 async fn test_behaviour_with_mdns_disabled() {
92 let mut config = Config::default();
93 config.network.enable_mdns = false;
94
95 let keypair = identity::Keypair::generate_ed25519();
96 let peer_id = PeerId::from(keypair.public());
97
98 let behaviour = ZephyrBehaviour::new(&config, peer_id, &keypair).await;
99 assert!(behaviour.is_ok(), "Should create behaviour with mDNS disabled");
100 }
101
102 #[tokio::test]
103 async fn test_behaviour_has_required_components() {
104 // This test ensures our behaviour struct has all required fields
105 let keypair = identity::Keypair::generate_ed25519();
106 let peer_id = PeerId::from(keypair.public());
107
108 // Create minimal components for testing
109 let ping = ping::Behaviour::new(ping::Config::new());
110 let identify = identify::Behaviour::new(
111 identify::Config::new("test/1.0.0".into(), keypair.public())
112 );
113
114 // This will fail to compile if we're missing required fields
115 let mdns = mdns::tokio::Behaviour::new(
116 mdns::Config::default(),
117 peer_id,
118 ).expect("mDNS creation should succeed in tests");
119
120 let _behaviour = ZephyrBehaviour {
121 ping,
122 identify,
123 mdns,
124 };
125
126 // If we get here, the struct is properly formed
127 assert!(true, "Behaviour struct is properly formed");
128 }
129 }