extension_api 0.0.8

自定义wasm plugin 扩展api
Documentation
use std::sync::{Mutex, MutexGuard};

use wit::{PluginInput, PluginOutput};

pub mod http_client;

/// extension Result
pub type Result<T, E = String> = core::result::Result<T, E>;

pub trait Plugin: Send + Sync {
    fn new() -> Self
    where
        Self: Sized;
    /// 执行插件
    fn run_plugin(&self, input: PluginInput) -> Result<PluginOutput, String>;
}

static PLUGIN: Mutex<Option<Box<dyn Plugin>>> = Mutex::new(None);

#[allow(dead_code)]
#[doc(hidden)]
const WORKOSS_API_VERSION: &[u8] = {
    let version = concat!(env!("CARGO_PKG_VERSION"));
    version.as_bytes()
};

#[cfg(all(target_os = "wasi", target_env = "p2"))]
#[unsafe(link_section = "workoss:api-version")]
#[doc(hidden)]
pub static WORKOSS_API_VERSION_SECTION: [u8; WORKOSS_API_VERSION.len()] = {
    let mut arr = [0u8; WORKOSS_API_VERSION.len()];
    let mut i = 0;
    while i < WORKOSS_API_VERSION.len() {
        arr[i] = WORKOSS_API_VERSION[i];
        i += 1;
    }
    arr
};

#[macro_export]
macro_rules! register_plugin {
    ($plugin_type:ty) => {
        #[doc(hidden)]
        const WORKOSS_API_SCHEMA: &[u8] = {
            let schema = concat!(
                "id::",
                env!("CARGO_PKG_NAME"),
                "\nname::",
                env!("CARGO_PKG_NAME"),
                "\nversion::",
                env!("CARGO_PKG_VERSION"),
                "\ndescription::",
                env!("CARGO_PKG_DESCRIPTION"),
                "\nrepository::",
                env!("CARGO_PKG_REPOSITORY"),
                "\nauthors::",
                env!("CARGO_PKG_AUTHORS"),
            );
            schema.as_bytes()
        };

        #[cfg(all(target_os = "wasi", target_env = "p2"))]
        #[unsafe(link_section = "workoss:api-schema")]
        #[doc(hidden)]
        pub static WORKOSS_API_SCHEMA_SECTION: [u8; WORKOSS_API_SCHEMA.len()] = {
            let mut arr = [0u8; WORKOSS_API_SCHEMA.len()];
            let mut i = 0;
            while i < WORKOSS_API_SCHEMA.len() {
                arr[i] = WORKOSS_API_SCHEMA[i];
                i += 1;
            }
            arr
        };

        #[unsafe(export_name = "init-plugin")]
        pub extern "C" fn __init_plugin() {
            //default /  No such file or directory
            // std::env::set_current_dir(std::env::var("PWD").unwrap_or_default()).unwrap();
            let load_result = extension_api::load_plugin(|| {
                Box::new(<$plugin_type as extension_api::Plugin>::new())
            });
            if load_result.is_err() {
                panic!("{}", load_result.unwrap_err());
            }
        }
    };
}

pub fn load_plugin(build_plugin: fn() -> Box<dyn Plugin>) -> Result<(), String> {
    let mut binding = PLUGIN.lock();
    let plugin = binding.as_mut();
    if let Ok(p) = plugin {
        **p = Some((build_plugin)());
    } else {
        return Err("Fail to register plugin".to_string());
    }
    Ok(())
}

fn plugin<'a>() -> Result<MutexGuard<'a, Option<Box<dyn Plugin>>>, String> {
    let plugin = PLUGIN.lock();
    if let Ok(p) = plugin {
        Ok(p)
    } else {
        Err("Failed to get plugin".to_string())
    }
}

pub mod wit {
    wit_bindgen::generate!({
        path: "./wit",
        world: "extension",
        skip: ["init-plugin"],
    });

    use super::Component;
    export!(Component);
}

struct Component;

impl wit::Guest for Component {
    #[doc = " 执行扩展"]
    fn run_plugin(input: PluginInput) -> Result<PluginOutput, String> {
        let plugin = plugin();
        if let Ok(p) = plugin {
            return p.as_ref().unwrap().run_plugin(input);
        }
        Err("get plugin error".to_string())
    }
}