#[macro_export]
macro_rules! log_error {
($ctx:expr, $($arg:tt)*) => {
$ctx.log_error(&format!($($arg)*))
};
}
#[macro_export]
macro_rules! log_warn {
($ctx:expr, $($arg:tt)*) => {
$ctx.log_warn(&format!($($arg)*))
};
}
#[macro_export]
macro_rules! log_info {
($ctx:expr, $($arg:tt)*) => {
$ctx.log_info(&format!($($arg)*))
};
}
#[macro_export]
macro_rules! log_debug {
($ctx:expr, $($arg:tt)*) => {
$ctx.log_debug(&format!($($arg)*))
};
}
#[macro_export]
macro_rules! log_trace {
($ctx:expr, $($arg:tt)*) => {
$ctx.log_trace(&format!($($arg)*))
};
}
#[macro_export]
macro_rules! export_wasm {
($plugin_type:ty) => {
static PLUGIN: std::sync::LazyLock<$plugin_type> =
std::sync::LazyLock::new(|| <$plugin_type>::new());
#[unsafe(no_mangle)]
pub extern "C" fn aiway_dealloc(ptr: i32, size: i32) {
let layout = std::alloc::Layout::from_size_align(size as usize, 1).unwrap();
unsafe {
std::alloc::dealloc(ptr as *mut u8, layout);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn plugin_info() -> i64 {
let info = aiway_plugin::wasm_types::WasmPluginInfo {
name: PLUGIN.name().to_string(),
version: PLUGIN.info().version.to_string(),
description: PLUGIN.info().description.clone(),
default_config: aiway_plugin::serde_json::to_string(&PLUGIN.info().default_config)
.unwrap_or_default(),
readme: PLUGIN.info().readme.clone(),
};
let bytes = $crate::bincode::serialize(&info).unwrap();
let len = bytes.len();
let ptr = bytes.as_ptr() as i32;
std::mem::forget(bytes);
((ptr as i64) << 32) | (len as i64)
}
#[unsafe(no_mangle)]
pub extern "C" fn aiway_call(hook_id: i32) -> i64 {
let result: Result<aiway_plugin::Outcome, String> = match hook_id {
aiway_plugin::wasm_types::HOOK_ON_REQUEST => handle_on_request(&PLUGIN),
aiway_plugin::wasm_types::HOOK_ON_REQUEST_BODY => handle_on_request_body(&PLUGIN),
aiway_plugin::wasm_types::HOOK_ON_RESPONSE => handle_on_response(&PLUGIN),
aiway_plugin::wasm_types::HOOK_ON_RESPONSE_BODY => handle_on_response_body(&PLUGIN),
aiway_plugin::wasm_types::HOOK_ON_LOGGING => handle_on_logging(&PLUGIN),
_ => Err(format!("unknown hook_id: {}", hook_id)),
};
match result {
Ok(outcome) => encode_outcome(&outcome),
Err(err_msg) => encode_error(&err_msg),
}
}
fn encode_outcome(outcome: &aiway_plugin::Outcome) -> i64 {
match outcome {
aiway_plugin::Outcome::Continue => {
aiway_plugin::wasm_types::HookControl::Continue as i64
}
aiway_plugin::Outcome::Respond(resp) => {
aiway_plugin::respond_to_host(
resp.status,
resp.headers.clone(),
resp.body.clone(),
);
aiway_plugin::wasm_types::HookControl::Respond as i64
}
}
}
fn encode_error(msg: &str) -> i64 {
let bytes = msg.as_bytes();
let dst = unsafe {
std::slice::from_raw_parts_mut(
aiway_plugin::wasm_types::ERROR_BUF_PTR as *mut u8,
bytes.len(),
)
};
dst.copy_from_slice(bytes);
(1i64 << 32) | (bytes.len() as i64)
}
fn encode_plugin_error(e: aiway_plugin::PluginError) -> String {
format!("{}", e)
}
fn handle_on_request(plugin: &$plugin_type) -> Result<aiway_plugin::Outcome, String> {
let mut ctx = aiway_plugin::WasmHttpContext;
aiway_plugin::block_on(async { plugin.on_request(&mut ctx).await })
.map_err(encode_plugin_error)
}
fn handle_on_request_body(plugin: &$plugin_type) -> Result<aiway_plugin::Outcome, String> {
let mut ctx = aiway_plugin::WasmHttpContext;
aiway_plugin::block_on(async { plugin.on_request_body(&mut ctx).await })
.map_err(encode_plugin_error)
}
fn handle_on_response(plugin: &$plugin_type) -> Result<aiway_plugin::Outcome, String> {
let mut ctx = aiway_plugin::WasmHttpContext;
aiway_plugin::block_on(async { plugin.on_response(&mut ctx).await })
.map_err(encode_plugin_error)
}
fn handle_on_response_body(plugin: &$plugin_type) -> Result<aiway_plugin::Outcome, String> {
let mut ctx = aiway_plugin::WasmHttpContext;
aiway_plugin::block_on(async { plugin.on_response_body(&mut ctx).await })
.map_err(encode_plugin_error)
}
fn handle_on_logging(plugin: &$plugin_type) -> Result<aiway_plugin::Outcome, String> {
let mut ctx = aiway_plugin::WasmHttpContext;
aiway_plugin::block_on(async {
plugin.on_logging(&mut ctx).await;
});
Ok(aiway_plugin::Outcome::Continue)
}
};
}