use crate::nat::config::{NatConfig, TurnServerConfig};
pub struct RelayDiscovery {
static_servers: Vec<TurnServerConfig>,
}
impl RelayDiscovery {
#[must_use]
pub fn new(config: &NatConfig) -> Self {
Self {
static_servers: config.turn_servers.clone(),
}
}
#[must_use]
pub fn servers(&self) -> &[TurnServerConfig] {
&self.static_servers
}
pub fn add_server(&mut self, server: TurnServerConfig) {
if !self
.static_servers
.iter()
.any(|s| s.address == server.address)
{
self.static_servers.push(server);
}
}
pub fn remove_server(&mut self, address: &str) {
self.static_servers.retain(|s| s.address != address);
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_config_with_servers(n: usize) -> NatConfig {
let mut config = NatConfig::default();
for i in 0..n {
config.turn_servers.push(TurnServerConfig {
address: format!("relay{i}.example.com:3478"),
username: format!("user{i}"),
credential: format!("cred{i}"),
region: Some(format!("region-{i}")),
});
}
config
}
#[test]
fn test_discovery_new_empty() {
let config = NatConfig::default();
let discovery = RelayDiscovery::new(&config);
assert!(discovery.servers().is_empty());
}
#[test]
fn test_discovery_new_with_servers() {
let config = make_config_with_servers(3);
let discovery = RelayDiscovery::new(&config);
assert_eq!(discovery.servers().len(), 3);
assert_eq!(discovery.servers()[0].address, "relay0.example.com:3478");
assert_eq!(discovery.servers()[2].address, "relay2.example.com:3478");
}
#[test]
fn test_discovery_add_server() {
let config = NatConfig::default();
let mut discovery = RelayDiscovery::new(&config);
discovery.add_server(TurnServerConfig {
address: "new.example.com:3478".to_string(),
username: "user".to_string(),
credential: "cred".to_string(),
region: None,
});
assert_eq!(discovery.servers().len(), 1);
assert_eq!(discovery.servers()[0].address, "new.example.com:3478");
}
#[test]
fn test_discovery_add_server_dedup() {
let config = NatConfig::default();
let mut discovery = RelayDiscovery::new(&config);
let server = TurnServerConfig {
address: "relay.example.com:3478".to_string(),
username: "user".to_string(),
credential: "cred".to_string(),
region: None,
};
discovery.add_server(server.clone());
discovery.add_server(server);
assert_eq!(
discovery.servers().len(),
1,
"Duplicate server should not be added"
);
}
#[test]
fn test_discovery_remove_server() {
let config = make_config_with_servers(3);
let mut discovery = RelayDiscovery::new(&config);
discovery.remove_server("relay1.example.com:3478");
assert_eq!(discovery.servers().len(), 2);
assert_eq!(discovery.servers()[0].address, "relay0.example.com:3478");
assert_eq!(discovery.servers()[1].address, "relay2.example.com:3478");
}
#[test]
fn test_discovery_remove_nonexistent() {
let config = make_config_with_servers(2);
let mut discovery = RelayDiscovery::new(&config);
discovery.remove_server("nonexistent:3478");
assert_eq!(
discovery.servers().len(),
2,
"Removing nonexistent server should be a no-op"
);
}
}