extern crate bincode;
extern crate generic_array;
use libc;
use libloading;
use buffett_interface::account::KeyedAccount;
use std::path::PathBuf;
#[cfg(debug_assertions)]
const CARGO_PROFILE: &str = "debug";
#[cfg(not(debug_assertions))]
const CARGO_PROFILE: &str = "release";
#[cfg(unix)]
const PLATFORM_FILE_PREFIX: &str = "lib";
#[cfg(windows)]
const PLATFORM_FILE_PREFIX: &str = "";
#[cfg(any(target_os = "macos", target_os = "ios"))]
const PLATFORM_FILE_EXTENSION: &str = "dylib";
#[cfg(all(unix, not(any(target_os = "macos", target_os = "ios"))))]
const PLATFORM_FILE_EXTENSION: &str = "so";
#[cfg(windows)]
const PLATFORM_FILE_EXTENSION: &str = "dll";
fn create_library_path(name: &str) -> PathBuf {
let mut path = PathBuf::new();
path.push("target");
path.push(CARGO_PROFILE);
path.push("deps");
path.push(PLATFORM_FILE_PREFIX.to_string() + name);
path.set_extension(PLATFORM_FILE_EXTENSION);
path
}
const ENTRYPOINT: &str = "process";
type Entrypoint = unsafe extern "C" fn(infos: &mut Vec<KeyedAccount>, data: &[u8]);
#[derive(Debug)]
pub enum DynamicProgram {
Native {
name: String,
library: libloading::Library,
},
Bpf { userdata: Vec<u8> },
}
impl DynamicProgram {
pub fn new(name: String) -> Self {
let path = create_library_path(&name);
let os_lib =
libloading::os::unix::Library::open(Some(path), libc::RTLD_NODELETE | libc::RTLD_NOW)
.unwrap();
let library = libloading::Library::from(os_lib);
DynamicProgram::Native { name, library }
}
pub fn call(&self, infos: &mut Vec<KeyedAccount>, data: &[u8]) {
match self {
DynamicProgram::Native { name, library } => unsafe {
let entrypoint: libloading::Symbol<Entrypoint> =
match library.get(ENTRYPOINT.as_bytes()) {
Ok(s) => s,
Err(e) => panic!(
"{:?} Unable to find {:?} in program {}",
e, ENTRYPOINT, name
),
};
entrypoint(infos, data);
},
DynamicProgram::Bpf { .. } => {
println!{"Bpf program not supported"}
}
}
}
}