1
1
#[ cfg( feature = "metrics" ) ]
2
2
use super :: metrics;
3
- use super :: settings:: TelemetrySettings ;
3
+ use super :: settings:: { TelemetryServerAddr , TelemetrySettings } ;
4
4
use crate :: telemetry:: log;
5
5
use crate :: BootstrapResult ;
6
6
use anyhow:: Context as _;
@@ -14,18 +14,33 @@ use std::net::SocketAddr;
14
14
use std:: pin:: Pin ;
15
15
use std:: sync:: Arc ;
16
16
use std:: task:: { Context , Poll } ;
17
+ use tokio:: io:: { AsyncRead , AsyncWrite } ;
17
18
use tokio:: net:: TcpListener ;
19
+ #[ cfg( unix) ]
20
+ use tokio:: net:: { TcpStream , UnixListener , UnixStream } ;
18
21
use tokio:: sync:: watch;
19
22
20
23
mod router;
21
24
22
25
use router:: Router ;
26
+
27
+ trait AsyncReadWrite : AsyncRead + AsyncWrite + Send + Unpin + ' static { }
28
+
29
+ impl AsyncReadWrite for TcpStream { }
30
+ #[ cfg( unix) ]
31
+ impl AsyncReadWrite for UnixStream { }
32
+
33
+ enum TelemetryListener {
34
+ Tcp ( TcpListener ) ,
35
+ #[ cfg( unix) ]
36
+ Unix ( UnixListener ) ,
37
+ }
23
38
pub use router:: {
24
39
BoxError , TelemetryRouteHandler , TelemetryRouteHandlerFuture , TelemetryServerRoute ,
25
40
} ;
26
41
27
42
pub ( super ) struct TelemetryServerFuture {
28
- listener : TcpListener ,
43
+ listener : TelemetryListener ,
29
44
router : Router ,
30
45
}
31
46
@@ -47,27 +62,52 @@ impl TelemetryServerFuture {
47
62
. map_err ( |err| anyhow:: anyhow!( err) ) ?;
48
63
}
49
64
50
- let addr = settings. server . addr ;
51
-
52
- #[ cfg( feature = "settings" ) ]
53
- let addr = SocketAddr :: from ( addr) ;
54
-
55
- let router = Router :: new ( custom_routes, settings) ;
56
-
57
- let listener = {
58
- let std_listener = std:: net:: TcpListener :: from (
59
- bind_socket ( addr) . with_context ( || format ! ( "binding to socket {addr:?}" ) ) ?,
60
- ) ;
65
+ let router = Router :: new ( custom_routes, settings. clone ( ) ) ;
66
+
67
+ let listener = match & settings. server . addr {
68
+ TelemetryServerAddr :: Tcp ( addr) => {
69
+ #[ cfg( feature = "settings" ) ]
70
+ let addr = SocketAddr :: from ( * addr) ;
71
+
72
+ let std_listener = std:: net:: TcpListener :: from (
73
+ bind_socket ( addr) . with_context ( || format ! ( "binding to TCP socket {addr:?}" ) ) ?,
74
+ ) ;
75
+ std_listener. set_nonblocking ( true ) ?;
76
+ let tokio_listener = tokio:: net:: TcpListener :: from_std ( std_listener) ?;
77
+ TelemetryListener :: Tcp ( tokio_listener)
78
+ }
79
+ #[ cfg( unix) ]
80
+ TelemetryServerAddr :: Unix ( path) => {
81
+ if let Some ( parent) = path. parent ( ) {
82
+ if !parent. exists ( ) {
83
+ std:: fs:: create_dir_all ( parent) . with_context ( || {
84
+ format ! ( "creating parent directories for Unix socket {path:?}" )
85
+ } ) ?;
86
+ }
87
+ }
61
88
62
- std_listener. set_nonblocking ( true ) ?;
89
+ if path. exists ( ) {
90
+ std:: fs:: remove_file ( path)
91
+ . with_context ( || format ! ( "removing existing Unix socket {path:?}" ) ) ?;
92
+ }
63
93
64
- tokio:: net:: TcpListener :: from_std ( std_listener) ?
94
+ let unix_listener = UnixListener :: bind ( path)
95
+ . with_context ( || format ! ( "binding to Unix socket {path:?}" ) ) ?;
96
+ TelemetryListener :: Unix ( unix_listener)
97
+ }
65
98
} ;
66
99
67
100
Ok ( Some ( TelemetryServerFuture { listener, router } ) )
68
101
}
69
- pub ( super ) fn local_addr ( & self ) -> SocketAddr {
70
- self . listener . local_addr ( ) . unwrap ( )
102
+ pub ( super ) fn local_addr ( & self ) -> BootstrapResult < String > {
103
+ match & self . listener {
104
+ TelemetryListener :: Tcp ( listener) => Ok ( listener. local_addr ( ) ?. to_string ( ) ) ,
105
+ #[ cfg( unix) ]
106
+ TelemetryListener :: Unix ( listener) => match listener. local_addr ( ) ?. as_pathname ( ) {
107
+ Some ( path) => Ok ( path. display ( ) . to_string ( ) ) ,
108
+ None => Ok ( "<unnamed>" . to_string ( ) ) ,
109
+ } ,
110
+ }
71
111
}
72
112
73
113
// Adapted from Hyper 0.14 Server stuff and axum::serve::serve.
@@ -87,15 +127,21 @@ impl TelemetryServerFuture {
87
127
let ( close_tx, close_rx) = watch:: channel ( ( ) ) ;
88
128
let listener = self . listener ;
89
129
90
- pin_mut ! ( listener) ;
91
-
92
130
loop {
93
131
let socket = tokio:: select! {
94
- conn = listener. accept( ) => match conn {
132
+ conn = async {
133
+ match & listener {
134
+ TelemetryListener :: Tcp ( listener) => listener. accept( ) . await . map( |( conn, addr) | ( Box :: new( conn) as Box <dyn AsyncReadWrite >, addr. to_string( ) ) ) ,
135
+ #[ cfg( unix) ]
136
+ TelemetryListener :: Unix ( listener) => listener. accept( ) . await . map( |( conn, addr) | {
137
+ let addr_str = addr. as_pathname( ) . map( |p| p. display( ) . to_string( ) ) . unwrap_or_else( || "<unnamed>" . to_string( ) ) ;
138
+ ( Box :: new( conn) as Box <dyn AsyncReadWrite >, addr_str)
139
+ } ) ,
140
+ }
141
+ } => match conn {
95
142
Ok ( ( conn, _) ) => TokioIo :: new( conn) ,
96
143
Err ( e) => {
97
144
log:: warn!( "failed to accept connection" ; "error" => e) ;
98
-
99
145
continue ;
100
146
}
101
147
} ,
@@ -140,13 +186,22 @@ impl Future for TelemetryServerFuture {
140
186
let this = & mut * self ;
141
187
142
188
loop {
143
- let socket = match ready ! ( Pin :: new( & mut this. listener) . poll_accept( cx) ) {
144
- Ok ( ( conn, _) ) => TokioIo :: new ( conn) ,
145
- Err ( e) => {
146
- log:: warn!( "failed to accept connection" ; "error" => e) ;
147
-
148
- continue ;
149
- }
189
+ let socket = match & mut this. listener {
190
+ TelemetryListener :: Tcp ( listener) => match ready ! ( listener. poll_accept( cx) ) {
191
+ Ok ( ( conn, _) ) => TokioIo :: new ( Box :: new ( conn) as Box < dyn AsyncReadWrite > ) ,
192
+ Err ( e) => {
193
+ log:: warn!( "failed to accept connection" ; "error" => e) ;
194
+ continue ;
195
+ }
196
+ } ,
197
+ #[ cfg( unix) ]
198
+ TelemetryListener :: Unix ( listener) => match ready ! ( listener. poll_accept( cx) ) {
199
+ Ok ( ( conn, _) ) => TokioIo :: new ( Box :: new ( conn) as Box < dyn AsyncReadWrite > ) ,
200
+ Err ( e) => {
201
+ log:: warn!( "failed to accept connection" ; "error" => e) ;
202
+ continue ;
203
+ }
204
+ } ,
150
205
} ;
151
206
152
207
let router = this. router . clone ( ) ;
0 commit comments