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 datagram_safe(&self) -> bool { ... }
}
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 datagram_safe as false. 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 datagram_safe(&self) -> bool

Whether this stage may sit on a path carrying datagrams.

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.

Ctx::boundary makes the second of those sayable rather than silent: a stage that emits several units emits several messages. That is still a rewrite of the peer’s message stream rather than a preservation of it, so a stage doing it should say false here and let the host decide whether to warn.

Defaults to false because that is the safe answer for a stage that has not thought about it, including any plugin loaded from outside this binary. A pure observer that only calls pass_through can say true; anything holding state across calls should not.

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§