1use std::{
2 fmt::Display,
3 net::SocketAddr,
4 time::{Duration, Instant},
5};
6
7#[derive(Debug, Clone, PartialEq)]
13pub enum ConId {
14 Initiator { name: String, local: Option<SocketAddr>, peer: SocketAddr },
15 Acceptor { name: String, local: SocketAddr, peer: Option<SocketAddr> },
16}
17impl ConId {
18 pub fn clt(name: Option<&str>, local: Option<&str>, peer: &str) -> Self {
19 ConId::Initiator {
20 name: name.unwrap_or("unknown").to_owned(),
21 local: local.map(|addr| addr.parse().unwrap_or_else(|_| panic!("unable to parse addr: {:?}", addr))),
22 peer: peer.parse().unwrap_or_else(|_| panic!("unable to parse addr: {:?}", peer)),
23 }
24 }
25 pub fn set_local(&mut self, local: SocketAddr) {
26 match self {
27 ConId::Initiator { local: l, .. } => *l = Some(local),
28 ConId::Acceptor { local: l, .. } => *l = local,
29 }
30 }
31 pub fn set_peer(&mut self, peer: SocketAddr) {
32 match self {
33 ConId::Initiator { peer: p, .. } => *p = peer,
34 ConId::Acceptor { peer: p, .. } => *p = Some(peer),
35 }
36 }
37
38 pub fn svc(name: Option<&str>, local: &str, peer: Option<&str>) -> Self {
39 ConId::Acceptor {
40 name: name.unwrap_or("unknown").to_owned(),
41 local: local.parse().unwrap_or_else(|_| panic!("unable to parse addr: {:?}", local)),
42 peer: peer.map(|addr| addr.parse().unwrap_or_else(|_| panic!("unable to parse addr: {:?}", addr))),
43 }
44 }
45 pub fn name(&self) -> &str {
46 match self {
47 ConId::Initiator { name, .. } => name,
48 ConId::Acceptor { name, .. } => name,
49 }
50 }
51 pub fn get_peer(&self) -> Option<SocketAddr> {
52 match self {
53 ConId::Initiator { peer, .. } => Some(*peer),
54 ConId::Acceptor { peer, .. } => *peer,
55 }
56 }
57 pub fn get_local(&self) -> Option<SocketAddr> {
58 match self {
59 ConId::Initiator { local, .. } => *local,
60 ConId::Acceptor { local, .. } => Some(*local),
61 }
62 }
63 pub fn from_same_lineage(&self, other: &Self) -> bool {
64 match (self, other) {
65 (ConId::Acceptor { local: l1, .. }, ConId::Acceptor { local: l2, .. }) => l1 == l2,
67 _ => false,
68 }
69 }
70}
71impl Default for ConId {
72 fn default() -> Self {
73 ConId::clt(None, None, "0.0.0.0:0")
74 }
75}
76impl Display for ConId {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 match self {
79 ConId::Initiator { name, local, peer } => {
80 write!(
81 f,
82 "Initiator({name}@{}->{peer})",
83 match local {
84 Some(local) => format!("{}", local),
85 None => "pending".to_owned(),
86 }
87 )
88 }
89 ConId::Acceptor { name, local, peer } => {
90 write!(
91 f,
92 "Acceptor({name}@{local}<-{})",
93 match peer {
94 Some(peer) => format!("{}", peer),
95 None => "pending".to_owned(),
96 }
97 )
98 }
99 }
100 }
101}
102
103pub trait ConnectionId {
105 fn con_id(&self) -> &ConId;
106}
107
108pub trait ConnectionStatus {
109 fn is_connected(&self) -> bool;
111 fn is_connected_busywait_timeout(&self, timeout: Duration) -> bool {
112 let start = Instant::now();
113 while start.elapsed() < timeout {
114 if self.is_connected() {
115 return true;
116 }
117 std::hint::spin_loop();
118 }
119 self.is_connected()
121 }
122}
123pub trait PoolConnectionStatus {
125 fn is_next_connected(&mut self) -> bool;
126 fn is_next_connected_busywait_timeout(&mut self, timeout: Duration) -> bool {
127 let start = Instant::now();
128 while start.elapsed() < timeout {
129 if self.is_next_connected() {
130 return true;
131 }
132 std::hint::spin_loop();
133 }
134 self.is_next_connected()
136 }
137 fn all_connected(&mut self) -> bool;
138 fn all_connected_busywait_timeout(&mut self, timeout: Duration) -> bool {
139 let start = Instant::now();
140 while start.elapsed() < timeout {
141 if self.all_connected() {
142 return true;
143 }
144 std::hint::spin_loop();
145 }
146 self.all_connected()
148 }
149}
150
151#[cfg(test)]
152mod test {
153
154 use log::info;
155
156 use crate::prelude::*;
157 use crate::unittest::setup;
158
159 #[test]
160 fn test_con_id() {
161 setup::log::configure();
162 let con_id = ConId::clt(Some("unittest"), None, "0.0.0.0:1");
163 info!("con_id: {:?}", con_id);
164 info!("con_id: {}", con_id);
165 assert_eq!(con_id.to_string(), "Initiator(unittest@pending->0.0.0.0:1)");
166
167 let con_id = ConId::svc(Some("unittest"), "0.0.0.0:1", None);
168 info!("con_id: {:?}", con_id);
169 info!("con_id: {}", con_id);
170 assert_eq!(con_id.to_string(), "Acceptor(unittest@0.0.0.0:1<-pending)");
171 }
172}