use std::pin::Pin;
use std::sync::Arc;
use ruststream::memory::MemoryMessage;
use ruststream::memory::prelude::*;
use ruststream::runtime::{
BlanketLayer, DynMiddleware, DynStack, Handler, Identity, Layer, Next, Stack,
};
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Order {
id: u64,
}
#[subscriber("orders")]
async fn handle(order: &Order) -> HandlerOutcome {
println!("got order {}", order.id);
HandlerOutcome::ack()
}
#[subscriber("returns")]
async fn returns(order: &Order) -> HandlerOutcome {
println!("got return for order {}", order.id);
HandlerOutcome::ack()
}
#[derive(Clone)]
struct LogLayer;
struct Logged<H>(H);
impl<H> Layer<H> for LogLayer {
type Handler = Logged<H>;
fn layer(&self, inner: H) -> Logged<H> {
Logged(inner)
}
}
impl<M: Send + Sync, C: Send, S: Send + Sync, H: Handler<M, C, S>> Handler<M, C, S> for Logged<H> {
async fn handle(&self, msg: &M, ctx: &mut Context<'_, C, S>) -> HandlerOutcome {
println!("-> {}", ctx.name());
let outcome = self.0.handle(msg, ctx).await;
println!("<- {}", ctx.name());
outcome
}
}
impl BlanketLayer for LogLayer {
fn apply<M, C, S, H>(&self, handler: H) -> impl Handler<M, C, S> + 'static
where
M: Send + Sync + 'static,
C: Send + 'static,
S: Send + Sync + 'static,
H: Handler<M, C, S> + 'static,
{
Logged(handler)
}
}
struct Audit {
service: String,
}
impl<I: Send + Sync> DynMiddleware<I> for Audit {
fn handle<'a>(
&'a self,
input: &'a I,
ctx: &'a mut Context<'_>,
next: Next<'a, I>,
) -> Pin<Box<dyn Future<Output = HandlerOutcome> + Send + 'a>> {
Box::pin(async move {
println!("[{}] handling {}", self.service, ctx.name());
next.run(input, ctx).await
})
}
}
#[ruststream::app]
fn app() -> RustStream<Stack<LogLayer, Identity>> {
let audit_enabled = std::env::var("AUDIT").is_ok();
let info = AppInfo::new("middleware", "0.1.0");
let mut middleware: Vec<Arc<dyn DynMiddleware<MemoryMessage>>> = Vec::new();
if audit_enabled {
middleware.push(Arc::new(Audit {
service: "orders".to_owned(),
}));
}
let stack = DynStack::new(middleware);
RustStream::new(info)
.layer(LogLayer)
.with_broker(MemoryBroker::new(), |b| {
b.include(handle);
b.include_router(Router::<MemoryBroker>::new().include(returns).layer(stack));
})
}