Skip to main content

Module plugin

Module plugin 

Source
Expand description

Trait-based plugin API, inspired by Pingora’s ProxyHttp/CTX design: implement Plugin on a struct and export it with export_plugin! — no raw pointers, no unsafe handlers, panics contained at the ABI boundary.

Two kinds of state, exactly like Pingora:

  • Per-call state lives in Plugin::Ctx, created fresh by Plugin::new_ctx for every incoming call and dropped when the call ends.
  • Cross-call state lives on the plugin struct itself: one instance serves every call concurrently, so plain fields with Atomic*, Mutex, or anything Sync work like Pingora’s service struct.
use nylon_ring::{export_plugin, NrStatus, Plugin, Reply, Session};
use std::sync::atomic::{AtomicU64, Ordering};

struct Demo {
    // cross-call state, shared by every call
    calls: AtomicU64,
}

struct DemoCtx {
    // per-call state (Pingora-style CTX)
    uppercase: bool,
}

impl Plugin for Demo {
    type Ctx = DemoCtx;
    const ENTRIES: &'static [&'static str] = &["echo", "shout"];

    fn new() -> Self {
        Demo { calls: AtomicU64::new(0) }
    }

    fn new_ctx(&self) -> DemoCtx {
        DemoCtx { uppercase: false }
    }

    fn on_call(&self, session: &mut Session<'_>, ctx: &mut DemoCtx) -> Reply {
        self.calls.fetch_add(1, Ordering::Relaxed);
        match session.entry() {
            "echo" => Reply::Bytes(session.payload().to_vec()),
            "shout" => {
                ctx.uppercase = true;
                let text = String::from_utf8_lossy(session.payload()).to_string();
                Reply::Text(if ctx.uppercase { text.to_uppercase() } else { text })
            }
            _ => Reply::Fail(NrStatus::Invalid),
        }
    }
}

export_plugin!(Demo);

Entries listed in Plugin::ASYNC_ENTRIES dispatch to Plugin::on_async_call instead — a native async handler (no async_trait crate needed). The ABI callback returns immediately and the reply is delivered when the future completes, through the host’s cross-thread async path. Futures run via Plugin::spawn_async: dependency-free thread-per-call by default, or override it with tokio::spawn (or any executor) for real workloads.

The raw define_plugin! macro remains available for handlers that need full control over the ABI (owned responses, buffer leases); the safe host-call helpers in this module (send_result, send_result_owned, acquire_result_buffer, commit_result_buffer) can be mixed into either style.

Structs§

AsyncSession
One incoming async call: like Session but self-contained — the payload is copied out of host memory so the future may outlive the ABI callback that created it.
Session
One incoming call: the entry it targets, its payload, and the session id for manual (streaming) replies.

Enums§

Reply
What a Plugin::on_call handler answers with.

Traits§

Plugin
A nylon-ring plugin. Implement this and export it with export_plugin!; see the module docs for the state model.

Functions§

acquire_result_buffer
Leases a host-owned response buffer for sid; check NrBufferLease::is_failed before writing.
commit_result_buffer
Commits a leased buffer as the response for sid.
send_result
Sends a response or stream frame for sid through the host’s send_result. Borrowed payloads (owned = 0) are copied by the host before this returns. Reports Invalid when the plugin has not been initialized.
send_result_owned
Sends a response the host consumes without copying; the host takes ownership and calls the payload’s release exactly once.

Type Aliases§

AsyncTask
A boxed future handed to Plugin::spawn_async; drive it to completion to deliver the call’s reply.