use core::{net::IpAddr, time::Duration};
use ts_control_serde::{ControlDialPlan, ControlIpCandidate};
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum DialPlan {
#[default]
UseDns,
Plan(Vec<DialCandidate>),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct DialCandidate {
pub priority: usize,
pub start_delay_sec: Duration,
pub timeout: Duration,
pub mode: DialMode,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum DialMode {
Ip(IpAddr),
Ace {
host: String,
ip: Option<IpAddr>,
},
}
impl From<ControlDialPlan<'_>> for DialPlan {
fn from(value: ControlDialPlan<'_>) -> Self {
(&value).into()
}
}
impl TryFrom<ControlIpCandidate<'_>> for DialCandidate {
type Error = ();
fn try_from(value: ControlIpCandidate<'_>) -> Result<Self, Self::Error> {
(&value).try_into()
}
}
impl From<&ControlDialPlan<'_>> for DialPlan {
fn from(value: &ControlDialPlan<'_>) -> Self {
let mut plan_candidates = value
.candidates
.iter()
.filter_map(|x| x.try_into().ok())
.collect::<Vec<DialCandidate>>();
plan_candidates.sort_by(|a, b| a.cmp(b).reverse());
if plan_candidates.is_empty() {
DialPlan::UseDns
} else {
DialPlan::Plan(plan_candidates)
}
}
}
impl TryFrom<&ControlIpCandidate<'_>> for DialCandidate {
type Error = ();
fn try_from(value: &ControlIpCandidate<'_>) -> Result<Self, Self::Error> {
let mode = if let Some(ace_host) = value.ace_host {
DialMode::Ace {
host: ace_host.to_string(),
ip: value.ip,
}
} else if let Some(ip) = value.ip {
DialMode::Ip(ip)
} else {
return Err(());
};
Ok(Self {
mode,
timeout: value.dial_timeout_sec,
start_delay_sec: value.dial_start_delay_sec,
priority: value.priority.clamp(0, 256) as _,
})
}
}