-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Choose Listener
type at runtime
#3172
Comments
You can create something like enum TcpOrUnix {
Tcp(TcpListener),
Unix(UnixListener),
}
impl Listener for TcpOrUnix {
// match self and then just call the inner one...
} Is that good enough for you? |
Ah, thank you, that approach hadn't occurred to me! I'm trying to implement it, and having some trouble working out what the types of Am I way off track? or what am I missing? |
It's a bit more boilerplate than I expected, but you can use the same idea for the enum TcpOrUnix {
Tcp(TcpListener),
Unix(tokio::net::UnixListener),
}
enum TcpOrUnixIo {
Tcp(TcpStream),
Unix(tokio::net::UnixStream),
}
impl AsyncRead for TcpOrUnixIo {
fn poll_read(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut io::ReadBuf<'_>,
) -> std::task::Poll<std::io::Result<()>> {
match self.get_mut() {
TcpOrUnixIo::Tcp(tcp_stream) => std::pin::pin!(tcp_stream).poll_read(cx, buf),
TcpOrUnixIo::Unix(unix_stream) => std::pin::pin!(unix_stream).poll_read(cx, buf),
}
}
}
impl AsyncWrite for TcpOrUnixIo {
// Same idea as `AsyncRead`
}
enum TcpOrUnixAddr {
Tcp(std::net::SocketAddr),
Unix(tokio::net::unix::SocketAddr),
}
impl Listener for TcpOrUnix {
type Io = TcpOrUnixIo;
type Addr = TcpOrUnixAddr;
fn accept(&mut self) -> impl Future<Output = (Self::Io, Self::Addr)> + Send {
match self {
TcpOrUnix::Tcp(tcp_listener) => futures_util::future::Either::Left(
tcp_listener
.accept()
.map(|(io, addr)| (TcpOrUnixIo::Tcp(io), TcpOrUnixAddr::Tcp(addr))),
),
TcpOrUnix::Unix(unix_listener) => futures_util::future::Either::Right(
unix_listener
.accept()
.map(|(io, addr)| (TcpOrUnixIo::Unix(io), TcpOrUnixAddr::Unix(addr))),
),
}
}
fn local_addr(&self) -> io::Result<Self::Addr> {
match self {
TcpOrUnix::Tcp(tcp_listener) => tcp_listener.local_addr().map(TcpOrUnixAddr::Tcp),
TcpOrUnix::Unix(unix_listener) => unix_listener.local_addr().map(TcpOrUnixAddr::Unix),
}
}
} |
Yes, that's exactly right! I did try that, and did fight with the pins. Thanks for working out what it needed to be, @mladedav! So, do you think there is room in axum for code like this? Or is this too specific a use case? |
I think this is too specific. If there are more similar requests we might consider it (probably with generics though), but until then you can either use the code as is or publish it on crates in another crate. |
Okay, thanks for taking the time to work on this with me, @mladedav! |
Feature Request
Motivation
I want to choose between a
TcpListener
and aUnixListener
at runtime, and use the same simpleserve
function.I was trying to make use of the new feature introduced in #2941 to switch between a
TcpListener
and aUnixListener
depending on a command-line argument. It seems the genericity is for allowing Unix sockets at compile-time - which is great, thank you!Proposal
First I tried to
bind
one listener or the other outside of the function, so I could then pass it as an argument:But this fails with
Then, while trying to simplify, I tried this:
This fails with
Alternatives
I can call
serve
in two different branches - which, again, is much more than I could before v0.8.0!This looks reasonable in this small example, but
with_graceful_shutdown
makes it slightly more cumbersome.Thanks again for axum and v0.8!
The text was updated successfully, but these errors were encountered: