use std::borrow::Cow;
use std::fmt;
use std::marker::PhantomData;
use std::num::NonZeroUsize;
use crate::{BatchSubscriber, Broker, BuildContext, Connected, Subscriber, SubscriptionSource};
use crate::runtime::batch::BatchHandler;
use crate::runtime::dispatch::Workers;
use crate::runtime::failure::FailurePolicies;
use crate::runtime::handler::Handler;
use crate::runtime::metadata::HandlerMetadata;
use crate::runtime::middleware::BlanketLayer;
use crate::runtime::publish::{PublishIdentity, PublishPipeline};
use crate::runtime::redelivery::{CopyPathAddress, CopyPathPairing, RetryPairing, RetrySetup};
use crate::runtime::retry::DestinationDeclared;
use crate::runtime::retry::RetryOpen;
use crate::{CopyPath, RetryDeclaration};
use super::SourceMessage;
use super::sink::RouterSink;
#[doc(hidden)]
#[derive(Debug)]
pub struct SubscribeRoute<S, H, Cx = ()> {
pub(super) source: S,
pub(super) handler: H,
pub(super) meta: HandlerMetadata,
pub(super) policies: FailurePolicies,
pub(super) workers: Workers,
pub(super) _context: PhantomData<fn() -> Cx>,
}
#[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, Cx = ()> {
pub(super) source: S,
pub(super) handler: H,
pub(super) meta: HandlerMetadata,
pub(super) policies: FailurePolicies,
pub(super) workers: Workers,
pub(super) batch_size: NonZeroUsize,
pub(super) _context: PhantomData<fn() -> Cx>,
}
pub(super) trait MountRoute<B: Broker, State, RetryPipeline> {
type Context;
fn mount_one<G, PP>(
self,
global: &G,
pipeline: &PP,
retry_pipeline: &RetryPipeline,
sink: &mut RouterSink<B, State>,
setup: RetrySetup<B, Self::Context>,
) where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static;
}
#[doc(hidden)]
pub trait RouteSubscription<B: Broker> {
type Source;
type Copies: CopyPath;
type Context;
}
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "this registration does not say where its retry copies go",
label = "the subscription descriptor of `{Self}` addresses none, and nothing here names a \
destination",
note = "one such subscription reads many destinations (a wildcard subject, an MQTT filter, a \
Pulsar pattern, a list of topics), so the descriptor names none of them",
note = "name one with `.out_retry(policy).to(\"orders\")`, or compose a publish transform \
declaring `Destination = Names`, which reads the delivery being retried and names one \
per delivery"
)]
pub trait RetryDestinationsDeclared {}
macro_rules! impl_destination_declared {
($([$($extra:tt)*] $route:ty),+ $(,)?) => {$(
impl<$($extra)*> $crate::runtime::router::RetryDestinationsDeclared for $route {}
)+};
}
pub(super) use impl_destination_declared;
impl_destination_declared!(
[S, H, Cx] SubscribeRoute<S, H, Cx>,
[S, H, Cx] BatchRoute<S, H, Cx>,
[S, H] HandleRoute<S, H>,
[Route] DeclaredRoute<Route>,
);
impl<Route, B: Broker, Cx> RetryDestinationsDeclared
for RetriedRoute<Route, B, Cx, DestinationDeclared>
{
}
impl RetryDestinationsDeclared for () {}
impl<Head, Tail> RetryDestinationsDeclared for (Head, Tail)
where
Head: RetryDestinationsDeclared,
Tail: RetryDestinationsDeclared,
{
}
#[doc(hidden)]
pub trait RouteMetadata {
fn metadata_mut(&mut self) -> &mut HandlerMetadata;
}
#[doc(hidden)]
pub struct RetriedRoute<Route, B: Broker, Cx, Settled = DestinationDeclared> {
route: Route,
retry: RetryPairing<B, Cx>,
destination: Option<Cow<'static, str>>,
named_per_delivery: bool,
_settled: PhantomData<fn() -> Settled>,
}
impl<Route, B: Broker, Cx, Settled> RetriedRoute<Route, B, Cx, Settled> {
pub(super) fn new(
route: Route,
retry: RetryPairing<B, Cx>,
destination: Option<Cow<'static, str>>,
named_per_delivery: bool,
) -> Self {
Self {
route,
retry,
destination,
named_per_delivery,
_settled: PhantomData,
}
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct DeclaredRoute<Route> {
route: Route,
declaration: RetryDeclaration,
}
impl<Route> DeclaredRoute<Route> {
pub(super) fn new(route: Route, declaration: RetryDeclaration) -> Self {
Self { route, declaration }
}
}
impl<Route: RouteMeta> RouteMeta for DeclaredRoute<Route> {
fn collect(&self, out: &mut Vec<HandlerMetadata>) {
self.route.collect(out);
}
}
impl<Route: RouteMetadata> RouteMetadata for DeclaredRoute<Route> {
fn metadata_mut(&mut self) -> &mut HandlerMetadata {
self.route.metadata_mut()
}
}
impl<Route: RetryOpen> RetryOpen for DeclaredRoute<Route> {}
impl<B: Broker, Route: RouteSubscription<B>> RouteSubscription<B> for DeclaredRoute<Route> {
type Source = Route::Source;
type Copies = Route::Copies;
type Context = Route::Context;
}
impl<B, Route, State, RetryPipeline> MountRoute<B, State, RetryPipeline> for DeclaredRoute<Route>
where
B: Broker + 'static,
Route: MountRoute<B, State, RetryPipeline>,
{
type Context = Route::Context;
fn mount_one<G, PP>(
self,
global: &G,
pipeline: &PP,
retry_pipeline: &RetryPipeline,
sink: &mut RouterSink<B, State>,
setup: RetrySetup<B, Route::Context>,
) where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
self.route.mount_one(
global,
pipeline,
retry_pipeline,
sink,
setup.with_declaration(self.declaration),
);
}
}
impl<Route: fmt::Debug, B: Broker, Cx, Settled> fmt::Debug for RetriedRoute<Route, B, Cx, Settled> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RetriedRoute")
.field("route", &self.route)
.finish_non_exhaustive()
}
}
impl<Route: RouteMeta, B: Broker, Cx, Settled> RouteMeta for RetriedRoute<Route, B, Cx, Settled> {
fn collect(&self, out: &mut Vec<HandlerMetadata>) {
self.route.collect(out);
}
}
impl<Route: RouteMetadata, B: Broker, Cx, Settled> RouteMetadata
for RetriedRoute<Route, B, Cx, Settled>
{
fn metadata_mut(&mut self) -> &mut HandlerMetadata {
self.route.metadata_mut()
}
}
impl<B, Route, State, RetryPipeline, Cx, Settled> MountRoute<B, State, RetryPipeline>
for RetriedRoute<Route, B, Cx, Settled>
where
B: Broker + 'static,
Route: MountRoute<B, State, RetryPipeline, Context = Cx>,
{
type Context = Cx;
fn mount_one<G, PP>(
self,
global: &G,
pipeline: &PP,
retry_pipeline: &RetryPipeline,
sink: &mut RouterSink<B, State>,
setup: RetrySetup<B, Cx>,
) where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
self.route.mount_one(
global,
pipeline,
retry_pipeline,
sink,
setup.with_publisher(self.retry, self.destination, self.named_per_delivery),
);
}
}
macro_rules! impl_retry_open {
($($route:ident<$($param:ident),+>),+ $(,)?) => {$(
impl<$($param),+> RetryOpen for $route<$($param),+> {}
)+};
}
impl_retry_open!(SubscribeRoute<S, H, Cx>, BatchRoute<S, H, Cx>);
macro_rules! impl_route_metadata {
($($route:ident<$($param:ident),+>),+ $(,)?) => {$(
impl<$($param),+> RouteMetadata for $route<$($param),+> {
fn metadata_mut(&mut self) -> &mut HandlerMetadata {
&mut self.meta
}
}
)+};
}
impl_route_metadata!(
SubscribeRoute<S, H, Cx>,
BatchRoute<S, H, Cx>,
HandleRoute<S, H>,
);
macro_rules! impl_route_subscription {
($($route:ident<$source:ident, $handler:ident, $context:ident>),+ $(,)?) => {$(
impl<B, $source, $handler, $context> RouteSubscription<B>
for $route<$source, $handler, $context>
where
B: Broker,
$source: SubscriptionSource<Connected<B>>,
{
type Source = $source;
type Copies = <$source as SubscriptionSource<Connected<B>>>::Copies;
type Context = $context;
}
)+};
}
impl_route_subscription!(SubscribeRoute<S, H, Cx>, BatchRoute<S, H, Cx>);
pub(super) trait RouteMeta {
fn collect(&self, out: &mut Vec<HandlerMetadata>);
}
impl<S, H, Cx> RouteMeta for SubscribeRoute<S, H, Cx> {
fn collect(&self, out: &mut Vec<HandlerMetadata>) {
out.push(self.meta.clone());
}
}
impl<S, H, Cx> RouteMeta for BatchRoute<S, H, Cx> {
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, Cx, State, RetryPipeline> MountRoute<B, State, RetryPipeline>
for SubscribeRoute<S, H, Cx>
where
B: Broker + 'static,
S: SubscriptionSource<Connected<B>> + Send + 'static,
S::Subscriber: Send + 'static,
S::Copies: CopyPathPairing<B, Cx, RetryPipeline> + CopyPathAddress<Connected<B>, S>,
SourceMessage<B, S>: Send + Sync + 'static,
Cx: BuildContext<SourceMessage<B, S>> + Send + Sync + 'static,
State: Send + Sync + 'static,
H: Handler<SourceMessage<B, S>, Cx, State> + 'static,
RetryPipeline: Clone,
{
type Context = Cx;
fn mount_one<G, PP>(
self,
global: &G,
_pipeline: &PP,
retry_pipeline: &RetryPipeline,
sink: &mut RouterSink<B, State>,
setup: RetrySetup<B, Cx>,
) where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
let handler = global.apply::<SourceMessage<B, S>, Cx, State, H>(self.handler);
let mut meta = self.meta;
let setup = setup.resolve::<S::Copies, _>(retry_pipeline, &mut meta);
sink.push_subscribe_workers(
self.source,
handler,
meta,
self.policies,
self.workers,
setup,
);
}
}
impl<B, S, H, Cx, State, RetryPipeline> MountRoute<B, State, RetryPipeline> for BatchRoute<S, H, Cx>
where
B: Broker + 'static,
S: SubscriptionSource<Connected<B>> + Send + 'static,
S::Subscriber: BatchSubscriber + Send + 'static,
S::Copies: CopyPathPairing<B, Cx, RetryPipeline> + CopyPathAddress<Connected<B>, S>,
SourceMessage<B, S>: Send + 'static,
Cx: crate::BuildBatchContext<SourceMessage<B, S>> + Send + Sync + 'static,
State: Send + Sync + 'static,
H: BatchHandler<SourceMessage<B, S>, Cx, State> + 'static,
RetryPipeline: Clone,
{
type Context = Cx;
fn mount_one<G, PP>(
self,
_global: &G,
_pipeline: &PP,
retry_pipeline: &RetryPipeline,
sink: &mut RouterSink<B, State>,
setup: RetrySetup<B, Cx>,
) where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
let mut meta = self.meta;
let setup = setup.resolve::<S::Copies, _>(retry_pipeline, &mut meta);
sink.push_subscribe_batch::<_, _, Cx>(
self.source,
self.handler,
meta,
self.policies,
self.workers,
self.batch_size,
setup,
);
}
}
impl<B, S, H, State, RetryPipeline> MountRoute<B, State, RetryPipeline> 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,
{
type Context = ();
fn mount_one<G, PP>(
self,
global: &G,
_pipeline: &PP,
_retry_pipeline: &RetryPipeline,
sink: &mut RouterSink<B, State>,
_setup: RetrySetup<B, ()>,
) 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);
}
}
pub trait RouterDef<B: Broker, State = (), RetryPipeline = PublishIdentity> {
#[doc(hidden)]
fn mount<G, PP>(
self,
global: &G,
pipeline: &PP,
retry_pipeline: &RetryPipeline,
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, RetryPipeline> RouterDef<B, State, RetryPipeline> for () {
fn mount<G, PP>(
self,
_global: &G,
_pipeline: &PP,
_retry_pipeline: &RetryPipeline,
_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, RetryPipeline> RouterDef<B, State, RetryPipeline> for (Head, Tail)
where
B: Broker + 'static,
Head: MountRoute<B, State, RetryPipeline>,
Tail: RouterDef<B, State, RetryPipeline>,
{
fn mount<G, PP>(
self,
global: &G,
pipeline: &PP,
retry_pipeline: &RetryPipeline,
sink: &mut RouterSink<B, State>,
) where
G: BlanketLayer + Clone + Send + Sync + 'static,
PP: PublishPipeline + Clone + Send + 'static,
{
self.1.mount(global, pipeline, retry_pipeline, sink);
self.0.mount_one(
global,
pipeline,
retry_pipeline,
sink,
RetrySetup::default(),
);
}
}
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);
}
}