use std::collections::HashMap;
use std::sync::Arc;
use cheetah_string::CheetahString;
use tracing::error;
use tracing::warn;
use crate::common::namesrv::name_server_update_callback::NameServerUpdateCallback;
use crate::common::namesrv::top_addressing::TopAddressing;
use crate::utils::http_tiny_client::HttpTinyClient;
pub struct DefaultTopAddressing {
ns_addr: Option<CheetahString>,
ws_addr: CheetahString,
unit_name: Option<CheetahString>,
para: Option<HashMap<CheetahString, CheetahString>>,
top_addressing_list: Vec<Arc<dyn TopAddressing>>,
}
impl DefaultTopAddressing {
pub fn new(ws_addr: CheetahString, unit_name: Option<CheetahString>) -> Self {
let top_addressing_list = Self::load_custom_top_addressing();
DefaultTopAddressing {
ns_addr: None,
ws_addr,
unit_name,
para: None,
top_addressing_list,
}
}
fn load_custom_top_addressing() -> Vec<Arc<dyn TopAddressing>> {
Vec::new()
}
fn clear_new_line(input: &str) -> String {
let trimmed = input.trim();
if let Some(index) = trimmed.find('\r') {
return trimmed[..index].to_string();
}
if let Some(index) = trimmed.find('\n') {
return trimmed[..index].to_string();
}
trimmed.to_string()
}
fn build_url(&self) -> String {
let mut url = self.ws_addr.clone().to_string();
if let Some(ref para) = self.para {
if !para.is_empty() {
if let Some(ref unit_name) = self.unit_name {
if !unit_name.is_empty() {
url.push_str(&format!("-{unit_name}?nofix=1&"));
}
} else {
url.push('?');
}
let mut query_params = Vec::new();
for (key, value) in para {
query_params.push(format!("{key}={value}"));
}
url.push_str(&query_params.join("&"));
}
} else if let Some(ref unit_name) = self.unit_name {
if !unit_name.is_empty() {
url.push_str(&format!("-{unit_name}?nofix=1"));
}
}
url
}
pub async fn fetch_ns_addr_inner_async(&self, verbose: bool, timeout_millis: u64) -> Option<String> {
let url = self.build_url();
match HttpTinyClient::http_get_async(&url, None, None, "UTF-8", timeout_millis).await {
Ok(response) => {
if response.code == 200 {
if !response.content.is_empty() {
return Some(Self::clear_new_line(&response.content));
} else {
error!("fetch nameserver address is null");
}
} else {
error!("fetch nameserver address failed. statusCode={}", response.code);
}
}
Err(e) => {
if verbose {
error!("fetch name remoting_server address exception: {}", e);
}
}
}
if verbose {
warn!(
"connect to {} failed, maybe the domain name not bind in /etc/hosts",
url
);
}
None
}
#[deprecated(
since = "0.8.0",
note = "Use fetch_ns_addr_inner_async() instead for better async performance"
)]
pub fn fetch_ns_addr_inner(&self, verbose: bool, timeout_millis: u64) -> Option<String> {
#[allow(deprecated)]
match HttpTinyClient::http_get(&self.build_url(), None, None, "UTF-8", timeout_millis) {
Ok(response) => {
if response.code == 200 {
if !response.content.is_empty() {
return Some(Self::clear_new_line(&response.content));
} else {
error!("fetch nameserver address is null");
}
} else {
error!("fetch nameserver address failed. statusCode={}", response.code);
}
}
Err(e) => {
if verbose {
error!("fetch name remoting_server address exception: {}", e);
}
}
}
if verbose {
warn!(
"connect to {} failed, maybe the domain name not bind in /etc/hosts",
self.build_url()
);
}
None
}
}
impl TopAddressing for DefaultTopAddressing {
fn fetch_ns_addr(&self) -> Option<String> {
for top_addressing in &self.top_addressing_list {
if let Some(ns_address) = top_addressing.fetch_ns_addr() {
if !ns_address.trim().is_empty() {
return Some(ns_address);
}
}
}
#[allow(deprecated)]
self.fetch_ns_addr_inner(true, 3000)
}
fn register_change_callback(&self, change_callback: Arc<dyn NameServerUpdateCallback>) {
for top_addressing in &self.top_addressing_list {
top_addressing.register_change_callback(change_callback.clone());
}
}
}