Skip to main content

Plugin

Trait Plugin 

Source
pub trait Plugin: Send {
    // Required methods
    fn name(&self) -> &str;
    fn on_bytes(&mut self, ctx: &mut Ctx<'_>, input: &[u8]) -> Result<()>;

    // Provided methods
    fn on_eof(&mut self, ctx: &mut Ctx<'_>) -> Result<()> { ... }
    fn tick_interval(&self) -> Option<Duration> { ... }
    fn on_tick(&mut self, ctx: &mut Ctx<'_>) -> Result<()> { ... }
    fn boundaries(&self) -> Boundaries { ... }
    fn needs(&self) -> Needs { ... }
}
Expand description

One stage of a pipeline. Instances are per-direction and per-connection.

Synchronous on purpose: it is the only shape that maps onto a WASM guest call, and it keeps the per-chunk cost at a function call rather than a future poll. Anything that must await belongs on the effect side, where the host performs it off the critical path.

Required Methods§

Source

fn name(&self) -> &str

The name of the plugin

Source

fn on_bytes(&mut self, ctx: &mut Ctx<'_>, input: &[u8]) -> Result<()>

A chunk arrived from upstream. input is the same slice as Ctx::input; it is passed separately because it is the hot argument.

One call is one unit. Where a stage above declared framing with Ctx::boundary that is one call per unit rather than one per chunk, so a stage never has to unpick two of them from a single slice.

Provided Methods§

Source

fn on_eof(&mut self, ctx: &mut Ctx<'_>) -> Result<()>

Upstream reached EOF. Last chance to emit buffered bytes.

Source

fn tick_interval(&self) -> Option<Duration>

How often this stage wants on_tick called, or None (the default) for never.

Read once, at the end of construction, so it must not depend on anything that changes later. A stage whose interval is configurable reads its config in PluginFactory::build and answers from that.

The host owns the clock. A guest cannot read one (a WASM module has no way to reach the host’s time) which is why this is a period the stage asks for rather than a timestamp it checks. The cost falls on the relay: one timer per direction per connection for any pipeline containing a ticking stage, so a stage asking for milliseconds is asking every forked connection to wake up that often.

Source

fn on_tick(&mut self, ctx: &mut Ctx<'_>) -> Result<()>

The stage’s schedule came due.

Called from the same task, and under the same rules, as on_bytes, it just arrives without any. This is how a stage does anything that time rather than traffic should drive: report a measurement, release bytes it has been holding back, emit a keepalive. Without it a stalled stream and a finished one are indistinguishable from inside a plugin.

Ctx::input is empty, so there is nothing to pass through; anything emitted here is emitted with Ctx::forward and continues downstream through the stages below this one, in the same way on_eof cascades. Emitting nothing is the common case and costs nothing.

A stage that emits from here is fabricating a message boundary on a datagram path (the bytes belong to no datagram the peer sent) so it should report Boundaries::Fuse from boundaries. A stage that only observes need not.

What is emitted here is one unit unless Ctx::boundary says otherwise, exactly as in on_bytes.

Ticks run for the life of the pipeline and stop at end of stream, so they arrive whether or not anything is moving, which is the point, and is what a keepalive needs. A stage that has nothing to say until the first chunk has arrived is expected to keep that state itself.

Source

fn boundaries(&self) -> Boundaries

What this stage does to the message boundaries passing through it.

On a byte stream a chunk is an arbitrary slice: a stage may buffer, split or coalesce freely, and the host is free to do the same. On a datagram path the chunk is the message: one on_bytes call per datagram, and whatever it emits is sent as exactly one datagram. A stage that buffers across calls, or emits two messages’ worth from one, silently corrupts the protocol unless it says so here.

The four answers, in the order a stage usually wants them:

  • Preserve: one unit in, one unit out. Every observer, and every codec that rewrites a message in place.
  • Fuse: the units are gone below this stage. Anything that buffers across calls, splits, coalesces, or emits from a tick.
  • Seal: as Preserve, and the boundary is also written into the payload, so it outlives a stage below that fuses. frame and nothing else.
  • Split: the units below are read out of the bytes rather than inherited, so the ones from above do not survive. unframe and nothing else.

Defaults to Fuse because that is the answer that claims nothing, which is the safe one for a stage that has not thought about it, including any plugin loaded from outside this binary.

Declaring the truth matters more than declaring safety. block fuses and says so, and it is still the right stage to reach for when one datagram per 1400 bytes is exactly what was wanted: the host warns and relays anyway.

Source

fn needs(&self) -> Needs

What this stage needs of the path it was placed on.

Unlike boundaries, which the host only warns about, an unmet requirement is a build error: a stage saying this cannot do its job at all where it was put.

Upstream means every call must carry one whole message, so boundaries have to arrive from a datagram endpoint or from an unframe. Downstream means the units this stage emits have to reach a datagram endpoint or a frame, or what it wrote cannot be read back. The two are separate because the stages that want them want opposite ones: a stage that seals a message and appends a tag makes its own boundaries and needs them to survive downwards, while the stage that verifies and strips that tag needs whole messages from above and does not care what happens below it.

Read once, after build, alongside boundaries. Neither is consulted on the per-chunk path.

Trait Implementations§

Source§

impl From<Box<dyn Plugin>> for Stage

Source§

fn from(plugin: Box<dyn Plugin>) -> Self

Converts to this type from the input type.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§