use crate::{
core::{
transport::{ListenerEvent, TransportError},
Transport,
},
Multiaddr,
};
use atomic::Atomic;
use futures::{
io::{IoSlice, IoSliceMut},
prelude::*,
ready,
};
use std::{
convert::TryFrom as _,
io,
pin::Pin,
sync::{atomic::Ordering, Arc},
task::{Context, Poll},
};
#[derive(Clone)]
pub struct BandwidthLogging<TInner> {
inner: TInner,
sinks: Arc<BandwidthSinks>,
}
impl<TInner> BandwidthLogging<TInner> {
pub fn new(inner: TInner) -> (Self, Arc<BandwidthSinks>) {
let sink = Arc::new(BandwidthSinks {
inbound: Atomic::new(0),
outbound: Atomic::new(0),
});
let trans = BandwidthLogging {
inner,
sinks: sink.clone(),
};
(trans, sink)
}
}
impl<TInner> Transport for BandwidthLogging<TInner>
where
TInner: Transport,
{
type Output = BandwidthConnecLogging<TInner::Output>;
type Error = TInner::Error;
type Listener = BandwidthListener<TInner::Listener>;
type ListenerUpgrade = BandwidthFuture<TInner::ListenerUpgrade>;
type Dial = BandwidthFuture<TInner::Dial>;
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, TransportError<Self::Error>> {
let sinks = self.sinks;
self.inner
.listen_on(addr)
.map(move |inner| BandwidthListener { inner, sinks })
}
fn dial(self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
let sinks = self.sinks;
self.inner
.dial(addr)
.map(move |fut| BandwidthFuture { inner: fut, sinks })
}
fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
self.inner.address_translation(server, observed)
}
}
#[pin_project::pin_project]
pub struct BandwidthListener<TInner> {
#[pin]
inner: TInner,
sinks: Arc<BandwidthSinks>,
}
impl<TInner, TConn, TErr> Stream for BandwidthListener<TInner>
where
TInner: TryStream<Ok = ListenerEvent<TConn, TErr>, Error = TErr>,
{
type Item = Result<ListenerEvent<BandwidthFuture<TConn>, TErr>, TErr>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project();
let event = if let Some(event) = ready!(this.inner.try_poll_next(cx)?) {
event
} else {
return Poll::Ready(None);
};
let event = event.map({
let sinks = this.sinks.clone();
|inner| BandwidthFuture { inner, sinks }
});
Poll::Ready(Some(Ok(event)))
}
}
#[pin_project::pin_project]
pub struct BandwidthFuture<TInner> {
#[pin]
inner: TInner,
sinks: Arc<BandwidthSinks>,
}
impl<TInner: TryFuture> Future for BandwidthFuture<TInner> {
type Output = Result<BandwidthConnecLogging<TInner::Ok>, TInner::Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let inner = ready!(this.inner.try_poll(cx)?);
let logged = BandwidthConnecLogging {
inner,
sinks: this.sinks.clone(),
};
Poll::Ready(Ok(logged))
}
}
pub struct BandwidthSinks {
inbound: Atomic<u64>,
outbound: Atomic<u64>,
}
impl BandwidthSinks {
pub fn total_inbound(&self) -> u64 {
self.inbound.load(Ordering::Relaxed)
}
pub fn total_outbound(&self) -> u64 {
self.outbound.load(Ordering::Relaxed)
}
}
#[pin_project::pin_project]
pub struct BandwidthConnecLogging<TInner> {
#[pin]
inner: TInner,
sinks: Arc<BandwidthSinks>,
}
impl<TInner: AsyncRead> AsyncRead for BandwidthConnecLogging<TInner> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
let this = self.project();
let num_bytes = ready!(this.inner.poll_read(cx, buf))?;
this.sinks.inbound.fetch_add(
u64::try_from(num_bytes).unwrap_or(u64::max_value()),
Ordering::Relaxed,
);
Poll::Ready(Ok(num_bytes))
}
fn poll_read_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &mut [IoSliceMut<'_>],
) -> Poll<io::Result<usize>> {
let this = self.project();
let num_bytes = ready!(this.inner.poll_read_vectored(cx, bufs))?;
this.sinks.inbound.fetch_add(
u64::try_from(num_bytes).unwrap_or(u64::max_value()),
Ordering::Relaxed,
);
Poll::Ready(Ok(num_bytes))
}
}
impl<TInner: AsyncWrite> AsyncWrite for BandwidthConnecLogging<TInner> {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
let this = self.project();
let num_bytes = ready!(this.inner.poll_write(cx, buf))?;
this.sinks.outbound.fetch_add(
u64::try_from(num_bytes).unwrap_or(u64::max_value()),
Ordering::Relaxed,
);
Poll::Ready(Ok(num_bytes))
}
fn poll_write_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[IoSlice<'_>],
) -> Poll<io::Result<usize>> {
let this = self.project();
let num_bytes = ready!(this.inner.poll_write_vectored(cx, bufs))?;
this.sinks.outbound.fetch_add(
u64::try_from(num_bytes).unwrap_or(u64::max_value()),
Ordering::Relaxed,
);
Poll::Ready(Ok(num_bytes))
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let this = self.project();
this.inner.poll_flush(cx)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
let this = self.project();
this.inner.poll_close(cx)
}
}