use std::collections::HashMap;
use std::sync::Arc;
use once_cell::sync::Lazy;
use std::time::Duration;
use tokio::sync::RwLock;
use tokio::time::sleep;
use std::sync::atomic::{AtomicUsize, Ordering};
use crate::client::CLIENT;
use crate::result::Error::CustomError;
use crate::result::Result;
pub type ServiceName = String;
pub static SERVICE_ADDRESSES: Lazy<Arc<RwLock<HashMap<ServiceName, (Vec<String>, AtomicUsize)>>>> = Lazy::new(||{
tokio::spawn(get_list());
Arc::new(RwLock::new(HashMap::new()))
});
async fn get_list() -> Result<()> {
let flag = true;
while flag {
let services;
let mut ins_list;
{
let read = CLIENT.read().await;
services = read.get_service_list(1, 1000).service_list().await?;
ins_list = read.get_instance_list("", true);
}
let mut map = HashMap::new();
let mut flag = false;
for service_name in services.doms {
ins_list.serviceName = service_name.to_owned();
let ins = ins_list.instance_list().await.expect("instance_list error");
let mut hosts = vec![];
for i in ins.hosts {
let host = format!("{}:{}", i.ip, i.port);
hosts.push(host);
}
if !flag {
if let Some((data, _index)) = SERVICE_ADDRESSES.read().await.get(&service_name) {
if data.len() != hosts.len() {
flag = true;
} else {
for host in data {
if !hosts.contains(&host) {
flag = true;
}
}
}
} else {
flag = true;
}
}
map.insert(service_name, (hosts, AtomicUsize::new(0)));
}
if flag{
let mut w = SERVICE_ADDRESSES.write().await;
*w = map;
}
sleep(Duration::from_secs(CLIENT.read().await.client_beat_interval)).await;
};
Ok(())
}
pub async fn get_address(service_name: &str) -> Result<String> {
if let Some((data, index)) = SERVICE_ADDRESSES.read().await.get(service_name) {
let idx = index.load(Ordering::Relaxed);
let length = data.len();
if length > 1 {
let cur_idx = idx + 1;
if cur_idx < length - 1 {
index.store(idx + 1, Ordering::Relaxed);
} else {
index.store(0, Ordering::Relaxed);
}
}
let addr = data.get(idx).unwrap().to_string();
return Ok(addr)
}
Err(CustomError("not found address".to_string()))
}