use std::marker::PhantomData;
use futures::Stream;
use tower::{
layer::util::{Identity, Stack},
Layer, Service, ServiceBuilder,
};
use crate::{
backend::Backend,
error::Error,
layers::extensions::Data,
request::Request,
service_fn::service_fn,
service_fn::ServiceFn,
worker::{Ready, Worker, WorkerId},
};
pub struct WorkerBuilder<Req, Ctx, Source, Middleware, Serv> {
id: WorkerId,
request: PhantomData<Request<Req, Ctx>>,
layer: ServiceBuilder<Middleware>,
source: Source,
service: PhantomData<Serv>,
}
impl<Req, Ctx, Source, Middleware, Serv> std::fmt::Debug
for WorkerBuilder<Req, Ctx, Source, Middleware, Serv>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WorkerBuilder")
.field("id", &self.id)
.field("job", &std::any::type_name::<Req>())
.field("layer", &std::any::type_name::<Middleware>())
.field("source", &std::any::type_name::<Source>())
.finish()
}
}
impl<Serv> WorkerBuilder<(), (), (), Identity, Serv> {
pub fn new<T: AsRef<str>>(name: T) -> WorkerBuilder<(), (), (), Identity, Serv> {
let job: PhantomData<Request<(), ()>> = PhantomData;
WorkerBuilder {
request: job,
layer: ServiceBuilder::new(),
source: (),
id: WorkerId::new(name),
service: PhantomData,
}
}
}
impl<M, Serv> WorkerBuilder<(), (), (), M, Serv> {
#[deprecated(since = "0.6.0", note = "Consider using the `.backend`")]
pub fn stream<
NS: Stream<Item = Result<Option<Request<NJ, Ctx>>, Error>> + Send + 'static,
NJ,
Ctx,
>(
self,
stream: NS,
) -> WorkerBuilder<NJ, Ctx, NS, M, Serv> {
WorkerBuilder {
request: PhantomData,
layer: self.layer,
source: stream,
id: self.id,
service: self.service,
}
}
pub fn backend<NB: Backend<Request<NJ, Ctx>, Res>, NJ, Res: Send, Ctx>(
self,
backend: NB,
) -> WorkerBuilder<NJ, Ctx, NB, M, Serv>
where
Serv: Service<Request<NJ, Ctx>, Response = Res>,
{
WorkerBuilder {
request: PhantomData,
layer: self.layer,
source: backend,
id: self.id,
service: self.service,
}
}
}
impl<Req, M, Serv, Ctx> WorkerBuilder<Req, Ctx, (), M, Serv> {
pub fn chain<NewLayer>(
self,
f: impl FnOnce(ServiceBuilder<M>) -> ServiceBuilder<NewLayer>,
) -> WorkerBuilder<Req, Ctx, (), NewLayer, Serv> {
let middleware = f(self.layer);
WorkerBuilder {
request: self.request,
layer: middleware,
id: self.id,
source: self.source,
service: self.service,
}
}
pub fn layer<U>(self, layer: U) -> WorkerBuilder<Req, Ctx, (), Stack<U, M>, Serv>
where
M: Layer<U>,
{
WorkerBuilder {
request: self.request,
source: self.source,
layer: self.layer.layer(layer),
id: self.id,
service: self.service,
}
}
pub fn data<D>(self, data: D) -> WorkerBuilder<Req, Ctx, (), Stack<Data<D>, M>, Serv>
where
M: Layer<Data<D>>,
{
WorkerBuilder {
request: self.request,
source: self.source,
layer: self.layer.layer(Data::new(data)),
id: self.id,
service: self.service,
}
}
}
impl<Req, P, M, S, Ctx> WorkerFactory<Req, Ctx, S> for WorkerBuilder<Req, Ctx, P, M, S>
where
S: Service<Request<Req, Ctx>> + Send + 'static + Sync,
S::Future: Send,
S::Response: 'static,
M: Layer<S>,
Req: Send + 'static + Sync,
P: Backend<Request<Req, Ctx>, S::Response> + 'static,
M: 'static,
{
type Source = P;
type Service = M::Service;
fn build(self, service: S) -> Worker<Ready<M::Service, P>> {
let worker_id = self.id;
let poller = self.source;
let middleware = self.layer;
let service = middleware.service(service);
Worker::new(worker_id, Ready::new(service, poller))
}
}
pub trait WorkerFactory<Req, Ctx, S> {
type Source;
type Service;
fn build(self, service: S) -> Worker<Ready<Self::Service, Self::Source>>;
}
pub trait WorkerFactoryFn<Req, Ctx, F, FnArgs> {
type Source;
type Service;
fn build_fn(self, f: F) -> Worker<Ready<Self::Service, Self::Source>>;
}
impl<Req, W, F, Ctx, FnArgs> WorkerFactoryFn<Req, Ctx, F, FnArgs> for W
where
W: WorkerFactory<Req, Ctx, ServiceFn<F, Req, Ctx, FnArgs>>,
{
type Source = W::Source;
type Service = W::Service;
fn build_fn(self, f: F) -> Worker<Ready<Self::Service, Self::Source>> {
self.build(service_fn(f))
}
}