use std::{net::SocketAddr, time::Duration};
use rand::Rng;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use serde_with::DurationSeconds;
use crate::HealthCheck;
fn default_weight() -> u16 {
100
}
fn fail_timeout() -> Duration {
Duration::from_secs(30)
}
fn default_fall_times() -> usize {
2
}
fn default_rise_times() -> usize {
2
}
#[serde_as]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SingleStreamConfig {
pub addr: SocketAddr,
#[serde(default = "default_weight")]
pub weight: u16,
#[serde_as(as = "DurationSeconds<u64>")]
#[serde(default = "fail_timeout")]
fail_timeout: Duration,
#[serde(default = "default_fall_times")]
fall_times: usize,
#[serde(default = "default_rise_times")]
rise_times: usize,
#[serde(skip)]
pub status: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpstreamConfig {
pub name: String,
#[serde(default = "String::new")]
pub bind: String,
#[serde(default = "Vec::new")]
pub server: Vec<SingleStreamConfig>,
}
impl UpstreamConfig {
pub fn new_single(name: String, to: SocketAddr) -> Self {
Self {
name,
bind: String::new(),
server: vec![SingleStreamConfig::new_simple(to)],
}
}
pub fn get_server_addr(&self) -> Option<SocketAddr> {
if self.server.is_empty() {
return None;
}
let (sum, sum_all) = self.calc_sum_weight();
let mut rng = rand::thread_rng();
if sum != 0 {
let mut random_weight = rng.gen_range(0..sum);
for server in &self.server {
if !HealthCheck::check_fall_down(
&server.addr,
&server.fail_timeout,
&server.fall_times,
&server.rise_times,
) {
if random_weight <= server.weight {
return Some(server.addr.clone());
}
random_weight -= server.weight;
}
}
} else {
let mut random_weight = rng.gen_range(0..sum_all);
for server in &self.server {
if random_weight <= server.weight {
return Some(server.addr.clone());
}
random_weight -= server.weight;
}
}
return None;
}
pub fn calc_sum_weight(&self) -> (u16, u16) {
let mut sum = 0;
let mut sum_all = 0;
for server in &self.server {
if !HealthCheck::is_fall_down(&server.addr) {
sum += server.weight;
}
sum_all += server.weight;
}
return (sum, sum_all);
}
}
impl SingleStreamConfig {
pub fn new_simple(addr: SocketAddr) -> Self {
Self {
addr,
weight: 100,
fail_timeout: Duration::from_secs(60),
fall_times: 3,
rise_times: 2,
status: None,
}
}
}