pub struct PushSender { /* private fields */ }Expand description
Delivers notifications, under the controls in the module docs.
Implementations§
Source§impl PushSender
impl PushSender
Sourcepub const DEFAULT_TIMEOUT: Duration
pub const DEFAULT_TIMEOUT: Duration
The spec recommends 10–30 seconds; a webhook that needs longer is doing work it should not be doing on our thread.
pub fn new(policy: PushPolicy) -> Self
Sourcepub fn for_operator_destinations(destinations: &[Destination]) -> Self
pub fn for_operator_destinations(destinations: &[Destination]) -> Self
A sender for destinations the deployment configured.
Takes no PushPolicy, because a host allowlist answers may this
caller name this host? and there is no caller: the URL comes from the
deployment’s own configuration, written by whoever would have written the
allowlist. HTTPS and the public-address check are lifted for the same
reason — an in-cluster collector on plaintext HTTP at a private address
is the ordinary shape here, and it is the only shape the inward-facing
case has.
This is not an off switch for push. It cannot deliver to a
caller-registered webhook at all: Outbox owns the rows this serves,
the A2A worker owns the others, and the two id namespaces do not overlap.
§Why it takes the destinations
For the signing keys of whichever of them called
Destination::signed_with, which live here and not in the stored
registration: a caller’s bearer token has to be persisted because the
request that carried it is over, while an operator’s signing key is this
deployment’s own configuration, read at every start — persisting it
would put a forge-anything key in a row per run per destination and
freeze rotation at admission. Taking
them as an argument rather than offering a .signing(..) setter is the
difference between a control you can forget and one you cannot: a
destination configured to be signed whose sender was built without it
would deliver unsigned, and nothing downstream could notice, because a
receiver’s own refusal is the only place a missing signature shows up.
Pass Outbox::destinations, which is the list that was actually
registered.
Sourcepub const fn allow_plaintext_loopback(self) -> Self
pub const fn allow_plaintext_loopback(self) -> Self
Permit http:// to a webhook on this machine. testkit only.
The A2A conformance kit’s webhook receiver is an http://localhost:PORT
server, because a kit cannot mint a public TLS endpoint for a run on a
laptop. Both of this crate’s address controls refuse that, correctly —
and the consequence was that the kit’s ten push MUSTs could not run at
all, so the one surface where an untrusted party names an address this
plane connects to had no outside-authority evidence behind it. Ten
unrunnable rows is a worse answer than one named exception.
What this does not lift is the part that is the actual control: the operator’s host grant still has to name the host, the task-level authorization still runs, the cursor still advances only on 2xx, and every non-loopback destination is judged exactly as before — a plaintext URL to a public host stays refused with the flag set, which is the half that keeps this from being an off switch.
It cannot exist in a production build: the field is cfg(testkit), and
testkit is documented as never belonging in one.
pub const fn timeout(self, d: Duration) -> Self
Sourcepub const fn policy(&self) -> &PushPolicy
pub const fn policy(&self) -> &PushPolicy
The grant this sender enforces, so a registration can be checked against the same policy that will later be checked at delivery.
Trait Implementations§
Source§impl Clone for PushSender
impl Clone for PushSender
Source§impl Debug for PushSender
impl Debug for PushSender
Source§impl PushTransport for PushSender
impl PushTransport for PushSender
fn validate(&self, config: &PushConfig) -> Result<(), PushError>
Source§fn deliver<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
config: &'life1 PushConfig,
message: &'life2 PushMessage,
at: u64,
) -> Pin<Box<dyn Future<Output = Result<Delivered, PushError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn deliver<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
config: &'life1 PushConfig,
message: &'life2 PushMessage,
at: u64,
) -> Pin<Box<dyn Future<Output = Result<Delivered, PushError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Auto Trait Implementations§
impl !Freeze for PushSender
impl !RefUnwindSafe for PushSender
impl !UnwindSafe for PushSender
impl Send for PushSender
impl Sync for PushSender
impl Unpin for PushSender
impl UnsafeUnpin for PushSender
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more