Skip to content

Native Plugins & Advanced FFI

In addition to external crates, you can write custom native Rust code inside your project and call it directly from Flame with zero runtime overhead.


Building a Custom Plugin: Axum + Tokio Web Server

Section titled “Building a Custom Plugin: Axum + Tokio Web Server”
  1. Create a native folder containing native/Cargo.toml and native/src/lib.rs:

    native/Cargo.toml
    [package]
    name = "server"
    version = "0.1.0"
    edition = "2021"
    [dependencies]
    axum = "0.7"
    tokio = { version = "1.0", features = ["full"] }
    flame-macro = "0.1.0"
  2. native/src/lib.rs
    use axum::{
    routing::{get, post},
    Router,
    };
    use flame_macro::flame;
    use std::mem;
    use std::net::SocketAddr;
    pub struct FlameServer {
    router: Router,
    }
    #[derive(Debug, Clone)]
    pub struct Request {
    pub body: String,
    }
    #[derive(Debug, Clone)]
    pub struct Response {
    pub body: String,
    }
    // Module-level function
    /// Initialize a new FlameServer instance.
    pub fn init() -> FlameServer {
    FlameServer {
    router: Router::new(),
    }
    }
    impl FlameServer {
    pub fn get<H, T>(&mut self, path: &'static str, handler: H)
    where
    H: axum::handler::Handler<T, ()> + Clone + Send + Sync + 'static,
    T: 'static,
    {
    let router = mem::take(&mut self.router);
    self.router = router.route(path, get(handler));
    }
    pub fn post<H, T>(&mut self, path: &'static str, handler: H)
    where
    H: axum::handler::Handler<T, ()> + Clone + Send + Sync + 'static,
    T: 'static,
    {
    let router = mem::take(&mut self.router);
    self.router = router.route(path, post(handler));
    }
    pub fn router(&mut self) -> Router {
    mem::take(&mut self.router)
    }
    #[flame(daemon)]
    pub async fn listen(self, port: u16) -> std::io::Result<()> {
    let addr = SocketAddr::from(([127, 0, 0, 1], port));
    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, self.router)
    .await
    .map_err(std::io::Error::other)
    }
    }
  3. [plugins]
    server = "./native"
  4. import native.flamer
    let app = flamer.init()
    fn main() -> String {
    "hello"
    }
    app.get("/", main)
    print("Server started!")
    app.listen(3000)