pub mod auth;
pub mod client;
pub mod device;
pub mod protocol;
pub mod ratelimit;
pub mod server;
pub use device::{load_or_create_device_id, DeviceIdentity};
pub const DEFAULT_RELAY_URL: &str = "https://ilinkhub.ai";
pub fn resolve_pair_public_url(device_id: &str) -> String {
if let Ok(url) = std::env::var("HUB_PAIR_URL").or_else(|_| std::env::var("HUB_PUBLIC_URL")) {
let s = url.trim().trim_end_matches('/').to_string();
if !s.is_empty() {
return s;
}
}
if std::env::var("ILINKHUB_RELAY")
.map(|v| v == "0" || v.eq_ignore_ascii_case("false"))
.unwrap_or(false)
{
return "http://127.0.0.1:8765".to_string();
}
let relay_base =
std::env::var("ILINKHUB_RELAY_URL").unwrap_or_else(|_| DEFAULT_RELAY_URL.to_string());
format!(
"{}/pair/{}",
relay_base.trim().trim_end_matches('/'),
device_id
)
}
pub fn pair_qr_url(public_base: &str, code: &str) -> String {
let legacy = std::env::var("HUB_PAIR_URL").is_ok() || std::env::var("HUB_PUBLIC_URL").is_ok();
if legacy {
format!("{public_base}/hub/pair/{code}")
} else {
format!("{public_base}/{code}")
}
}
pub fn relay_enabled() -> bool {
!std::env::var("ILINKHUB_RELAY")
.map(|v| v == "0" || v.eq_ignore_ascii_case("false"))
.unwrap_or(false)
&& std::env::var("HUB_PAIR_URL").is_err()
&& std::env::var("HUB_PUBLIC_URL").is_err()
}
pub fn relay_ws_url() -> String {
let base =
std::env::var("ILINKHUB_RELAY_URL").unwrap_or_else(|_| DEFAULT_RELAY_URL.to_string());
let base = base.trim().trim_end_matches('/');
if let Some(rest) = base.strip_prefix("https://") {
format!("wss://{rest}/ws/pairing")
} else if let Some(rest) = base.strip_prefix("http://") {
format!("ws://{rest}/ws/pairing")
} else {
format!("wss://{base}/ws/pairing")
}
}
pub fn hub_loopback_addr(listen_addr: &str) -> String {
listen_addr.replacen("0.0.0.0", "127.0.0.1", 1)
}