base_endpoint/
host_endpoint.rs1use crate::{AddressEndpoint, BindEndpoint, BindOptions, CompositeEndpoint, ConnectEndpoint};
5use base_scheduler::{
6 AddressHints, AddressInfoCollection, AddressInfoView, AddressResolution, AddressService,
7 Cancellation, OperationResult, SocketBind, SocketClose, SocketConnect, SocketDomain,
8 SocketListen, SocketOpen, SocketProtocol, SocketType,
9};
10use std::fmt;
11
12#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct HostEndpoint {
15 hostname: Option<String>,
16 port: u16,
17 domain: Option<SocketDomain>,
18}
19
20impl HostEndpoint {
21 pub fn new(hostname: impl Into<String>, port: u16) -> Self {
23 Self {
24 hostname: Some(hostname.into()),
25 port,
26 domain: None,
27 }
28 }
29
30 pub const fn wildcard(port: u16) -> Self {
32 Self {
33 hostname: None,
34 port,
35 domain: None,
36 }
37 }
38
39 pub fn with_domain(mut self, domain: SocketDomain) -> Self {
41 self.domain = Some(domain);
42 self
43 }
44
45 pub fn hostname(&self) -> Option<&str> {
47 self.hostname.as_deref()
48 }
49
50 pub const fn port(&self) -> u16 {
52 self.port
53 }
54
55 pub async fn resolve<S: AddressResolution + ?Sized>(
57 &self,
58 scheduler: &S,
59 passive: bool,
60 cancellation: &Cancellation,
61 ) -> OperationResult<Vec<AddressEndpoint>> {
62 cancellation.check()?;
63 let addresses = scheduler
64 .address_resolve(
65 self.hostname(),
66 AddressService::Port(self.port),
67 AddressHints {
68 domain: self.domain,
69 socket_type: Some(SocketType::Stream),
70 protocol: Some(SocketProtocol::Tcp),
71 passive,
72 ..AddressHints::default()
73 },
74 cancellation,
75 )
76 .await?;
77 Ok(addresses
78 .entries()
79 .map(|entry| AddressEndpoint::new(entry.address()))
80 .collect())
81 }
82}
83
84impl fmt::Display for HostEndpoint {
85 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
86 let hostname = self.hostname().unwrap_or("*");
87 if hostname.contains(':') {
88 write!(formatter, "tcp://[{hostname}]:{}", self.port)
89 } else {
90 write!(formatter, "tcp://{hostname}:{}", self.port)
91 }
92 }
93}
94
95impl<S> ConnectEndpoint<S> for HostEndpoint
96where
97 S: AddressResolution + SocketOpen + SocketConnect + SocketClose + ?Sized,
98{
99 type Connection = S::Socket;
100
101 async fn connect(
102 &self,
103 scheduler: &S,
104 cancellation: &Cancellation,
105 ) -> OperationResult<S::Socket> {
106 CompositeEndpoint::new(self.resolve(scheduler, false, cancellation).await?)
107 .connect(scheduler, cancellation)
108 .await
109 }
110}
111
112impl<S> BindEndpoint<S> for HostEndpoint
113where
114 S: AddressResolution + SocketOpen + SocketBind + SocketListen + SocketClose + ?Sized,
115{
116 type Listener = S::Socket;
117
118 async fn bind(
119 &self,
120 scheduler: &S,
121 options: BindOptions,
122 cancellation: &Cancellation,
123 ) -> OperationResult<Vec<S::Socket>> {
124 CompositeEndpoint::new(self.resolve(scheduler, true, cancellation).await?)
125 .bind(scheduler, options, cancellation)
126 .await
127 }
128}