1use core::{net::IpAddr, time::Duration};
2
3use ts_control_serde::{ControlDialPlan, ControlIpCandidate};
4
5#[derive(Debug, Clone, PartialEq, Eq, Default)]
7pub enum DialPlan {
8 #[default]
10 UseDns,
11
12 Plan(Vec<DialCandidate>),
14}
15
16#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
18pub struct DialCandidate {
19 pub priority: usize,
25
26 pub start_delay_sec: Duration,
28 pub timeout: Duration,
30
31 pub mode: DialMode,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
37pub enum DialMode {
38 Ip(IpAddr),
40
41 Ace {
43 host: String,
47
48 ip: Option<IpAddr>,
50 },
51}
52
53impl From<ControlDialPlan<'_>> for DialPlan {
54 fn from(value: ControlDialPlan<'_>) -> Self {
55 (&value).into()
56 }
57}
58
59impl TryFrom<ControlIpCandidate<'_>> for DialCandidate {
60 type Error = ();
61
62 fn try_from(value: ControlIpCandidate<'_>) -> Result<Self, Self::Error> {
63 (&value).try_into()
64 }
65}
66
67impl From<&ControlDialPlan<'_>> for DialPlan {
68 fn from(value: &ControlDialPlan<'_>) -> Self {
69 let mut plan_candidates = value
70 .candidates
71 .iter()
72 .filter_map(|x| x.try_into().ok())
73 .collect::<Vec<DialCandidate>>();
74
75 plan_candidates.sort_by(|a, b| a.cmp(b).reverse());
77
78 if plan_candidates.is_empty() {
79 DialPlan::UseDns
80 } else {
81 DialPlan::Plan(plan_candidates)
82 }
83 }
84}
85
86impl TryFrom<&ControlIpCandidate<'_>> for DialCandidate {
87 type Error = ();
88
89 fn try_from(value: &ControlIpCandidate<'_>) -> Result<Self, Self::Error> {
90 let mode = if let Some(ace_host) = value.ace_host {
91 DialMode::Ace {
92 host: ace_host.to_string(),
93 ip: value.ip,
94 }
95 } else if let Some(ip) = value.ip {
96 DialMode::Ip(ip)
97 } else {
98 return Err(());
99 };
100
101 Ok(Self {
102 mode,
103 timeout: value.dial_timeout_sec,
104 start_delay_sec: value.dial_start_delay_sec,
105 priority: value.priority.clamp(0, 256) as _,
106 })
107 }
108}