use std::any::Any;
use dactor::{
Disposition, HandlerWrapper, Headers, InboundContext, InboundInterceptor, Outcome,
RuntimeHeaders,
};
use dcontext::ContextFutureExt;
use crate::header::{ContextHeader, ContextSnapshotHeader};
use crate::propagation::bytes_to_snapshot;
use crate::ErrorPolicy;
#[derive(Default)]
pub struct ContextInboundInterceptor {
error_policy: ErrorPolicy,
}
impl ContextInboundInterceptor {
pub fn new(error_policy: ErrorPolicy) -> Self {
Self { error_policy }
}
}
impl InboundInterceptor for ContextInboundInterceptor {
fn name(&self) -> &'static str {
"dcontext-inbound"
}
fn on_receive(
&self,
_ctx: &InboundContext<'_>,
_runtime_headers: &RuntimeHeaders,
headers: &mut Headers,
_message: &dyn Any,
) -> Disposition {
if headers.get::<ContextSnapshotHeader>().is_some() {
return Disposition::Continue;
}
if let Some(wire_header) = headers.get::<ContextHeader>() {
let bytes = &wire_header.bytes;
match bytes_to_snapshot(bytes) {
Some(snap) => {
headers.insert(ContextSnapshotHeader { snapshot: snap });
}
None => {
tracing::warn!(
target: "dcontext_dactor",
"failed to deserialize dcontext from inbound wire bytes"
);
if self.error_policy == ErrorPolicy::Reject {
return Disposition::Reject(
"dcontext deserialization failed: corrupt wire bytes".into(),
);
}
}
}
}
Disposition::Continue
}
fn wrap_handler<'a>(
&'a self,
ctx: &InboundContext<'_>,
headers: &Headers,
) -> Option<HandlerWrapper<'a>> {
let snapshot = headers.get::<ContextSnapshotHeader>()?.snapshot.clone();
let scope_name = format!("remote:{}", ctx.actor_name);
Some(Box::new(move |next| {
Box::pin(async move {
let scoped_snapshot = async move {
let _scope = dcontext::push_scope(&scope_name);
dcontext::capture()
}
.attach(snapshot)
.await;
next.attach(scoped_snapshot).await
})
}))
}
fn on_complete(
&self,
_ctx: &InboundContext<'_>,
_runtime_headers: &RuntimeHeaders,
_headers: &Headers,
_outcome: &Outcome<'_>,
) {
}
}