use std::path::Path;
use pluginop_common::{
quic::{ConnectionField, RecoveryField},
APIResult, WASMLen,
};
use wasmer::{Exports, Function, FunctionEnv, FunctionEnvMut, Imports, Store, WasmPtr};
use crate::{
plugin::{Env, TimerEvent},
PluginizableConnection,
};
pub enum CTPError {
BadType,
SerializeError,
BadBytes,
FileError,
}
pub trait ConnectionToPlugin:
Sized + Send + Unpin + ToPluginizableConnection<Self> + 'static
{
fn get_connection<'a>(
&self,
field: ConnectionField,
w: &'a mut [u8],
) -> postcard::Result<&'a mut [u8]>;
fn set_connection(&mut self, field: ConnectionField, value: &[u8]) -> Result<(), CTPError>;
fn get_recovery<'a>(
&self,
field: RecoveryField,
w: &'a mut [u8],
) -> postcard::Result<&'a mut [u8]>;
fn set_recovery(
&mut self,
field: RecoveryField,
value: &[u8],
) -> std::result::Result<(), CTPError>;
}
pub trait ToPluginizableConnection<CTP: ConnectionToPlugin> {
fn set_pluginizable_connection(&mut self, pc: *mut PluginizableConnection<CTP>);
fn get_pluginizable_connection(&mut self) -> Option<&mut PluginizableConnection<CTP>>;
}
fn save_output_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
ptr: WasmPtr<u8>,
len: WASMLen,
) -> APIResult {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let output_cells = match ptr.slice(&view, len) {
Ok(oc) => oc,
Err(_) => return -3,
};
let output_serialized = match output_cells.read_to_vec() {
Ok(os) => os,
Err(_) => return -4,
};
match postcard::from_bytes(&output_serialized) {
Ok(pv) => {
env.data_mut().outputs.push(pv);
0
}
Err(_) => -5,
}
}
fn save_outputs_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
ptr: WasmPtr<u8>,
len: WASMLen,
) -> APIResult {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let output_cells = match ptr.slice(&view, len) {
Ok(oc) => oc,
Err(_) => return -3,
};
let output_serialized = match output_cells.read_to_vec() {
Ok(os) => os,
Err(_) => return -4,
};
match postcard::from_bytes(&output_serialized) {
Ok(pvs) => {
*env.data_mut().outputs = pvs;
0
}
Err(_) => -5,
}
}
fn get_input_from_plugin<CTP: ConnectionToPlugin>(
env: FunctionEnvMut<Env<CTP>>,
index: u32,
mem_ptr: WasmPtr<u8>,
mem_len: WASMLen,
) -> APIResult {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let input = match env.data().inputs.get(index as usize) {
Some(i) => i,
None => return -3,
};
let memory_slice = unsafe { view.data_unchecked_mut() };
match postcard::to_slice(
input,
&mut memory_slice[mem_ptr.offset() as usize..(mem_ptr.offset() + mem_len) as usize],
) {
Ok(_) => 0,
Err(_) => -6,
}
}
fn get_inputs_from_plugin<CTP: ConnectionToPlugin>(
env: FunctionEnvMut<Env<CTP>>,
mem_ptr: WasmPtr<u8>,
mem_len: WASMLen,
) -> APIResult {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked_mut() };
match postcard::to_slice(
&*env.data().inputs,
&mut memory_slice[mem_ptr.offset() as usize..(mem_ptr.offset() + mem_len) as usize],
) {
Ok(_) => 0,
Err(_) => -5,
}
}
fn print_from_plugin<CTP: ConnectionToPlugin>(
env: FunctionEnvMut<Env<CTP>>,
ptr: WasmPtr<u8>,
len: WASMLen,
) {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return,
};
let view = memory.view(&env);
if let Ok(s) = ptr.read_utf8_string(&view, len) {
println!("{s}");
}
}
fn get_connection_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
field_ptr: WasmPtr<u8>,
field_len: WASMLen,
res_ptr: WasmPtr<u8>,
res_len: WASMLen,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked_mut() };
let memory_slice =
unsafe { std::slice::from_raw_parts_mut(memory_slice.as_mut_ptr(), memory_slice.len()) };
let field = match postcard::from_bytes(
&memory_slice[field_ptr.offset() as usize..(field_ptr.offset() + field_len) as usize],
) {
Ok(f) => f,
Err(_) => return -3,
};
let ph = if let Some(ph) = env.data_mut().get_ph() {
ph
} else {
return -4;
};
let conn = match ph.get_conn() {
Some(c) => c,
None => return -5,
};
match conn.get_conn().get_connection(
field,
&mut memory_slice[res_ptr.offset() as usize..(res_ptr.offset() + res_len) as usize],
) {
Ok(_) => 0,
Err(_) => -6,
}
}
fn set_connection_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
field_ptr: WasmPtr<u8>,
field_len: WASMLen,
val_ptr: WasmPtr<u8>,
val_len: WASMLen,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked() };
let memory_slice =
unsafe { std::slice::from_raw_parts(memory_slice.as_ptr(), memory_slice.len()) };
let field = match postcard::from_bytes(
&memory_slice[field_ptr.offset() as usize..(field_ptr.offset() + field_len) as usize],
) {
Ok(f) => f,
Err(_) => return -3,
};
let ph = if let Some(ph) = env.data_mut().get_ph() {
ph
} else {
return -4;
};
let conn = match ph.get_conn_mut() {
Some(c) => c,
None => return -5,
};
match conn.get_conn_mut().set_connection(
field,
&memory_slice[val_ptr.offset() as usize..(val_ptr.offset() + val_len) as usize],
) {
Ok(()) => 0,
Err(_) => -6,
}
}
fn get_bytes_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
tag: u64,
len: u64,
res_ptr: WasmPtr<u8>,
res_len: WASMLen,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked_mut() };
let memory_slice =
unsafe { std::slice::from_raw_parts_mut(memory_slice.as_mut_ptr(), memory_slice.len()) };
let mem = &mut memory_slice[res_ptr.offset() as usize..(res_ptr.offset() + res_len) as usize];
match env.data_mut().get_bytes(tag as usize, len as usize, mem) {
Ok(w) => w as i64,
Err(_) => -3,
}
}
fn put_bytes_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
tag: u64,
ptr: WasmPtr<u8>,
len: WASMLen,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked_mut() };
let memory_slice =
unsafe { std::slice::from_raw_parts(memory_slice.as_ptr(), memory_slice.len()) };
let mem = &memory_slice[ptr.offset() as usize..(ptr.offset() + len) as usize];
match env.data_mut().put_bytes(tag as usize, mem) {
Ok(w) => w as i64,
Err(_) => -3,
}
}
fn register_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
ptr: WasmPtr<u8>,
len: WASMLen,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked() };
let r = match postcard::from_bytes(
&memory_slice[ptr.offset() as usize..(ptr.offset() + len) as usize],
) {
Ok(f) => f,
Err(_) => return -3,
};
let ph = if let Some(ph) = env.data_mut().get_ph() {
ph
} else {
return -4;
};
ph.add_registration(r);
0
}
fn set_timer_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
ts_ptr: WasmPtr<u8>,
ts_len: WASMLen,
id: u64,
timer_id: u64,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked() };
let unix_instant = match postcard::from_bytes(
&memory_slice[ts_ptr.offset() as usize..(ts_ptr.offset() + ts_len) as usize],
) {
Ok(i) => i,
Err(_) => return -3,
};
let ph = if let Some(ph) = env.data_mut().get_ph() {
ph
} else {
return -4;
};
let instant = ph.get_instant_from_unix_instant(unix_instant);
env.data_mut()
.insert_timer_event(TimerEvent::new(instant, id, timer_id));
0
}
fn cancel_timer_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
id: u64,
) -> i64 {
if env.data_mut().cancel_timer_event(id).is_some() {
0
} else {
-1
}
}
fn get_unix_instant_from_plugin<CTP: ConnectionToPlugin>(
env: FunctionEnvMut<Env<CTP>>,
res_ptr: WasmPtr<u8>,
res_len: WASMLen,
) -> APIResult {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let now = unix_time::Instant::now();
let memory_slice = unsafe { view.data_unchecked_mut() };
match postcard::to_slice(
&now,
&mut memory_slice[res_ptr.offset() as usize..(res_ptr.offset() + res_len) as usize],
) {
Ok(_) => 0,
Err(_) => -6,
}
}
fn create_file_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
path_ptr: WasmPtr<u8>,
path_len: WASMLen,
) -> APIResult {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked() };
let path: String = match std::str::from_utf8(
&memory_slice[path_ptr.offset() as usize..(path_ptr.offset() + path_len) as usize],
) {
Ok(p) => p.to_string(),
Err(_) => return -3,
};
println!("Path is {}", path);
env.data_mut()
.create_file_with_path(Path::new(&path))
.unwrap_or(-4)
}
fn write_file_from_plugin<CTP: ConnectionToPlugin>(
env: FunctionEnvMut<Env<CTP>>,
fd: i64,
ptr: WasmPtr<u8>,
ptr_len: WASMLen,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked() };
match env.data().write_to_file(
fd,
&memory_slice[ptr.offset() as usize..(ptr.offset() + ptr_len) as usize],
) {
Ok(w) => w as i64,
Err(_) => -3,
}
}
fn enable_from_plugin<CTP: ConnectionToPlugin>(mut env: FunctionEnvMut<Env<CTP>>) {
env.data_mut().enable();
}
fn get_recovery_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
field_ptr: WasmPtr<u8>,
field_len: WASMLen,
res_ptr: WasmPtr<u8>,
res_len: WASMLen,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked_mut() };
let memory_slice =
unsafe { std::slice::from_raw_parts_mut(memory_slice.as_mut_ptr(), memory_slice.len()) };
let field = match postcard::from_bytes(
&memory_slice[field_ptr.offset() as usize..(field_ptr.offset() + field_len) as usize],
) {
Ok(f) => f,
Err(_) => return -3,
};
let ph = if let Some(ph) = env.data_mut().get_ph() {
ph
} else {
return -4;
};
let conn = match ph.get_conn() {
Some(c) => c,
None => return -5,
};
match conn.get_conn().get_recovery(
field,
&mut memory_slice[res_ptr.offset() as usize..(res_ptr.offset() + res_len) as usize],
) {
Ok(_) => 0,
Err(_) => -6,
}
}
fn set_recovery_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
field_ptr: WasmPtr<u8>,
field_len: WASMLen,
val_ptr: WasmPtr<u8>,
val_len: WASMLen,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked() };
let memory_slice =
unsafe { std::slice::from_raw_parts(memory_slice.as_ptr(), memory_slice.len()) };
let field = match postcard::from_bytes(
&memory_slice[field_ptr.offset() as usize..(field_ptr.offset() + field_len) as usize],
) {
Ok(f) => f,
Err(_) => return -3,
};
let ph = if let Some(ph) = env.data_mut().get_ph() {
ph
} else {
return -4;
};
let conn = match ph.get_conn_mut() {
Some(c) => c,
None => return -5,
};
match conn.get_conn_mut().set_recovery(
field,
&memory_slice[val_ptr.offset() as usize..(val_ptr.offset() + val_len) as usize],
) {
Ok(()) => 0,
Err(_) => -6,
}
}
fn poctl_from_plugin<CTP: ConnectionToPlugin>(
mut env: FunctionEnvMut<Env<CTP>>,
id: u64,
inputs_ptr: WasmPtr<u8>,
inputs_len: WASMLen,
res_ptr: WasmPtr<u8>,
res_len: WASMLen,
) -> i64 {
let instance = if let Some(i) = env.data().get_instance() {
i
} else {
return -1;
};
let instance = instance.as_ref();
let memory = match instance.exports.get_memory("memory") {
Ok(m) => m,
Err(_) => return -2,
};
let view = memory.view(&env);
let memory_slice = unsafe { view.data_unchecked_mut() };
let memory_slice =
unsafe { std::slice::from_raw_parts_mut(memory_slice.as_mut_ptr(), memory_slice.len()) };
let inputs: Vec<crate::PluginVal> = match postcard::from_bytes(
&memory_slice[inputs_ptr.offset() as usize..(inputs_ptr.offset() + inputs_len) as usize],
) {
Ok(i) => i,
Err(_) => return -3,
};
let ph = if let Some(ph) = env.data_mut().get_ph() {
ph
} else {
return -4;
};
let outputs = match ph.poctl(id, &inputs) {
Ok(pvs) => pvs,
Err(_) => return -5,
};
match postcard::to_slice(
&outputs,
&mut memory_slice[res_ptr.offset() as usize..(res_ptr.offset() + res_len) as usize],
) {
Ok(_) => 0,
Err(_) => -6,
}
}
macro_rules! exports_insert {
($e:ident, $s:ident, $env:ident, $f:ident) => {
$e.insert(stringify!($f), Function::new_typed_with_env($s, $env, $f));
};
}
pub fn get_imports_with<CTP: ConnectionToPlugin>(
mut exports: Exports,
store: &mut Store,
env: &FunctionEnv<Env<CTP>>,
) -> Imports {
exports_insert!(exports, store, env, save_output_from_plugin);
exports_insert!(exports, store, env, save_outputs_from_plugin);
exports_insert!(exports, store, env, get_input_from_plugin);
exports_insert!(exports, store, env, get_inputs_from_plugin);
exports_insert!(exports, store, env, print_from_plugin);
exports_insert!(exports, store, env, get_connection_from_plugin);
exports_insert!(exports, store, env, set_connection_from_plugin);
exports_insert!(exports, store, env, get_bytes_from_plugin);
exports_insert!(exports, store, env, put_bytes_from_plugin);
exports_insert!(exports, store, env, register_from_plugin);
exports_insert!(exports, store, env, set_timer_from_plugin);
exports_insert!(exports, store, env, cancel_timer_from_plugin);
exports_insert!(exports, store, env, get_unix_instant_from_plugin);
exports_insert!(exports, store, env, create_file_from_plugin);
exports_insert!(exports, store, env, write_file_from_plugin);
exports_insert!(exports, store, env, enable_from_plugin);
exports_insert!(exports, store, env, get_recovery_from_plugin);
exports_insert!(exports, store, env, set_recovery_from_plugin);
exports_insert!(exports, store, env, poctl_from_plugin);
let mut imports = Imports::new();
imports.register_namespace("env", exports);
imports
}