use flume::{Receiver, Sender};
use monocoque_core::options::SocketOptions;
use monocoque_core::rt::{JoinHandle, spawn};
use monocoque_core::rt::{TcpListener, TcpStream};
use std::collections::VecDeque;
use std::io;
use super::PullSocket;
const MAX_ITEM_MESSAGES: usize = 128;
const CHANNEL_CAPACITY: usize = 64;
type Batch = Vec<Vec<bytes::Bytes>>;
pub struct PullFanIn {
rx: Receiver<Batch>,
buf: VecDeque<Vec<bytes::Bytes>>,
_readers: Vec<JoinHandle<()>>,
}
impl PullFanIn {
pub async fn bind(
addr: impl monocoque_core::rt::ToSocketAddrs,
n_workers: usize,
) -> io::Result<(TcpListener, Self)> {
Self::bind_with_options(addr, n_workers, SocketOptions::default()).await
}
pub async fn bind_with_options(
addr: impl monocoque_core::rt::ToSocketAddrs,
n_workers: usize,
options: SocketOptions,
) -> io::Result<(TcpListener, Self)> {
let listener = TcpListener::bind(addr).await?;
let fanin = Self::accept_workers(&listener, n_workers, options).await?;
Ok((listener, fanin))
}
pub async fn accept_workers(
listener: &TcpListener,
n_workers: usize,
options: SocketOptions,
) -> io::Result<Self> {
let (tx, rx) = flume::bounded(CHANNEL_CAPACITY);
let mut readers = Vec::with_capacity(n_workers);
for _ in 0..n_workers {
let (stream, _) = listener.accept().await?;
let pull = PullSocket::from_tcp_with_options(stream, options.clone()).await?;
readers.push(spawn(read_into_channel(pull, tx.clone())));
}
drop(tx);
Ok(Self {
rx,
buf: VecDeque::new(),
_readers: readers,
})
}
pub async fn recv(&mut self) -> io::Result<Option<Vec<bytes::Bytes>>> {
if let Some(msg) = self.buf.pop_front() {
return Ok(Some(msg));
}
match self.rx.recv_async().await {
Ok(batch) => {
self.buf.extend(batch);
Ok(self.buf.pop_front())
}
Err(_) => Ok(None),
}
}
pub fn try_recv(&mut self) -> io::Result<Option<Vec<bytes::Bytes>>> {
if let Some(msg) = self.buf.pop_front() {
return Ok(Some(msg));
}
match self.rx.try_recv() {
Ok(batch) => {
self.buf.extend(batch);
Ok(self.buf.pop_front())
}
Err(_) => Ok(None),
}
}
pub async fn recv_batch(&mut self) -> io::Result<Option<Vec<Vec<bytes::Bytes>>>> {
let mut out: Vec<Vec<bytes::Bytes>> = self.buf.drain(..).collect();
if out.is_empty() {
match self.rx.recv_async().await {
Ok(batch) => out = batch,
Err(_) => return Ok(None),
}
}
while let Ok(batch) = self.rx.try_recv() {
out.extend(batch);
}
Ok(Some(out))
}
}
async fn read_into_channel(mut pull: PullSocket<TcpStream>, tx: Sender<Batch>) {
loop {
match pull.recv_batch().await {
Ok(Some(batch)) => {
let mut it = batch.into_iter();
loop {
let chunk: Batch = it.by_ref().take(MAX_ITEM_MESSAGES).collect();
if chunk.is_empty() {
break;
}
if tx.send_async(chunk).await.is_err() {
return;
}
}
}
_ => return,
}
}
}