149 lines
4.3 KiB
Rust
149 lines
4.3 KiB
Rust
use std::fmt;
|
|
use std::sync::Arc;
|
|
|
|
use futures::future::{Executor, Future};
|
|
|
|
use body::Payload;
|
|
use proto::h2::server::H2Stream;
|
|
use server::conn::spawn_all::{NewSvcTask, Watcher};
|
|
use service::Service;
|
|
|
|
pub trait H2Exec<F, B: Payload>: Clone {
|
|
fn execute_h2stream(&self, fut: H2Stream<F, B>) -> ::Result<()>;
|
|
}
|
|
|
|
pub trait NewSvcExec<I, N, S: Service, E, W: Watcher<I, S, E>>: Clone {
|
|
fn execute_new_svc(&self, fut: NewSvcTask<I, N, S, E, W>) -> ::Result<()>;
|
|
}
|
|
|
|
// Either the user provides an executor for background tasks, or we use
|
|
// `tokio::spawn`.
|
|
#[derive(Clone)]
|
|
pub enum Exec {
|
|
Default,
|
|
Executor(Arc<Executor<Box<Future<Item=(), Error=()> + Send>> + Send + Sync>),
|
|
}
|
|
|
|
// ===== impl Exec =====
|
|
|
|
impl Exec {
|
|
pub(crate) fn execute<F>(&self, fut: F) -> ::Result<()>
|
|
where
|
|
F: Future<Item=(), Error=()> + Send + 'static,
|
|
{
|
|
match *self {
|
|
Exec::Default => {
|
|
#[cfg(feature = "runtime")]
|
|
{
|
|
use std::error::Error as StdError;
|
|
use ::tokio_executor::Executor;
|
|
|
|
struct TokioSpawnError;
|
|
|
|
impl fmt::Debug for TokioSpawnError {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
fmt::Debug::fmt("tokio::spawn failed (is a tokio runtime running this future?)", f)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for TokioSpawnError {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
fmt::Display::fmt("tokio::spawn failed (is a tokio runtime running this future?)", f)
|
|
}
|
|
}
|
|
|
|
impl StdError for TokioSpawnError {
|
|
fn description(&self) -> &str {
|
|
"tokio::spawn failed"
|
|
}
|
|
}
|
|
|
|
::tokio_executor::DefaultExecutor::current()
|
|
.spawn(Box::new(fut))
|
|
.map_err(|err| {
|
|
warn!("executor error: {:?}", err);
|
|
::Error::new_execute(TokioSpawnError)
|
|
})
|
|
}
|
|
#[cfg(not(feature = "runtime"))]
|
|
{
|
|
// If no runtime, we need an executor!
|
|
panic!("executor must be set")
|
|
}
|
|
},
|
|
Exec::Executor(ref e) => {
|
|
e.execute(Box::new(fut))
|
|
.map_err(|err| {
|
|
warn!("executor error: {:?}", err.kind());
|
|
::Error::new_execute("custom executor failed")
|
|
})
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for Exec {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
f.debug_struct("Exec")
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
|
|
impl<F, B> H2Exec<F, B> for Exec
|
|
where
|
|
H2Stream<F, B>: Future<Item=(), Error=()> + Send + 'static,
|
|
B: Payload,
|
|
{
|
|
fn execute_h2stream(&self, fut: H2Stream<F, B>) -> ::Result<()> {
|
|
self.execute(fut)
|
|
}
|
|
}
|
|
|
|
impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for Exec
|
|
where
|
|
NewSvcTask<I, N, S, E, W>: Future<Item=(), Error=()> + Send + 'static,
|
|
S: Service,
|
|
W: Watcher<I, S, E>,
|
|
{
|
|
fn execute_new_svc(&self, fut: NewSvcTask<I, N, S, E, W>) -> ::Result<()> {
|
|
self.execute(fut)
|
|
}
|
|
}
|
|
|
|
// ==== impl Executor =====
|
|
|
|
impl<E, F, B> H2Exec<F, B> for E
|
|
where
|
|
E: Executor<H2Stream<F, B>> + Clone,
|
|
H2Stream<F, B>: Future<Item=(), Error=()>,
|
|
B: Payload,
|
|
{
|
|
fn execute_h2stream(&self, fut: H2Stream<F, B>) -> ::Result<()> {
|
|
self.execute(fut)
|
|
.map_err(|err| {
|
|
warn!("executor error: {:?}", err.kind());
|
|
::Error::new_execute("custom executor failed")
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<I, N, S, E, W> NewSvcExec<I, N, S, E, W> for E
|
|
where
|
|
E: Executor<NewSvcTask<I, N, S, E, W>> + Clone,
|
|
NewSvcTask<I, N, S, E, W>: Future<Item=(), Error=()>,
|
|
S: Service,
|
|
W: Watcher<I, S, E>,
|
|
{
|
|
fn execute_new_svc(&self, fut: NewSvcTask<I, N, S, E, W>) -> ::Result<()> {
|
|
self.execute(fut)
|
|
.map_err(|err| {
|
|
warn!("executor error: {:?}", err.kind());
|
|
::Error::new_execute("custom executor failed")
|
|
})
|
|
}
|
|
}
|
|
|
|
// ===== StdError impls =====
|
|
|