use serde::Serialize;
use std::sync::Arc;
use crate::codec::Codec;
use crate::{
BatchSubscriber, Broker, Connected, PublishPolicy, Publisher, Subscriber, SubscriptionSource,
};
use crate::runtime::batch::BatchHandler;
use crate::runtime::batch_publishing::{BatchPublishingCall, BatchPublishingHandler};
use crate::runtime::dispatch::{Workers, spawn_dispatch_workers};
use crate::runtime::failure::{DispatchFailure, FailurePolicies};
use crate::runtime::handler::Handler;
use crate::runtime::inject::FromStartup;
use crate::runtime::input::DecodeWith;
use crate::runtime::lifecycle::BoxError;
use crate::runtime::metadata::HandlerMetadata;
use crate::runtime::middleware::BlanketLayer;
use crate::runtime::publish::{PublishPipeline, PublishTransform, ReplyPublisher, TypedPublisher};
use crate::runtime::publishing::{PublishingCall, PublishingHandler};
use super::SourceMessage;
use super::sink::RouterSink;
#[doc(hidden)]
#[derive(Debug)]
pub struct SubscribeRoute<S, H> {
pub(super) source: S,
pub(super) handler: H,
pub(super) meta: HandlerMetadata,
pub(super) policies: FailurePolicies,
pub(super) workers: Workers,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct HandleRoute<S, H> {
pub(super) subscriber: S,
pub(super) handler: H,
pub(super) meta: HandlerMetadata,
pub(super) policies: FailurePolicies,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct BatchRoute<S, H> {
pub(super) source: S,
pub(super) handler: H,
pub(super) meta: HandlerMetadata,
pub(super) policies: FailurePolicies,
pub(super) workers: Workers,
}
pub(super) trait MountRoute<B: Broker, State> {
fn mount_one<G, PP>(self, global: &G, pipeline: &PP, sink: &mut RouterSink<B, State>)
where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static;
}
pub(super) trait RouteMeta {
fn collect(&self, out: &mut Vec<HandlerMetadata>);
}
impl<S, H> RouteMeta for SubscribeRoute<S, H> {
fn collect(&self, out: &mut Vec<HandlerMetadata>) {
out.push(self.meta.clone());
}
}
impl<S, H> RouteMeta for BatchRoute<S, H> {
fn collect(&self, out: &mut Vec<HandlerMetadata>) {
out.push(self.meta.clone());
}
}
impl<S, H> RouteMeta for HandleRoute<S, H> {
fn collect(&self, out: &mut Vec<HandlerMetadata>) {
out.push(self.meta.clone());
}
}
impl<B, S, H, State> MountRoute<B, State> for SubscribeRoute<S, H>
where
B: Broker + 'static,
S: SubscriptionSource<Connected<B>> + Send + 'static,
S::Subscriber: Send + 'static,
SourceMessage<B, S>: Send + Sync + 'static,
State: Send + Sync + 'static,
H: Handler<SourceMessage<B, S>, (), State> + 'static,
{
fn mount_one<G, PP>(self, global: &G, _pipeline: &PP, sink: &mut RouterSink<B, State>)
where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
let handler = global.apply::<SourceMessage<B, S>, (), State, H>(self.handler);
sink.push_subscribe_workers(self.source, handler, self.meta, self.policies, self.workers);
}
}
impl<B, S, H, State> MountRoute<B, State> for BatchRoute<S, H>
where
B: Broker + 'static,
S: SubscriptionSource<Connected<B>> + Send + 'static,
S::Subscriber: BatchSubscriber + Send + 'static,
SourceMessage<B, S>: Send + 'static,
State: Send + Sync + 'static,
H: BatchHandler<SourceMessage<B, S>, State> + 'static,
{
fn mount_one<G, PP>(self, _global: &G, _pipeline: &PP, sink: &mut RouterSink<B, State>)
where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
sink.push_subscribe_batch(
self.source,
self.handler,
self.meta,
self.policies,
self.workers,
);
}
}
impl<B, S, H, State> MountRoute<B, State> for HandleRoute<S, H>
where
B: Broker + 'static,
S: Subscriber + Send + 'static,
S::Message: Send + Sync + 'static,
State: Send + Sync + 'static,
H: Handler<S::Message, (), State> + 'static,
{
fn mount_one<G, PP>(self, global: &G, _pipeline: &PP, sink: &mut RouterSink<B, State>)
where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
let handler = global.apply::<S::Message, (), State, H>(self.handler);
sink.push_handle(self.subscriber, handler, self.meta, self.policies);
}
}
#[doc(hidden)]
pub struct PublishingRoute<S, D, C, P, PC, PL> {
pub(super) source: S,
pub(super) def: D,
pub(super) codec: C,
pub(super) publisher: TypedPublisher<P, PC, PL>,
pub(super) meta: HandlerMetadata,
pub(super) policies: FailurePolicies,
pub(super) workers: Workers,
}
impl<S, D, C, P, PC, PL> std::fmt::Debug for PublishingRoute<S, D, C, P, PC, PL> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PublishingRoute")
.field("meta", &self.meta)
.finish_non_exhaustive()
}
}
#[doc(hidden)]
pub struct BatchPublishingRoute<S, D, C, R> {
pub(super) source: S,
pub(super) def: D,
pub(super) codec: C,
pub(super) publisher: R,
pub(super) meta: HandlerMetadata,
pub(super) policies: FailurePolicies,
pub(super) workers: Workers,
}
impl<S, D, C, R> std::fmt::Debug for BatchPublishingRoute<S, D, C, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BatchPublishingRoute")
.field("meta", &self.meta)
.finish_non_exhaustive()
}
}
impl<S, D, C, P, PC, PL> RouteMeta for PublishingRoute<S, D, C, P, PC, PL> {
fn collect(&self, out: &mut Vec<HandlerMetadata>) {
out.push(self.meta.clone());
}
}
impl<S, D, C, R> RouteMeta for BatchPublishingRoute<S, D, C, R> {
fn collect(&self, out: &mut Vec<HandlerMetadata>) {
out.push(self.meta.clone());
}
}
impl<B, Source, Def, DecodeCodec, Leaf, ReplyCodec, Transforms, State> MountRoute<B, State>
for PublishingRoute<Source, Def, DecodeCodec, Leaf, ReplyCodec, Transforms>
where
B: Broker + 'static,
Source: SubscriptionSource<Connected<B>> + Send + 'static,
Source::Subscriber: Sync + Send + 'static,
SourceMessage<B, Source>: Send + Sync + 'static,
State: Send + Sync + 'static,
Def: PublishingCall<State> + 'static,
Def::Input: DecodeWith<DecodeCodec>,
Def::Injections: FromStartup<B, Source::Subscriber, ()> + Send + Sync + 'static,
Def::Reply: Serialize + Send + Sync + 'static,
Def::Context: crate::BuildContext<SourceMessage<B, Source>> + Send + Sync + 'static,
DecodeCodec: Codec + Send + 'static,
Leaf: PublishPolicy<Connected<B>> + Send + 'static,
Leaf::Live: Publisher + 'static,
ReplyCodec: Codec + Send + 'static,
Transforms: PublishTransform<Def::Context> + Send + 'static,
{
fn mount_one<G, PP>(self, global: &G, pipeline: &PP, sink: &mut RouterSink<B, State>)
where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
let global = global.clone();
let pipeline = pipeline.clone();
let Self {
source,
def,
codec,
publisher,
meta,
policies,
workers,
} = self;
let name: Arc<str> = Arc::from(meta.name.as_ref());
sink.push_raw(
Box::new(move |connected, state, delivery, shutdown, token| {
Box::pin(async move {
let publisher = publisher
.pair(connected.as_ref())
.await
.map_err(|e| Box::new(e) as BoxError)?;
let subscriber = source
.subscribe(connected.as_ref())
.await
.map_err(|e| Box::new(e) as BoxError)?;
let injections = Def::Injections::resolve(&(), connected.as_ref(), &subscriber)
.await
.map_err(|e| Box::new(e) as BoxError)?;
let handler = global.apply::<SourceMessage<B, Source>, Def::Context, State, _>(
PublishingHandler {
def,
codec,
publisher,
pipeline,
injections,
decode: policies.decode,
},
);
let failure = DispatchFailure::new(policies, shutdown);
Ok(spawn_dispatch_workers(
subscriber,
Arc::new(handler),
token,
name,
state,
delivery,
failure,
workers,
))
})
}),
meta,
);
}
}
impl<B, Source, Def, DecodeCodec, ReplySource, BatchReply, State> MountRoute<B, State>
for BatchPublishingRoute<Source, Def, DecodeCodec, ReplySource>
where
B: Broker + 'static,
Source: SubscriptionSource<Connected<B>> + Send + 'static,
Source::Subscriber: BatchSubscriber + Sync + Send + 'static,
SourceMessage<B, Source>: Send + 'static,
State: Send + Sync + 'static,
Def: BatchPublishingCall<State> + 'static,
Def::Input: DecodeWith<DecodeCodec>,
Def::Injections: FromStartup<B, Source::Subscriber, ()> + Send + Sync + 'static,
Def::Reply: Serialize + Send + Sync + 'static,
DecodeCodec: Send + Sync + 'static,
ReplySource: PublishPolicy<Connected<B>, Live = BatchReply> + Send + 'static,
BatchReply: ReplyPublisher + 'static,
{
fn mount_one<G, PP>(self, _global: &G, pipeline: &PP, sink: &mut RouterSink<B, State>)
where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
let pipeline = pipeline.clone();
let Self {
source,
def,
codec,
publisher,
meta,
policies,
workers,
} = self;
sink.push_injected_batch(
source,
async move |connected: Arc<Connected<B>>, subscriber| {
let publisher = publisher
.pair(connected.as_ref())
.await
.map_err(|e| Box::new(e) as BoxError)?;
let injections = Def::Injections::resolve(&(), connected.as_ref(), &subscriber)
.await
.map_err(|e| Box::new(e) as BoxError)?;
let handler = BatchPublishingHandler {
def,
codec,
publisher,
pipeline,
injections,
decode: policies.decode,
};
Ok((subscriber, handler))
},
meta,
policies,
workers,
);
}
}
pub trait RouterDef<B: Broker, State = ()> {
#[doc(hidden)]
fn mount<G, PP>(self, global: &G, pipeline: &PP, sink: &mut RouterSink<B, State>)
where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static;
}
pub trait RouterHandlers {
#[doc(hidden)]
fn collect_handlers(&self, out: &mut Vec<HandlerMetadata>);
}
impl<B: Broker + 'static, State> RouterDef<B, State> for () {
fn mount<G, PP>(self, _global: &G, _pipeline: &PP, _sink: &mut RouterSink<B, State>)
where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
}
}
impl RouterHandlers for () {
fn collect_handlers(&self, _out: &mut Vec<HandlerMetadata>) {}
}
impl<B, Head, Tail, State> RouterDef<B, State> for (Head, Tail)
where
B: Broker + 'static,
Head: MountRoute<B, State>,
Tail: RouterDef<B, State>,
{
fn mount<G, PP>(self, global: &G, pipeline: &PP, sink: &mut RouterSink<B, State>)
where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
self.1.mount(global, pipeline, sink);
self.0.mount_one(global, pipeline, sink);
}
}
impl<Head, Tail> RouterHandlers for (Head, Tail)
where
Head: RouteMeta,
Tail: RouterHandlers,
{
fn collect_handlers(&self, out: &mut Vec<HandlerMetadata>) {
self.1.collect_handlers(out);
self.0.collect(out);
}
}