use super::libloading::{Library, Symbol};
#[cfg(feature="pluginlua")]
use super::rlua;
use super::server::RICSServer;
use std::sync::Mutex;
use std;
pub trait ScriptingInterface {
fn initialize(&self) -> bool { true }
fn start(&self, _svr: &mut RICSServer, _node: i32) -> bool { true }
fn can_rx(&self, _svr: &mut RICSServer, _id: u32, _data: Vec<u8>) -> bool { true }
fn update(&self, _svr: &mut RICSServer) -> bool { true }
}
pub struct ScriptingInterfaceWrapper {
pub iface : Mutex<Box<dyn ScriptingInterface>>
}
unsafe impl Send for ScriptingInterfaceWrapper {}
unsafe impl Sync for ScriptingInterfaceWrapper {}
#[cfg(target_family="unix")]
type DynRawSymbol<T> = libloading::os::unix::Symbol<T>;
#[cfg(target_family="windows")]
type DynRawSymbol<T> = libloading::os::windows::Symbol<T>;
pub struct DynlibScript {
lib: Library,
on_can_msg: Option<DynRawSymbol<unsafe extern fn(u32, usize, *const u8) -> i32>>,
}
impl DynlibScript {
pub fn new(path: String) -> DynlibScript {
trace!("Creating DynlibScript from {}", path.clone());
let lib = Library::new(path).unwrap();
DynlibScript {
lib: lib,
on_can_msg: None,
}
}
pub fn load(mut self) -> Self {
unsafe {
let symbol: Symbol<unsafe extern fn(u32, usize, *const u8) -> i32> = self.lib.get(b"rics_can_callback").unwrap();
self.on_can_msg = Some(symbol.into_raw());
}
self
}
}
impl ScriptingInterface for DynlibScript {
fn initialize(&self) -> bool {
0 != unsafe {(&*self.lib.get::<fn() -> i32>(b"rics_init").unwrap())()}
}
fn start(&self, _svr: &mut RICSServer, node: i32) -> bool {
0 != unsafe {(&*self.lib.get::<fn(i32) -> i32>(b"rics_start").unwrap())(node)}
}
fn can_rx(&self, _svr: &mut RICSServer, id: u32, data: Vec<u8>) -> bool {
let len = data.len();
0 != unsafe {(&*self.on_can_msg.as_ref().unwrap())(id, len, data.as_ptr())}
}
fn update(&self, _svr: &mut RICSServer) -> bool {
true
}
}
struct ServerBox {
svr: *mut RICSServer
}
unsafe impl Send for ServerBox {}
#[cfg(feature="pluginlua")]
impl rlua::UserData for ServerBox {
fn add_methods<'lua, M: rlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method_mut("send_can", |_, this, (id, dat, dest): (u32,Vec<u8>, Option<i32>)| {
match dest {
Some(target) => unsafe {(*this.svr).send_packet_to(super::server::can_packet(id as i32, dat), target); }
None => unsafe {(*this.svr).send_packet(super::server::can_packet(id as i32, dat)); }
}
Ok(())
});
methods.add_method("get_time_ms", |_, this, () | {
Ok( std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("Invalid current time").as_millis() )
});
methods.add_method("rics_exit", |_, this, () | {
std::process::exit(0);
Ok(())
});
}
}
#[cfg(feature="pluginlua")]
pub struct LuaScript {
lua: rlua::Lua,
on_init: rlua::RegistryKey,
on_start: rlua::RegistryKey,
on_can_msg: rlua::RegistryKey,
on_update: rlua::RegistryKey
}
#[cfg(feature="pluginlua")]
impl LuaScript {
pub fn new(path: String) -> LuaScript {
let lua = rlua::Lua::new();
let content = std::fs::read_to_string(path).unwrap();
let (func_init, func_start, func_can_msg, func_update) = lua.context(move|ctx| {
if let Err(e) = ctx.load(&content).exec() {
error!("Lua error loading file: {}", e);
}
let func_init = ctx.create_registry_value(match ctx.globals().get("rics_init") {
Ok(f) => f,
Err(e) => { error!("Lua error rics_init undefined: {}", e);
ctx.create_function(|_,()|Ok(true)).unwrap()
}
}).unwrap();
let func_start = ctx.create_registry_value(match ctx.globals().get("rics_start") {
Ok(f) => f,
Err(e) => { error!("Lua error rics_start undefined: {}", e);
ctx.create_function(|_,_:i32|Ok(true)).unwrap() }
}).unwrap();
let func_can_msg = ctx.create_registry_value(match ctx.globals().get("rics_can_callback") {
Ok(f) => f,
Err(e) => { error!("Lua error rics_can_callback undefined: {}", e);
ctx.create_function(|_, _:(u32,Vec<u8>)|Ok(true)).unwrap() }
}).unwrap();
let func_update = ctx.create_registry_value(match ctx.globals().get("rics_update") {
Ok(f) => f,
Err(e) => { error!("Lua error rics_update undefined: {}", e);
ctx.create_function(|_, ()|Ok(true)).unwrap() }
}).unwrap();
(func_init, func_start, func_can_msg, func_update)
});
LuaScript {
lua: lua,
on_init: func_init,
on_start: func_start,
on_can_msg: func_can_msg,
on_update: func_update,
}
}
}
#[cfg(feature="pluginlua")]
impl ScriptingInterface for LuaScript {
fn initialize(&self) -> bool {
self.lua.context(|ctx| { match ctx.registry_value::<rlua::Function>(&self.on_init).unwrap().call(()) {
Ok(o) => o,
Err(e) => { error!("Lua error initialization: {}", e); false }
}})
}
fn start(&self, svr: &mut RICSServer, node: i32) -> bool {
self.lua.context(|ctx| { match ctx.registry_value::<rlua::Function>(&self.on_start).unwrap().call((ServerBox {svr:svr as *mut _},node)) {
Ok(o) => o,
Err(e) => { error!("Lua error start: {}", e); false },
}})
}
fn can_rx(&self, svr: &mut RICSServer, id: u32, data: Vec<u8>) -> bool {
self.lua.context(|ctx| { match ctx.registry_value::<rlua::Function>(&self.on_can_msg).unwrap().call((ServerBox {svr:svr as *mut _}, id,data)) {
Ok(o) => o,
Err(e) => { error!("Lua error can_callback: {}", e); false },
}})
}
fn update(&self, svr: &mut RICSServer) -> bool {
self.lua.context(|ctx| { match ctx.registry_value::<rlua::Function>(&self.on_update).unwrap().call(ServerBox{ svr: svr as *mut RICSServer }) {
Ok(p) => p,
Err(e) => { error!("Lua error update: {}", e); false },
}})
}
}
pub struct NoEngine;
impl ScriptingInterface for NoEngine {}