use std::marker::PhantomData;
use tower_layer::{Identity, Stack};
use tower_service::Service;
use crate::{
backend::{Backend, BackendConfig},
monitor::shutdown::Shutdown,
task::data::Data,
worker::{
Worker, context::WorkerContext, event::EventHandlerBuilder, service::IntoWorkerService,
},
};
pub struct WorkerBuilder<Args, Source, Middleware> {
pub(crate) context: WorkerContext,
pub(crate) request: PhantomData<Args>,
pub(crate) layer: Middleware,
pub(crate) source: Source,
pub(crate) event_handler: EventHandlerBuilder,
pub(crate) shutdown: Option<Shutdown>,
}
impl<Args, Source, Middleware> std::fmt::Debug for WorkerBuilder<Args, Source, Middleware> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WorkerBuilder")
.field("id", &self.context.name())
.field("job", &std::any::type_name::<Args>())
.field("layer", &std::any::type_name::<Middleware>())
.field("source", &std::any::type_name::<Source>())
.finish()
}
}
impl WorkerBuilder<(), (), Identity> {
pub fn new<T: Into<WorkerContext>>(name: T) -> Self {
Self {
request: PhantomData,
layer: Identity::new(),
source: (),
context: name.into(),
event_handler: EventHandlerBuilder::default(),
shutdown: None,
}
}
}
impl WorkerBuilder<(), (), Identity> {
pub fn backend<NB, NJ>(self, backend: NB) -> WorkerBuilder<NJ, NB, Identity>
where
NB: Backend + BackendConfig<Args = NJ>,
{
WorkerBuilder {
request: PhantomData,
layer: self.layer,
source: backend,
context: self.context,
shutdown: self.shutdown,
event_handler: self.event_handler,
}
}
}
impl<Args, M, B> WorkerBuilder<Args, B, M>
where
B: Backend,
{
pub fn chain<NewLayer>(
self,
f: impl FnOnce(M) -> NewLayer,
) -> WorkerBuilder<Args, B, NewLayer> {
let middleware = f(self.layer);
WorkerBuilder {
request: self.request,
layer: middleware,
context: self.context,
source: self.source,
shutdown: self.shutdown,
event_handler: self.event_handler,
}
}
pub fn layer<U>(self, layer: U) -> WorkerBuilder<Args, B, Stack<U, M>> {
WorkerBuilder {
request: self.request,
source: self.source,
layer: Stack::new(layer, self.layer),
context: self.context,
shutdown: self.shutdown,
event_handler: self.event_handler,
}
}
pub fn data<D>(self, data: D) -> WorkerBuilder<Args, B, Stack<Data<D>, M>> {
WorkerBuilder {
request: self.request,
source: self.source,
layer: Stack::new(Data::new(data), self.layer),
context: self.context,
shutdown: self.shutdown,
event_handler: self.event_handler,
}
}
#[doc(hidden)]
pub fn map_backend<F, NB>(self, map: F) -> WorkerBuilder<Args, NB, M>
where
NB: Backend<Task = B::Task>,
F: FnOnce(B) -> NB,
{
WorkerBuilder {
request: self.request,
source: map(self.source),
layer: self.layer,
context: self.context,
shutdown: self.shutdown,
event_handler: self.event_handler,
}
}
}
impl<Args, B, M> WorkerBuilder<Args, B, M> {
pub fn build<W, Svc, NB>(self, service: W) -> Worker<Args, W::Backend, Svc, M>
where
W: IntoWorkerService<B, Svc, Backend = NB>,
B: Backend + BackendConfig,
NB: Backend + BackendConfig + Send + Unpin,
Svc: Service<NB::Task>,
Args: Send + 'static,
{
let svc = service.into_service(self.source);
let mut worker = Worker::new(self.context, svc.backend, svc.service, self.layer);
worker.event_handler = self
.event_handler
.write()
.map(|mut d| d.take())
.unwrap()
.unwrap_or(Box::new(|_, _e| {
debug!("[>] {_e}");
}));
worker.shutdown = self.shutdown;
worker
}
}