#![allow(missing_docs)]
pub mod interface;
pub mod net;
pub mod nitro;
pub mod output;
pub mod sys;
pub mod util;
use anyhow::{Context, bail};
use serde::de::DeserializeOwned;
use crate::hook::Hook;
pub use interface::Guest;
pub use interface::export;
static mut HOOK_RESULT: String = String::new();
#[macro_export]
macro_rules! nitro_wasm_plugin {
($func:ident, $id: literal) => {
struct ExportedWASMPlugin;
impl $crate::api::wasm::Guest for ExportedWASMPlugin {
fn run_plugin(hook: String, arg: String, hook_version: u32) -> u32 {
let mut plugin = $crate::api::wasm::WASMPlugin {
id: $id.to_string(),
hook: hook.to_string(),
arg: arg.to_string(),
hook_version,
};
let result = $func(&mut plugin);
if let Err(e) = result {
unsafe {
$crate::api::wasm::_set_hook_result(format!("{e:?}"));
}
1
} else {
0
}
}
fn get_result() -> String {
unsafe { $crate::api::wasm::_get_hook_result() }
}
}
$crate::api::wasm::export!(ExportedWASMPlugin with_types_in $crate::api::wasm::interface);
};
}
pub struct WASMPlugin {
pub id: String,
pub hook: String,
pub arg: String,
pub hook_version: u32,
}
impl WASMPlugin {
pub(crate) fn handle_hook<H: Hook>(
&mut self,
arg: impl FnOnce(&Self) -> anyhow::Result<H::Arg>,
f: impl FnOnce(H::Arg) -> anyhow::Result<H::Result>,
) -> anyhow::Result<()> {
if self.hook != H::get_name_static() {
return Ok(());
}
if self.hook_version != H::get_version() as u32 {
bail!("Hook version does not match. Try updating the plugin or Nitrolaunch.");
}
let arg = arg(self)?;
let result = f(arg);
let result = match result {
Ok(result) => result,
Err(e) => {
if H::get_takes_over() {
eprintln!("{e:?}");
return Ok(());
} else {
return Err(e);
}
}
};
if !H::get_takes_over() {
let serialized = serde_json::to_string(&result)?;
unsafe { _set_hook_result(serialized) };
}
Ok(())
}
pub(crate) fn get_hook_arg<Arg: DeserializeOwned>(&self) -> anyhow::Result<Arg> {
serde_json::from_str(&self.arg).context("Failed to deserialize hook argument")
}
}
pub unsafe fn _set_hook_result(result: String) {
unsafe {
HOOK_RESULT = result;
}
}
pub unsafe fn _get_hook_result() -> String {
#[allow(static_mut_refs)]
unsafe {
HOOK_RESULT.clone()
}
}