Skip to main content

tailscale/
axum.rs

1//! Support for the [`axum`] http server wrapping [`netstack::TcpListener`].
2//!
3//! # Example
4//!
5//! ```rust,no_run
6//! # #[tokio::main]
7//! # async fn main() -> Result<(), Box<dyn core::error::Error>> {
8//! # use tailscale::{Config, Device};
9//! let dev = Device::new(
10//!     &Config::default_with_key_file("tsrs_keys.json").await?,
11//!     Some("YOUR_AUTH_KEY".to_owned()),
12//! ).await?;
13//!
14//! let listener = dev.tcp_listen((dev.ipv4_addr().await?, 80).into()).await?;
15//! let listener: tailscale::axum::Listener = listener.into();
16//!
17//! async fn index() -> &'static str { "Hello world!" }
18//! let router = axum::Router::new().route("/", axum::routing::get(index));
19//!
20//! axum::serve(listener, router).await?;
21//! #   Ok(())
22//! # }
23//! ```
24
25use std::net::SocketAddr;
26
27use crate::netstack;
28
29/// Wrapper type implementing [`axum::serve::Listener`] on [`netstack::TcpListener`].
30#[derive(Debug)]
31pub struct Listener(netstack::TcpListener);
32
33impl From<netstack::TcpListener> for Listener {
34    fn from(listener: netstack::TcpListener) -> Self {
35        Self(listener)
36    }
37}
38
39impl From<Listener> for netstack::TcpListener {
40    fn from(listener: Listener) -> Self {
41        listener.0
42    }
43}
44
45impl AsRef<netstack::TcpListener> for Listener {
46    fn as_ref(&self) -> &netstack::TcpListener {
47        &self.0
48    }
49}
50
51impl axum::serve::Listener for Listener {
52    type Io = netstack::TcpStream;
53    type Addr = SocketAddr;
54
55    async fn accept(&mut self) -> (Self::Io, Self::Addr) {
56        let stream = loop {
57            match self.0.accept().await {
58                Ok(stream) => break stream,
59                Err(e) => tracing::error!(err = %e, "tcp accept"),
60            }
61        };
62
63        let addr = stream.remote_addr();
64
65        (stream, addr)
66    }
67
68    fn local_addr(&self) -> std::io::Result<Self::Addr> {
69        Ok(self.0.local_addr())
70    }
71}