use super::client_registry::{ALL_KNOWN_CLIENT_PROTOCOLS, CLIENT_REGISTRY};
use super::server_registry::ALL_KNOWN_PROTOCOLS;
const SERVER_TO_CLIENT_ALIASES: &[(&str, &str)] = &[
("DoH", "DNS-over-HTTPS"),
("Proxy", "HTTP Proxy"),
("Tor Relay", "Tor"),
("OpenID", "OpenIDConnect"),
("SamlIdp", "SAML"),
("SamlSp", "SAML"),
("WebRTC Signaling", "WebRTC"),
("Torrent-Tracker", "BitTorrent Tracker"),
("Torrent-DHT", "BitTorrent DHT"),
("Torrent-Peer", "BitTorrent Peer Wire"),
];
fn normalize(name: &str) -> String {
name.chars()
.filter(|c| c.is_ascii_alphanumeric())
.collect::<String>()
.to_ascii_lowercase()
}
pub fn client_protocol_for_server(server_name: &str) -> Option<&'static str> {
if let Some((_, client)) = SERVER_TO_CLIENT_ALIASES
.iter()
.find(|(server, _)| server.eq_ignore_ascii_case(server_name))
{
return Some(client);
}
let wanted = normalize(server_name);
ALL_KNOWN_CLIENT_PROTOCOLS
.iter()
.map(|(name, _feature)| *name)
.find(|name| normalize(name) == wanted)
}
pub fn compiled_client_protocol_for_server(server_name: &str) -> Option<String> {
let wanted = normalize(server_name);
let known_canonical = ALL_KNOWN_PROTOCOLS
.iter()
.map(|(name, _)| *name)
.find(|name| normalize(name) == wanted);
let canonical = known_canonical.or_else(|| {
super::server_registry::registry()
.resolve(server_name)
.ok()
.map(|server| server.protocol_name())
});
let client_name = client_protocol_for_server(canonical.unwrap_or(server_name))?;
CLIENT_REGISTRY
.get(client_name)
.map(|_| client_name.to_string())
}
pub fn all_dual_protocols() -> Vec<(&'static str, &'static str)> {
ALL_KNOWN_PROTOCOLS
.iter()
.filter_map(|(server, _feature)| {
client_protocol_for_server(server).map(|client| (*server, client))
})
.collect()
}
pub fn alias_table_problems() -> Vec<String> {
let mut problems = Vec::new();
for (server, client) in SERVER_TO_CLIENT_ALIASES {
if !ALL_KNOWN_PROTOCOLS.iter().any(|(name, _)| name == server) {
problems.push(format!(
"alias server side {server:?} is not in ALL_KNOWN_PROTOCOLS"
));
}
if !ALL_KNOWN_CLIENT_PROTOCOLS
.iter()
.any(|(name, _)| name == client)
{
problems.push(format!(
"alias client side {client:?} is not in ALL_KNOWN_CLIENT_PROTOCOLS"
));
}
if normalize(server) == normalize(client) {
problems.push(format!(
"alias {server:?} -> {client:?} is redundant: normalization already matches them"
));
}
}
problems
}