use std::iter::repeat;
use std::ffi::{CString};
use crypto::aes_gcm::AesGcm;
use crypto::aes::{KeySize};
use crypto::aead::AeadDecryptor;
use {NetMsg, FileUtils};
use td_rlua::{self, Lua, LuaRead};
use libc;
use tunm_proto;
use std::sync::Arc;
use td_rthreadpool::ReentrantMutex;
use td_rredis::{RedisResult, Value};
use super::{LuaWrapperTableValue, RedisWrapperResult};
use psocket::SOCKET;
const AES_KEY: [u8; 32] = [
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
0x2b, 0x72, 0xaf, 0xf0, 0x85, 0x7d, 0x77, 0x81,
0x1f, 0x35, 0x2c, 0x08, 0x3b, 0x62, 0x08, 0xd7,
0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
];
const AES_IV: [u8; 12] = [
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
0x2b, 0x72, 0xaf, 0xf0
];
static mut EL: *mut LuaEngine = 0 as *mut _;
enum LuaElem {
Message(SOCKET, NetMsg),
DbResult(u32, i32, Option<String>, Option<NetMsg>),
RedisResult(u32, Option<RedisResult<Value>>),
NewConnection(u32, SOCKET, String, u16, bool),
LostConnection(SOCKET),
ExecString(String),
ArgsFunc(String, Vec<String>),
}
pub struct LuaEngine {
exec_list: Vec<LuaElem>,
lua: Lua,
mutex: Arc<ReentrantMutex<i32>>,
}
extern "C" fn load_func(lua: *mut td_rlua::lua_State) -> libc::c_int {
let path: String = unwrap_or!(td_rlua::LuaRead::lua_read(lua), return 0);
let full_path = unwrap_or!(FileUtils::instance().full_path_for_name(&*path), path);
let full_path = full_path.trim_matches('\"');
let data = unwrap_or!(FileUtils::get_file_data(&*full_path).ok(), return 0);
if data.len() < 10 {
return 0;
}
let mut name = full_path.to_string();
let mut short_name = name.clone();
let len = name.len();
if len > 30 {
short_name = name.drain((len - 30)..).collect();
}
let short_name = CString::new(short_name).unwrap();
let ret;
if data[0] == 0xff && data[1] == 0xfe && data[2] == 0xfd && data.len() > 19 {
let mut out: Vec<u8> = repeat(0).take(data.len() - 19).collect();
let mut decipher = AesGcm::new(KeySize::KeySize256, &AES_KEY, &AES_IV, &[0;0]);
let _result = decipher.decrypt(&data[19..], &mut out[..], &data[3..19]);
ret = unsafe { td_rlua::luaL_loadbuffer(lua, out.as_ptr() as *const i8, out.len(), short_name.as_ptr()) };
} else {
ret = unsafe { td_rlua::luaL_loadbuffer(lua, data.as_ptr() as *const i8, data.len(), short_name.as_ptr()) };
}
if ret != 0 {
let err_msg : String = unwrap_or!(LuaRead::lua_read(lua), return 0);
let err_detail = CString::new(format!("error loading from file {} :\n\t{}", full_path, err_msg)).unwrap();
unsafe { td_rlua::luaL_error(lua, err_detail.as_ptr()); }
}
1
}
impl LuaEngine {
pub fn instance() -> &'static mut LuaEngine {
unsafe {
if EL == 0 as *mut _ {
EL = Box::into_raw(Box::new(LuaEngine::new(Lua::new())));
}
&mut *EL
}
}
pub fn new(mut lua: Lua) -> LuaEngine {
lua.openlibs();
lua.add_lualoader(load_func);
lua.enable_hotfix();
LuaEngine {
exec_list: vec![],
lua: lua,
mutex: Arc::new(ReentrantMutex::new(0)),
}
}
pub fn get_lua(&mut self) -> &mut Lua {
&mut self.lua
}
pub fn execute_lua(&mut self) -> bool {
let temp_list: Vec<LuaElem>;
{
let _guard = self.mutex.lock().unwrap();
temp_list = self.exec_list.drain(..).collect();
}
for elem in temp_list {
let _ = match elem {
LuaElem::Message(fd, net_msg) => self.execute_message(fd, net_msg),
LuaElem::DbResult(cookie, ret, err_msg, net_msg) => {
self.execute_db_result(cookie, ret, err_msg, net_msg)
}
LuaElem::RedisResult(cookie, result) => self.execute_redis_result(cookie, result),
LuaElem::NewConnection(cookie, new_fd, client_ip, server_port, websocket) => {
self.execute_new_connect(cookie, new_fd, client_ip, server_port, websocket)
}
LuaElem::LostConnection(lost_fd) => self.execute_lost_connect(lost_fd),
LuaElem::ExecString(func_str) => self.execute_string(func_str),
LuaElem::ArgsFunc(func, args) => self.execute_args_func(func, args),
};
}
true
}
pub fn apply_new_connect(&mut self,
cookie: u32,
new_fd: SOCKET,
client_ip: String,
server_port: u16,
websocket: bool) {
let _guard = self.mutex.lock().unwrap();
self.exec_list.push(LuaElem::NewConnection(cookie, new_fd, client_ip, server_port, websocket));
}
pub fn apply_lost_connect(&mut self, lost_fd: SOCKET) {
let _guard = self.mutex.lock().unwrap();
self.exec_list.push(LuaElem::LostConnection(lost_fd));
}
pub fn apply_db_result(&mut self,
cookie: u32,
ret: i32,
err_msg: Option<String>,
net_msg: Option<NetMsg>) {
let _guard = self.mutex.lock().unwrap();
self.exec_list.push(LuaElem::DbResult(cookie, ret, err_msg, net_msg));
}
pub fn apply_redis_result(&mut self, cookie: u32, result: Option<RedisResult<Value>>) {
let _guard = self.mutex.lock().unwrap();
self.exec_list.push(LuaElem::RedisResult(cookie, result));
}
pub fn apply_message(&mut self, fd: SOCKET, net_msg: NetMsg) {
let _guard = self.mutex.lock().unwrap();
self.exec_list.push(LuaElem::Message(fd, net_msg));
}
pub fn apply_exec_string(&mut self, func_str: String) {
let _guard = self.mutex.lock().unwrap();
self.exec_list.push(LuaElem::ExecString(func_str));
}
pub fn apply_args_func(&mut self, func: String, args: Vec<String>) {
let _guard = self.mutex.lock().unwrap();
self.exec_list.push(LuaElem::ArgsFunc(func, args));
}
pub fn execute_new_connect(&mut self,
cookie: u32,
new_fd: SOCKET,
client_ip: String,
server_port: u16,
websocket: bool)
-> i32 {
self.lua.exec_func5("cmd_new_connection", cookie, new_fd, client_ip, server_port, websocket)
}
pub fn execute_lost_connect(&mut self, lost_fd: SOCKET) -> i32 {
self.lua.exec_func1("cmd_connection_lost", lost_fd)
}
pub fn execute_db_result(&mut self,
cookie: u32,
ret: i32,
err_msg: Option<String>,
net_msg: Option<NetMsg>)
-> i32 {
if ret != 0 {
self.lua.exec_func3("msg_db_result",
cookie,
ret,
err_msg.unwrap_or("err msg detail miss".to_string()))
} else {
if net_msg.is_some() {
let mut net_msg = net_msg.unwrap();
net_msg.set_read_data();
if let Ok((_, val)) = tunm_proto::decode_proto(net_msg.get_buffer()) {
self.lua.exec_func3("msg_db_result", cookie, ret, LuaWrapperTableValue(val))
} else {
self.lua.exec_func3("msg_db_result", cookie, -2, "analyse data failed")
}
} else {
self.lua.exec_func3("msg_db_result", cookie, ret, LuaWrapperTableValue(vec![]))
}
}
}
pub fn execute_redis_result(&mut self, cookie: u32, result: Option<RedisResult<Value>>) -> i32 {
if result.is_none() {
self.lua.exec_func1("msg_redis_result", cookie)
} else {
self.lua.exec_func2("msg_redis_result",
cookie,
RedisWrapperResult(result.unwrap()))
}
}
pub fn execute_message(&mut self, fd: SOCKET, mut net_msg: NetMsg) -> i32 {
net_msg.set_read_data();
unwrap_or!(net_msg.read_head().ok(), return -1);
self.lua.exec_func3("global_dispatch_command",
fd,
net_msg.get_pack_name().clone(),
net_msg)
}
pub fn execute_string(&mut self, func_str: String) -> i32 {
self.lua.exec_func1("run_string", func_str)
}
pub fn execute_args_func(&mut self, func: String, args: Vec<String>) -> i32 {
match args.len() {
0 => self.lua.exec_func0(func),
1 => self.lua.exec_func1(func, &*args[0]),
2 => self.lua.exec_func2(func, &*args[0], &*args[1]),
3 => self.lua.exec_func3(func, &*args[0], &*args[1], &*args[2]),
4 => self.lua.exec_func4(func, &*args[0], &*args[1], &*args[2], &*args[3]),
5 => self.lua.exec_func5(func, &*args[0], &*args[1], &*args[2], &*args[3], &*args[4]),
6 => {
self.lua.exec_func6(func,
&*args[0],
&*args[1],
&*args[2],
&*args[3],
&*args[4],
&*args[5])
}
7 => {
self.lua.exec_func7(func,
&*args[0],
&*args[1],
&*args[2],
&*args[3],
&*args[4],
&*args[5],
&*args[6])
}
_ => -1,
}
}
pub fn convert_excute_string(mut ori: String) -> String {
if ori.len() == 0 {
return ori;
}
if let Some(index) = ori.find('\'') {
if index == 0 {
let t: String = ori.drain(1..).collect();
return format!("LOG.warn(\"%o\", {})", t);
}
}
return ori;
}
pub fn do_hotfix_file(&mut self, path: String) -> i32 {
let full_path = unwrap_or!(FileUtils::instance().full_path_for_name(&*path), path);
let full_path = full_path.trim_matches('\"');
let data = unwrap_or!(FileUtils::get_file_data(&*full_path).ok(), return 0);
if data.len() < 10 {
return 0;
}
let mut name = full_path.to_string();
let mut short_name = name.clone();
let len = name.len();
if len > 30 {
short_name = name.drain((len - 30)..).collect();
}
let file_data = if data[0] == 0xff && data[1] == 0xfe && data[2] == 0xfd && data.len() > 19 {
let mut out: Vec<u8> = repeat(0).take(data.len() - 19).collect();
let mut decipher = AesGcm::new(KeySize::KeySize256, &AES_KEY, &AES_IV, &[0;0]);
let _result = decipher.decrypt(&data[19..], &mut out[..], &data[3..19]);
unwrap_or!(String::from_utf8(out).ok(), return 0)
} else {
unwrap_or!(String::from_utf8(data).ok(), return 0)
};
self.lua.exec_func2("hotfix", file_data, short_name)
}
}