use std::io;
use std::net::SocketAddr;
use std::ops::Deref;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use axum::extract::connect_info::Connected;
use axum::serve::{IncomingStream, Listener};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio::net::TcpListener;
use tokio::sync::{OwnedSemaphorePermit, Semaphore};
pub struct MaxConnListener<L> {
inner: L,
permits: Arc<Semaphore>,
}
impl<L> MaxConnListener<L> {
#[must_use]
pub fn new(inner: L, max_connections: usize) -> Self {
let permits = max_connections.min(Semaphore::MAX_PERMITS);
Self {
inner,
permits: Arc::new(Semaphore::new(permits)),
}
}
}
impl<L> Listener for MaxConnListener<L>
where
L: Listener,
L::Io: Unpin,
{
type Io = PermittedIo<L::Io>;
type Addr = L::Addr;
async fn accept(&mut self) -> (Self::Io, Self::Addr) {
let permit = Arc::clone(&self.permits).acquire_owned().await.ok();
let (io, addr) = self.inner.accept().await;
(
PermittedIo {
io,
_permit: permit,
},
addr,
)
}
fn local_addr(&self) -> io::Result<Self::Addr> {
self.inner.local_addr()
}
}
#[derive(Clone, Copy, Debug)]
pub struct CappedPeerAddr(pub SocketAddr);
impl Deref for CappedPeerAddr {
type Target = SocketAddr;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::fmt::Display for CappedPeerAddr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl Connected<IncomingStream<'_, MaxConnListener<TcpListener>>> for CappedPeerAddr {
fn connect_info(stream: IncomingStream<'_, MaxConnListener<TcpListener>>) -> Self {
Self(*stream.remote_addr())
}
}
pub struct PermittedIo<Io> {
io: Io,
_permit: Option<OwnedSemaphorePermit>,
}
impl<Io: AsyncRead + Unpin> AsyncRead for PermittedIo<Io> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<io::Result<()>> {
Pin::new(&mut self.get_mut().io).poll_read(cx, buf)
}
}
impl<Io: AsyncWrite + Unpin> AsyncWrite for PermittedIo<Io> {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.get_mut().io).poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.get_mut().io).poll_flush(cx)
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.get_mut().io).poll_shutdown(cx)
}
fn poll_write_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[io::IoSlice<'_>],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.get_mut().io).poll_write_vectored(cx, bufs)
}
fn is_write_vectored(&self) -> bool {
self.io.is_write_vectored()
}
}