use std::sync::Arc;
use tokio::runtime::Runtime;
use virtual_fs::{AsyncReadExt, AsyncSeekExt};
use wasmer_package::utils::from_bytes;
use wasmer_wasix::{
bin_factory::BinaryPackage,
runners::{wasi::WasiRunner, Runner},
runtime::{package_loader::BuiltinPackageLoader, task_manager::tokio::TokioTaskManager},
PluggableRuntime,
};
uniffi::setup_scaffolding!();
macro_rules! err {
($e:expr) => {
match $e {
Ok(r) => r,
Err(e) => {
println!("{e}");
return Err(WasmerError::Err { e: e.to_string() });
}
}
};
}
#[derive(Debug, uniffi::Error, thiserror::Error)]
pub enum WasmerError {
#[error("An error occurred during execution: {e:?}")]
Err { e: String },
}
#[uniffi::export]
pub fn run_package(webc_bytes: Vec<u8>, args: Vec<String>) -> Result<String, WasmerError> {
let tokio_rt = Runtime::new().unwrap();
let _enter = tokio_rt.enter();
let container = err!(from_bytes(webc_bytes));
let tasks = TokioTaskManager::new(tokio_rt.handle().clone());
let tasks = Arc::new(tasks);
let mut rt = PluggableRuntime::new(Arc::clone(&tasks) as Arc<_>);
rt.set_engine(Some(wasmer::Engine::default()))
.set_package_loader(BuiltinPackageLoader::new());
let pkg = tokio_rt
.handle()
.block_on(async { BinaryPackage::from_webc(&container, &rt).await.unwrap() });
if pkg.entrypoint_cmd.is_none() {
return Ok(format!("This WEBC ({}) has no entrypoint!", pkg.id));
}
let entrypoint = pkg.entrypoint_cmd.clone().unwrap();
let mut stdout = virtual_fs::ArcFile::new(Box::<virtual_fs::BufferFile>::default());
let stdout_2 = stdout.clone();
let handle = std::thread::spawn(move || {
let _guard = tasks.runtime_handle().enter();
WasiRunner::new()
.with_args(args)
.with_stdin(Box::<virtual_fs::NullFile>::default())
.with_stdout(Box::new(stdout_2) as Box<_>)
.with_stderr(Box::<virtual_fs::NullFile>::default())
.run_command(&entrypoint, &pkg, Arc::new(rt))
});
let _ = handle.join();
let mut output = Vec::new();
tokio_rt.handle().block_on(async {
stdout.rewind().await.unwrap();
stdout.read_to_end(&mut output).await.unwrap();
});
Ok(err!(String::from_utf8(output)))
}