use std::fmt;
use futures::{AsyncSink, Stream, StartSend, Poll, Async};
use futures::sync::mpsc::{self, channel, Sender};
use futures::sink::Sink;
use futures::stream::Fuse;
use futures::future::Future;
use tokio_core::reactor::Handle;
use metrics::Collect;
use error_log::{ErrorLog, ShutdownReason};
use config::{Queue, DefaultQueue, private};
#[derive(Debug)]
pub struct Pool<V, M> {
channel: Sender<V>,
metrics: M,
}
pub struct QueueError<V>(V);
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
struct ForwardFuture<S, M, E>
where S: Sink
{
receiver: Fuse<mpsc::Receiver<S::SinkItem>>,
buffer: Option<S::SinkItem>,
metrics: M,
errors: E,
sink: S,
}
impl<I: 'static, M> private::NewQueue<I, M> for DefaultQueue {
type Pool = Pool<I, M>;
fn spawn_on<S, E>(self, pool: S, err: E, metrics: M, handle: &Handle)
-> Self::Pool
where S: Sink<SinkItem=I, SinkError=private::Done> + 'static,
E: ErrorLog + 'static,
M: Collect + 'static,
{
Queue(100).spawn_on(pool, err, metrics, handle)
}
}
impl<I: 'static, M> private::NewQueue<I, M> for Queue {
type Pool = Pool<I, M>;
fn spawn_on<S, E>(self, pool: S, e: E, metrics: M, handle: &Handle)
-> Self::Pool
where S: Sink<SinkItem=I, SinkError=private::Done> + 'static,
E: ErrorLog + 'static,
M: Collect + 'static,
{
let buf_size = self.0.saturating_sub(1);
let (tx, rx) = channel(buf_size);
handle.spawn(ForwardFuture {
receiver: rx.fuse(),
metrics: metrics.clone(),
errors: e,
sink: pool,
buffer: None,
});
return Pool {
channel: tx,
metrics,
};
}
}
trait AssertTraits: Clone + Send + Sync {}
impl<V: Send, M: Collect> AssertTraits for Pool<V, M> {}
impl<V, M: Clone> Clone for Pool<V, M> {
fn clone(&self) -> Self {
Pool {
channel: self.channel.clone(),
metrics: self.metrics.clone(),
}
}
}
impl<S, M, E> ForwardFuture<S, M, E>
where S: Sink<SinkError=private::Done>,
M: Collect,
E: ErrorLog,
{
fn poll_forever(&mut self) -> Async<()> {
if let Some(item) = self.buffer.take() {
match self.sink.start_send(item) {
Ok(AsyncSink::Ready) => {
self.metrics.request_forwarded();
}
Ok(AsyncSink::NotReady(item)) => {
self.buffer = Some(item);
return Async::NotReady;
}
Err(private::Done) => return Async::Ready(()),
}
}
let was_done = self.receiver.is_done();
loop {
match self.receiver.poll() {
Ok(Async::Ready(Some(item))) => {
match self.sink.start_send(item) {
Ok(AsyncSink::Ready) => {
self.metrics.request_forwarded();
continue;
}
Ok(AsyncSink::NotReady(item)) => {
self.buffer = Some(item);
return Async::NotReady;
}
Err(private::Done) => return Async::Ready(()),
}
}
Ok(Async::Ready(None)) => {
if !was_done {
self.errors.pool_shutting_down(
ShutdownReason::RequestStreamClosed);
}
match self.sink.close() {
Ok(Async::NotReady) => {
return Async::NotReady;
}
Ok(Async::Ready(())) | Err(private::Done) => {
return Async::Ready(());
}
}
}
Ok(Async::NotReady) => match self.sink.poll_complete() {
Ok(_) => {
return Async::NotReady;
}
Err(private::Done) => {
return Async::Ready(());
}
}
Err(()) => unreachable!(),
}
}
}
}
impl<S, M, E> Future for ForwardFuture<S, M, E>
where S: Sink<SinkError=private::Done>,
M: Collect,
E: ErrorLog,
{
type Item = ();
type Error = (); fn poll(&mut self) -> Result<Async<()>, ()> {
match self.poll_forever() {
Async::NotReady => Ok(Async::NotReady),
Async::Ready(()) => {
self.errors.pool_closed();
self.metrics.pool_closed();
Ok(Async::Ready(()))
}
}
}
}
impl<V, M> Sink for Pool<V, M>
where M: Collect,
{
type SinkItem=V;
type SinkError=QueueError<V>;
fn start_send(&mut self, item: Self::SinkItem)
-> StartSend<Self::SinkItem, Self::SinkError>
{
match self.channel.start_send(item) {
Ok(AsyncSink::Ready) => {
self.metrics.request_queued();
Ok(AsyncSink::Ready)
}
Ok(AsyncSink::NotReady(item)) => Ok(AsyncSink::NotReady(item)),
Err(e) => Err(QueueError(e.into_inner())),
}
}
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
self.channel.poll_complete()
.map_err(|_| {
unreachable!();
})
}
fn close(&mut self) -> Poll<(), Self::SinkError> {
self.channel.close()
.map_err(|_| {
unreachable!();
})
}
}
impl<T> QueueError<T> {
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> fmt::Display for QueueError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("connection pool is closed")
}
}
impl<T> fmt::Debug for QueueError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("QueueError(_)")
}
}
impl<T> ::std::error::Error for QueueError<T> {
fn description(&self) -> &str {
"QueueError"
}
fn cause(&self) -> Option<&::std::error::Error> {
None
}
}