use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::net::{AddrParseError, IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::str::FromStr;
#[derive(Clone, Debug)]
pub enum Address {
Ori(String),
Addr(SocketAddr),
}
impl Address {
pub fn hash_code(&self) -> u64 {
match self {
Address::Ori(ori) => crate::utils::bytes_to_hash_code(ori.as_bytes()),
Address::Addr(addr) => crate::utils::socketaddr_to_hash_code(addr),
}
}
}
impl From<String> for Address {
fn from(ori: String) -> Self {
Address::Ori(ori)
}
}
impl From<&str> for Address {
fn from(ori: &str) -> Self {
Address::Ori(ori.to_string())
}
}
impl From<SocketAddr> for Address {
fn from(addr: SocketAddr) -> Self {
Address::Addr(addr)
}
}
impl<I: Into<IpAddr>> From<(I, u16)> for Address {
fn from(value: (I, u16)) -> Self {
Address::from(SocketAddr::from(value))
}
}
impl From<SocketAddrV4> for Address {
fn from(value: SocketAddrV4) -> Self {
Address::from(SocketAddr::from(value))
}
}
impl From<SocketAddrV6> for Address {
fn from(value: SocketAddrV6) -> Self {
Address::from(SocketAddr::from(value))
}
}
impl FromStr for Address {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let a = SocketAddr::from_str(s)?;
Ok(Address::from(a))
}
}
#[derive(Clone, Debug)]
pub struct BackendState {
hash_code: u64,
valid: bool,
address: Address,
}
impl BackendState {
pub fn new(addr: Address) -> BackendState {
let hash_code = addr.hash_code();
BackendState {
hash_code,
valid: true,
address: addr,
}
}
pub fn hash_code(&self) -> u64 {
self.hash_code
}
pub fn set_valid(&mut self, valid: bool) {
self.valid = valid;
}
pub fn get_valid(&self) -> bool {
self.valid
}
pub fn get_address(&self) -> &Address {
&self.address
}
}
impl Hash for BackendState {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(self.hash_code)
}
}
impl Eq for BackendState {}
impl PartialEq for BackendState {
fn eq(&self, other: &Self) -> bool {
self.hash_code.eq(&other.hash_code)
}
}
impl PartialOrd for BackendState {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.hash_code.partial_cmp(&other.hash_code)
}
}
impl Ord for BackendState {
fn cmp(&self, other: &Self) -> Ordering {
self.hash_code.cmp(&other.hash_code)
}
}
impl From<Address> for BackendState {
fn from(addr: Address) -> Self {
BackendState::new(addr)
}
}
#[derive(Default)]
pub struct BackendStates(Vec<BackendState>);
impl BackendStates {
pub fn new() -> Self {
BackendStates(Vec::new())
}
pub fn contain(&self, hash_code: u64) -> bool {
self.0
.iter()
.find(|bs| bs.hash_code() == hash_code)
.is_some()
}
pub fn add_backend(&mut self, addr: Address) {
let hash_code = addr.hash_code();
if self.0.iter().any(|bs| bs.hash_code == hash_code) {
return;
}
self.0.push(BackendState::new(addr));
self.sort_backends();
}
pub fn remove_backend(&mut self, addr: &Address) -> bool {
let c = self.0.len();
let hash_code = addr.hash_code();
self.0.retain(|bs| bs.hash_code != hash_code);
self.0.len() != c
}
pub fn set_backend_valid(&mut self, addr: &Address, valid: bool) {
if let Some(bs) = self.get_backend_mut(addr) {
bs.valid = valid;
}
}
pub fn get_backend_valid(&self, addr: &Address) -> Option<bool> {
self.get_backend(addr).map(|bs| bs.valid)
}
pub fn get_backend(&self, addr: &Address) -> Option<&BackendState> {
let hash_code = addr.hash_code();
self.0.iter().find(|bs| bs.hash_code == hash_code)
}
pub fn get_backend_mut(&mut self, addr: &Address) -> Option<&mut BackendState> {
let hash_code = addr.hash_code();
self.0.iter_mut().find(|bs| bs.hash_code == hash_code)
}
pub fn get_backends(&self) -> &[BackendState] {
self.0.as_slice()
}
pub fn get_backends_mut(&mut self) -> &mut [BackendState] {
self.0.as_mut_slice()
}
fn sort_backends(&mut self) {
self.0.sort_by(|bs1, bs2| bs1.hash_code.cmp(&bs2.hash_code));
}
}