#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Endpoints {
pub ping: String,
pub download: String,
pub upload: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Server {
pub name: String,
pub description: String,
pub endpoints: Endpoints,
}
impl Server {
#[must_use]
pub fn from_base(
name: impl Into<String>,
base_url: &str,
download_path: &str,
upload_path: &str,
ping_path: &str,
) -> Self {
let base = normalize_base(base_url);
let description = host_of(&base);
Self {
name: name.into(),
description,
endpoints: Endpoints {
ping: join(&base, ping_path),
download: join(&base, download_path),
upload: join(&base, upload_path),
},
}
}
#[must_use]
pub fn matches(&self, query: &str) -> bool {
let query = query.to_lowercase();
self.name.to_lowercase().contains(&query)
|| self.description.to_lowercase().contains(&query)
}
}
fn normalize_base(base: &str) -> String {
let trimmed = base.trim();
let with_scheme = if let Some(rest) = trimmed.strip_prefix("//") {
format!("https://{rest}")
} else if trimmed.starts_with("http://") || trimmed.starts_with("https://") {
trimmed.to_owned()
} else {
format!("https://{trimmed}")
};
if with_scheme.ends_with('/') {
with_scheme
} else {
format!("{with_scheme}/")
}
}
fn join(base: &str, path: &str) -> String {
format!("{base}{}", path.trim_start_matches('/'))
}
fn host_of(url: &str) -> String {
let without_scheme = url
.strip_prefix("https://")
.or_else(|| url.strip_prefix("http://"))
.unwrap_or(url);
without_scheme
.split('/')
.next()
.unwrap_or(without_scheme)
.to_owned()
}