use std::{error::Error as StdError, fmt, future::Future, sync::Arc};
use crate::{Broker, Connected, Subscriber};
use crate::PublishPolicy;
use crate::runtime::failure::FailurePolicies;
use crate::runtime::handler::Handler;
use crate::runtime::lifecycle::ConnectedSlot;
use crate::runtime::metadata::HandlerMetadata;
use crate::runtime::middleware::{BlanketLayer, Identity};
use crate::runtime::publish::{PublishIdentity, PublishPipeline};
use crate::runtime::router::{RouterDef, RouterSink};
use super::{LifecycleHook, lifecycle_hooks::box_startup_publish};
pub struct BrokerScope<B: Broker, Layers = Identity, C = (), State = (), Pipeline = PublishIdentity>
{
pub(super) broker: B,
pub(super) slot: ConnectedSlot<B>,
pub(super) startup_hooks: Vec<LifecycleHook<State>>,
pub(super) sink: RouterSink<B, State>,
pub(super) pipeline: Pipeline,
pub(super) global: Layers,
pub(super) codec: C,
}
impl<B: Broker + 'static, Layers, C, State, Pipeline> BrokerScope<B, Layers, C, State, Pipeline> {
#[must_use]
pub fn broker(&self) -> &B {
&self.broker
}
pub fn after_startup<Source, Hook, Fut, E>(&mut self, source: Source, hook: Hook)
where
Source: PublishPolicy<Connected<B>> + Send + 'static,
Source::Live: Send,
Hook: FnOnce(Source::Live) -> Fut + Send + 'static,
Fut: Future<Output = Result<(), E>> + Send + 'static,
E: StdError + Send + Sync + 'static,
B: 'static,
{
self.startup_hooks
.push(box_startup_publish::<B, State, Source, Hook, Fut, E>(
Arc::clone(&self.slot),
source,
hook,
));
}
pub fn handle<S, H, Cx>(&mut self, subscriber: S, handler: H, meta: HandlerMetadata)
where
S: Subscriber + Send + 'static,
S::Message: Send + Sync + 'static,
State: Send + Sync + 'static,
Cx: crate::BuildContext<S::Message> + Send + Sync + 'static,
H: Handler<S::Message, Cx, State> + 'static,
Layers: BlanketLayer + Clone + Send + Sync + 'static,
{
let handler = self.global.apply::<S::Message, Cx, State, H>(handler);
self.sink
.push_handle(subscriber, handler, meta, FailurePolicies::default());
}
pub fn include_router<R>(&mut self, router: R)
where
R: RouterDef<B, State>,
State: Send + Sync + 'static,
Layers: BlanketLayer + Clone + Send + Sync + 'static,
Pipeline: PublishPipeline + Clone + Send + 'static,
{
router.mount(
&self.global,
&self.pipeline,
&PublishIdentity,
&mut self.sink,
);
}
}
impl<B: Broker, Layers, C, State, Pipeline> fmt::Debug
for BrokerScope<B, Layers, C, State, Pipeline>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BrokerScope")
.field("sink", &self.sink)
.finish_non_exhaustive()
}
}
#[cfg(all(test, feature = "memory"))]
mod tests {
use crate::memory::MemoryBroker;
use crate::runtime::{AppInfo, RustStream};
#[test]
fn scope_debug_reports_its_registrations() {
let _app =
RustStream::new(AppInfo::new("dbg", "0.1.0")).with_broker(MemoryBroker::new(), |b| {
let rendered = format!("{b:?}");
assert!(rendered.starts_with("BrokerScope"), "{rendered}");
assert!(rendered.contains("sink"), "{rendered}");
});
}
}