text:
#include "session_export_to_lua.h"
#include <google/protobuf/message.h>
using namespace google::protobuf;

#include "../netbus/session/AbstractSession.h"
#include "../netbus/protocol/CmdPackageProtocol.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "tolua++.h"
#ifdef __cplusplus
}
#endif // __cplusplus

#include "tolua_fix.h"
#include "../utils/logger/logger.h"
#include "../netbus/Netbus.h"

Message* lua_table_to_protobuf(lua_State* L, int stack_index, const char* msg_name) {
	if (!lua_istable(L, stack_index)) {
		return NULL;
	}

	Message* message = CmdPackageProtocol::CreateMessage(msg_name);
	if (!message) {
		log_error("cant find message  %s from compiled poll \n", msg_name);
		return NULL;
	}

	const Reflection* reflection = message->GetReflection();
	const Descriptor* descriptor = message->GetDescriptor();

	// 遍历table的所有key， 并且与 protobuf结构相比较。如果require的字段没有赋值， 报错！ 如果找不到字段，报错！
	for (int32_t index = 0; index < descriptor->field_count(); ++index) {
		const FieldDescriptor* fd = descriptor->field(index);
		const string& name = fd->name();

		bool isRequired = fd->is_required();
		bool bReapeted = fd->is_repeated();
		lua_pushstring(L, name.c_str());
		lua_rawget(L, stack_index);

		bool isNil = lua_isnil(L, -1);

		if (bReapeted) {
			if (isNil) {
				lua_pop(L, 1);
				continue;
			}
			else {
				bool isTable = lua_istable(L, -1);
				if (!isTable) {
					log_error("cant find required repeated field %s\n", name.c_str());
					CmdPackageProtocol::ReleaseMessage(message);
					return NULL;
				}
			}

			lua_pushnil(L);
			for (; lua_next(L, -2) != 0;) {
				switch (fd->cpp_type()) {

				case FieldDescriptor::CPPTYPE_DOUBLE:
				{
					double value = luaL_checknumber(L, -1);
					reflection->AddDouble(message, fd, value);
				}
				break;
				case FieldDescriptor::CPPTYPE_FLOAT:
				{
					float value = luaL_checknumber(L, -1);
					reflection->AddFloat(message, fd, value);
				}
				break;
				case FieldDescriptor::CPPTYPE_INT64:
				{
					int64_t value = luaL_checknumber(L, -1);
					reflection->AddInt64(message, fd, value);
				}
				break;
				case FieldDescriptor::CPPTYPE_UINT64:
				{
					uint64_t value = luaL_checknumber(L, -1);
					reflection->AddUInt64(message, fd, value);
				}
				break;
				case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
				{
					int32_t value = luaL_checknumber(L, -1);
					const EnumDescriptor* enumDescriptor = fd->enum_type();
					const EnumValueDescriptor* valueDescriptor = enumDescriptor->FindValueByNumber(value);
					reflection->AddEnum(message, fd, valueDescriptor);
				}
				break;
				case FieldDescriptor::CPPTYPE_INT32:
				{
					int32_t value = luaL_checknumber(L, -1);
					reflection->AddInt32(message, fd, value);
				}
				break;
				case FieldDescriptor::CPPTYPE_UINT32:
				{
					uint32_t value = luaL_checknumber(L, -1);
					reflection->AddUInt32(message, fd, value);
				}
				break;
				case FieldDescriptor::CPPTYPE_STRING:
				{
					size_t size = 0;
					const char* value = luaL_checklstring(L, -1, &size);
					reflection->AddString(message, fd, std::string(value, size));
				}
				break;
				case FieldDescriptor::CPPTYPE_BOOL:
				{
					bool value = lua_toboolean(L, -1);
					reflection->AddBool(message, fd, value);
				}
				break;
				case FieldDescriptor::CPPTYPE_MESSAGE:
				{
					Message* value = lua_table_to_protobuf(L, lua_gettop(L), fd->message_type()->name().c_str());
					if (!value) {
						log_error("convert to message %s failed whith value %s\n", fd->message_type()->name().c_str(), name.c_str());
						CmdPackageProtocol::ReleaseMessage(value);
						return NULL;
					}
					Message* msg = reflection->AddMessage(message, fd);
					msg->CopyFrom(*value);
					CmdPackageProtocol::ReleaseMessage(value);
				}
				break;
				default:
					break;
				}

				// remove value， keep the key
				lua_pop(L, 1);
			}
		}
		else {

			if (isRequired) {
				if (isNil) {
					log_error("cant find required field %s\n", name.c_str());
					CmdPackageProtocol::ReleaseMessage(message);
					return NULL;
				}
			}
			else {
				if (isNil) {
					lua_pop(L, 1);
					continue;
				}
			}

			switch (fd->cpp_type()) {
			case FieldDescriptor::CPPTYPE_DOUBLE:
			{
				double value = (double)luaL_checknumber(L, -1);
				reflection->SetDouble(message, fd, value);
			}
			break;
			case FieldDescriptor::CPPTYPE_FLOAT:
			{
				float value = (float)luaL_checknumber(L, -1);
				reflection->SetFloat(message, fd, value);
			}
			break;
			case FieldDescriptor::CPPTYPE_INT64:
			{
				int64_t value = (int64_t)luaL_checknumber(L, -1);
				reflection->SetInt64(message, fd, value);
			}
			break;
			case FieldDescriptor::CPPTYPE_UINT64:
			{
				uint64_t value = (uint64_t)luaL_checknumber(L, -1);
				reflection->SetUInt64(message, fd, value);
			}
			break;
			case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
			{
				int32_t value = (int32_t)luaL_checknumber(L, -1);
				const EnumDescriptor* enumDescriptor = fd->enum_type();
				const EnumValueDescriptor* valueDescriptor = enumDescriptor->FindValueByNumber(value);
				reflection->SetEnum(message, fd, valueDescriptor);
			}
			break;
			case FieldDescriptor::CPPTYPE_INT32:
			{
				int32_t value = (int32_t)luaL_checknumber(L, -1);
				reflection->SetInt32(message, fd, value);
			}
			break;
			case FieldDescriptor::CPPTYPE_UINT32:
			{
				uint32_t value = (uint32_t)luaL_checknumber(L, -1);
				reflection->SetUInt32(message, fd, value);
			}
			break;
			case FieldDescriptor::CPPTYPE_STRING:
			{
				size_t size = 0;
				const char* value = luaL_checklstring(L, -1, &size);
				reflection->SetString(message, fd, std::string(value, size));
			}
			break;
			case FieldDescriptor::CPPTYPE_BOOL:
			{
				bool value = lua_toboolean(L, -1);
				reflection->SetBool(message, fd, value);
			}
			break;
			case FieldDescriptor::CPPTYPE_MESSAGE:
			{
				Message* value = lua_table_to_protobuf(L, lua_gettop(L), fd->message_type()->name().c_str());
				if (!value) {
					log_error("convert to message %s failed whith value %s \n", fd->message_type()->name().c_str(), name.c_str());
					CmdPackageProtocol::ReleaseMessage(message);
					return NULL;
				}
				Message* msg = reflection->MutableMessage(message, fd);
				msg->CopyFrom(*value);
				CmdPackageProtocol::ReleaseMessage(value);
			}
			break;
			default:
				break;
			}
		}

		// pop value
		lua_pop(L, 1);
	}

	return message;
}

static int lua_session_close(lua_State* lua)
{
	if (1 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto session = (AbstractSession*)tolua_touserdata(lua, 1, 0);
	if (NULL == session)
	{
		return 0;
	}

	session->Close();
	return 0;
}
static int lua_session_getaddress(lua_State* lua)
{
	if (1 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto session = (AbstractSession*)tolua_touserdata(lua, 1, 0);
	if (NULL == session)
	{
		return 0;
	}

	int clientPort;
	auto ip = session->GetAddress(clientPort);
	lua_pushstring(lua, ip);
	lua_pushinteger(lua, clientPort);
	return 2;
}
static int lua_session_setutag(lua_State* lua)
{
	if (2 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto session = (AbstractSession*)tolua_touserdata(lua, 1, 0);
	if (NULL == session)
	{
		return 0;
	}

	auto utag = (unsigned int)lua_tointeger(lua, 2);
	session->utag = utag;
	return 0;
}
static int lua_session_getutag(lua_State* lua)
{
	if (1 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto session = (AbstractSession*)tolua_touserdata(lua, 1, 0);
	if (NULL == session)
	{
		return 0;
	}
	lua_pushinteger(lua, session->utag);
	return 1;
}

static int lua_session_setuid(lua_State* lua)
{
	if (2 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto session = (AbstractSession*)tolua_touserdata(lua, 1, 0);
	if (NULL == session)
	{
		return 0;
	}

	auto uid = (unsigned int)lua_tointeger(lua, 2);
	session->uid = uid;
	return 0;
}
static int lua_session_getuid(lua_State* lua)
{
	if (1 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto session = (AbstractSession*)tolua_touserdata(lua, 1, 0);
	if (NULL == session)
	{
		return 0;
	}
	lua_pushinteger(lua, session->uid);
	return 1;
}

static int lua_session_isclient(lua_State* lua)
{
	if (1 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto session = (AbstractSession*)tolua_touserdata(lua, 1, 0);
	if (NULL == session)
	{
		return 0;
	}
	lua_pushboolean(lua,session->isClient ? 1:0);
	return 1;
}

static int lua_session_sendrawpackage(lua_State* lua)
{
	if (2 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	// 1
	auto session = (AbstractSession*)tolua_touserdata(lua, 1, 0);
	if (NULL == session)
	{
		return 0;
	}

	//2
	auto* pk = (struct RawPackage*)tolua_touserdata(lua, 2, NULL);
	if (!pk)
		return 0;

	session->SendRawPackage(pk);
	return 0;
}

//第一个参数：session
//第二个参数：表：{1： sType, 2: cType, 3: uTag, 4: body}
static int lua_session_sendpackage(lua_State* lua)
{
	if (2 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	// 1
	auto session = (AbstractSession*)tolua_touserdata(lua, 1, 0);
	if (NULL == session)
	{
		return 0;
	}
	// 2
	if (!lua_istable(lua, 2))
	{
		return 0;
	}

	CmdPackage msg;

	auto num = luaL_len(lua, 2);
	if (num != 4 && num != 3)
	{
		log_error("Session.SendPackage参数错误")
		return 0;
	}

	lua_pushnumber(lua, 1);
	lua_gettable(lua, 2);
	msg.serviceType = luaL_checkinteger(lua, -1);
	lua_pop(lua, 1);

	lua_pushnumber(lua, 2);
	lua_gettable(lua, 2);
	msg.cmdType = luaL_checkinteger(lua, -1);
	lua_pop(lua, 1);

	lua_pushnumber(lua, 3);
	lua_gettable(lua, 2);
	msg.userTag = luaL_checkinteger(lua, -1);
	lua_pop(lua, 1);

	if (num == 3)
	{
		msg.body = NULL;
		session->SendCmdPackage(&msg);
		return 0;
	}

	lua_pushnumber(lua, 4);
	lua_gettable(lua, 2);
	switch (CmdPackageProtocol::ProtoType())
	{
	case ProtoType::Json:
		msg.body = (char*)lua_tostring(lua, -1);
		session->SendCmdPackage(&msg);
		break;
	case ProtoType::Protobuf:
		if (!lua_istable(lua, -1))
		{
			msg.body = NULL;
		}
		else
		{// protobuf message table
			msg.body =
			lua_table_to_protobuf(lua, lua_gettop(lua),
				CmdPackageProtocol::GetMessageName(msg.serviceType, msg.cmdType));
		}
		session->SendCmdPackage(&msg);
		CmdPackageProtocol::ReleaseMessage((Message*)msg.body);
		break;
	}
	lua_pop(lua, 1);
	return 0;
}

static void udp_send_package(char* ip, int port, CmdPackage* msg)
{
	int pkgLen;
	unsigned char* pkg = CmdPackageProtocol::EncodeCmdPackageToBytes(msg, &pkgLen);
	if (pkg)
	{
		Netbus::Instance()->UdpSendTo(ip, port, pkg, pkgLen);
		CmdPackageProtocol::FreeCmdPackageBytes(pkg);
	}
}

// ip, port, {stype,ctype,utag,body}
static int lua_session_udpsendpackage(lua_State* lua)
{
	auto x = 1;
	x++;

	if (3 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	// 1
	const char* ip = tolua_tostring(lua, 1,NULL);
	if (NULL == ip)
	{
		log_error("Session.UdpSendPackage(ip,port,pkg)");
		return 0;
	}
	// 2
	int port = (int)tolua_tonumber(lua, 2, NULL);
	if (!port || port==-1)
	{
		log_error("Session.UdpSendPackage: 获取port失败，port: %d", port);
		return 0;
	}

	if (!lua_istable(lua, 3))
	{
		return 0;
	}

	CmdPackage msg;

	auto num = luaL_len(lua, 3);
	if (num != 4 && num != 3)
	{
		log_error("Session.SendPackage参数错误")
			return 0;
	}

	lua_pushnumber(lua, 1);
	lua_gettable(lua, 3);
	msg.serviceType = luaL_checkinteger(lua, -1);
	lua_pop(lua, 1);

	lua_pushnumber(lua, 2);
	lua_gettable(lua, 3);
	msg.cmdType = luaL_checkinteger(lua, -1);
	lua_pop(lua, 1);

	lua_pushnumber(lua, 3);
	lua_gettable(lua, 3);
	msg.userTag = luaL_checkinteger(lua, -1);
	lua_pop(lua, 1);

	if (num == 3)
	{
		msg.body = NULL;
		udp_send_package((char*)ip, port, &msg);
		return 0;
	}

	lua_pushnumber(lua, 4);
	lua_gettable(lua, 3);
	switch (CmdPackageProtocol::ProtoType())
	{
	case ProtoType::Json:
		msg.body = (char*)lua_tostring(lua, -1);
		udp_send_package((char*)ip, port, &msg);
		break;
	case ProtoType::Protobuf:
		if (!lua_istable(lua, -1))
		{
			msg.body = NULL;
		}
		else
		{// protobuf message table
			msg.body =
				lua_table_to_protobuf(lua, lua_gettop(lua),
					CmdPackageProtocol::GetMessageName(msg.serviceType, msg.cmdType));
		}
		udp_send_package((char*)ip, port, &msg);
		CmdPackageProtocol::ReleaseMessage((Message*)msg.body);
		break;
	}
	lua_pop(lua, 1);
	return 0;
}

void register_session_export(lua_State* tolua_S)
{
	lua_getglobal(tolua_S, "_G");
	if (lua_istable(tolua_S, -1)) {
		tolua_open(tolua_S);
		tolua_module(tolua_S, "Session", 0);
		tolua_beginmodule(tolua_S, "Session");

		tolua_function(tolua_S, "Close", lua_session_close);
		tolua_function(tolua_S, "GetAddress", lua_session_getaddress);
		tolua_function(tolua_S, "SendPackage", lua_session_sendpackage);
		tolua_function(tolua_S, "SendRawPackage", lua_session_sendrawpackage);
		tolua_function(tolua_S, "UdpSendPackage", lua_session_udpsendpackage);

		tolua_function(tolua_S, "SetUTag", lua_session_setutag);
		tolua_function(tolua_S, "GetUTag", lua_session_getutag);
		tolua_function(tolua_S, "SetUId", lua_session_setuid);
		tolua_function(tolua_S, "GetUId", lua_session_getuid);
		tolua_function(tolua_S, "IsClient", lua_session_isclient);
		//tolua_function(tolua_S, "query", lua_redis_query);
		tolua_endmodule(tolua_S);
	}
	lua_pop(tolua_S, 1);
}


text:
#include "lua_wrapper.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "tolua++.h"
#ifdef __cplusplus
}
#endif // __cplusplus

#include "tolua_fix.h"
#include <string>
#include "mysql_export_to_lua.h"
#include "redis_export_to_lua.h"
#include "service_export_to_lua.h"
#include "session_export_to_lua.h"
#include "logger_export_to_lua.h"
#include "../utils/logger/logger.h"
#include "timer_export_to_lua.h"
#include "netbus_export_to_lua.h"
#include "cmd_package_proto_export_to_lua.h"
#include "utils_export_to_lua.h"

lua_State* g_lua = NULL;

static int lua_lua_addsearchpath(lua_State* lua)
{
	auto path = luaL_checkstring(lua, 1);
	if (path)
	{
		lua_wrapper::AddSearchPath(path);
	}
	return 0;
}

static void register_lua_export(lua_State* tolua_S)
{
	lua_getglobal(tolua_S, "_G");
	if (lua_istable(tolua_S, -1)) {
		tolua_open(tolua_S);
		tolua_module(tolua_S, "Lua", 0);
		tolua_beginmodule(tolua_S, "Lua");

		tolua_function(tolua_S, "AddSearchPath", lua_lua_addsearchpath);
		tolua_endmodule(tolua_S);
	}
	lua_pop(tolua_S, 1);
}

#pragma region Native
static bool
pushFunctionByHandler(int nHandler)
{
	toluafix_get_function_by_refid(g_lua, nHandler);                  /* L: ... func */
	if (!lua_isfunction(g_lua, -1))
	{
		log_error("没有注册过这个函数句柄：%d", nHandler);
		lua_pop(g_lua, 1);
		return false;
	}
	return true;
}

static int
executeFunction(int numArgs)
{
	int functionIndex = -(numArgs + 1);
	if (!lua_isfunction(g_lua, functionIndex))
	{
		log_error("value at stack [%d] is not function", functionIndex);
		lua_pop(g_lua, numArgs + 1); // remove function and arguments
		return 0;
	}

	int traceback = 0;
	lua_getglobal(g_lua, "__G__TRACKBACK__");                         /* L: ... func arg1 arg2 ... G */
	if (!lua_isfunction(g_lua, -1))
	{
		lua_pop(g_lua, 1);                                            /* L: ... func arg1 arg2 ... */
	}
	else
	{
		lua_insert(g_lua, functionIndex - 1);                         /* L: ... G func arg1 arg2 ... */
		traceback = functionIndex - 1;
	}

	int error = 0;
	error = lua_pcall(g_lua, numArgs, 1, traceback);                  /* L: ... [G] ret */
	if (error)
	{
		if (traceback == 0)
		{
			log_error("[LUA ERROR] %s", lua_tostring(g_lua, -1));        /* L: ... error */
			lua_pop(g_lua, 1); // remove error message from stack
		}
		else                                                            /* L: ... G error */
		{
			lua_pop(g_lua, 2); // remove __G__TRACKBACK__ and error message from stack
		}
		return 0;
	}

	// get return value
	int ret = 0;
	if (lua_isnumber(g_lua, -1))
	{
		ret = (int)lua_tointeger(g_lua, -1);
	}
	else if (lua_isboolean(g_lua, -1))
	{
		ret = (int)lua_toboolean(g_lua, -1);
	}
	// remove return value from stack
	lua_pop(g_lua, 1);                                                /* L: ... [G] */

	if (traceback)
	{
		lua_pop(g_lua, 1); // remove __G__TRACKBACK__ from stack      /* L: ... */
	}

	return ret;
}

#pragma endregion

#pragma region lua_wrapper
void lua_wrapper::Init()
{
	g_lua = luaL_newstate();
	//打开所有lua库
	luaL_openlibs(g_lua);
	toluafix_open(g_lua);

	register_logger_export(g_lua);
	register_mysql_export(g_lua);
	register_redis_export(g_lua);
	register_service_export(g_lua);
	register_rawcmd_export(g_lua);
	register_session_export(g_lua);
	register_timer_export(g_lua);
	register_lua_export(g_lua);
	register_netbus_export(g_lua);
	register_package_proto_export(g_lua);
	register_utils_export(g_lua);
}

void lua_wrapper::Exit()
{
	if (NULL != g_lua)
	{
		lua_close(g_lua);
		g_lua = NULL;
	}
}

lua_State* lua_wrapper::lua_state()
{
	return g_lua;
}

bool lua_wrapper::DoFile(const std::string& luaFilePath)
{
	if (luaL_dofile(g_lua, luaFilePath.c_str()))
	{
		lua_log_error(g_lua);
		return false;
	}

	return true;
}

int lua_wrapper::ExeScriptHandle(int nHandler, int numArgs)
{
	int ret = 0;
	if (pushFunctionByHandler(nHandler))                                /* L: ... arg1 arg2 ... func */
	{
		if (numArgs > 0)
		{
			lua_insert(g_lua, -(numArgs + 1));                        /* L: ... func arg1 arg2 ... */
		}
		ret = executeFunction(numArgs);
	}
	lua_settop(g_lua, 0);
	return ret;
}

void lua_wrapper::RemoveScriptHandle(int handle)
{
	toluafix_remove_function_by_refid(g_lua, handle);
}

void lua_wrapper::AddSearchPath(const std::string& path)
{
	auto tempPath = path;
	if (*(tempPath.end() - 1) != '/')
	{
		tempPath += "/";
	}

	char strPath[1024] = { 0 };
	sprintf(strPath, "local path = string.match([[%s]],[[(.*)/[^/]*$]])\n package.path = package.path .. [[;]] .. path .. [[/?.lua;]] .. path .. [[/?/init.lua]]\n", tempPath.c_str());
	luaL_dostring(g_lua, strPath);
}

void lua_wrapper::ExportFunc2Lua(const char* name, int(*func)(lua_State*))
{
	lua_pushcfunction(g_lua, func);
	lua_setglobal(g_lua, name);
}

#pragma endregion

mime_type: text/plain


text:
#ifndef __CMD_PACKAGE_PROTO_EXPORT_TO_LUA_H__
#define __CMD_PACKAGE_PROTO_EXPORT_TO_LUA_H__

struct lua_State;
void register_package_proto_export(lua_State* lua);
void register_rawcmd_export(lua_State* lua);

#endif // !__CMD_PACKAGE_PROTO_EXPORT_TO_LUA_H__


text:
#ifndef __MYSQL_EXPORT_TO_LUA_H__

#define __MYSQL_EXPORT_TO_LUA_H__

struct lua_State;

int register_mysql_export(lua_State* l);
#endif // !__MYSQL_EXPORT_TO_LUA_H__


text:
#ifndef __SESSION_EXPORT_TO_LUA_H__
#define __SESSION_EXPORT_TO_LUA_H__

struct lua_State;
void register_session_export(lua_State* lua);

#endif // !__SESSION_EXPORT_TO_LUA_H__


text:
#ifndef __TIMER_EXPORT_TO_LUA_H__
#define __TIMER_EXPORT_TO_LUA_H__

struct lua_State;
void register_timer_export(lua_State* lua);

#endif // !__TIMER_EXPORT_TO_LUA_H__


text:
#include "logger_export_to_lua.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "tolua++.h"
#ifdef __cplusplus
}
#endif // __cplusplus

#include "tolua_fix.h"
#include <string>
#include "../utils/logger/logger.h"
#include "lua_wrapper.h"

#pragma region 重定义_lua_panic函数

static int lua_panic(lua_State* L)
{
	return lua_log_error(L);
}

#pragma endregion

static void
print_error(const char* file_name, int line_num, const char* msg) {
	logger::log(file_name, line_num, tag_ERROR, msg);
}

static void
print_warning(const char* file_name, int line_num, const char* msg) {
	logger::log(file_name, line_num, tag_WARNING, msg);
}

static void
print_debug(const char* file_name, int line_num, const char* msg) {
	logger::log(file_name, line_num, tag_DEBUG, msg);
}

static void
do_log_message(void(*log)(const char* file_name, int line_num, const char* msg), const char* msg) {
	lua_Debug info;
	int depth = 0;
	auto g_lua_State = lua_wrapper::lua_state();
	while (lua_getstack(g_lua_State, depth, &info)) {

		lua_getinfo(g_lua_State, "S", &info);
		lua_getinfo(g_lua_State, "n", &info);
		lua_getinfo(g_lua_State, "l", &info);

		if (info.source[0] == '@') {
			log(&info.source[1], info.currentline, msg);
			return;
		}

		++depth;
	}
	if (depth == 0) {
		log("trunk", 0, msg);
	}
}

static int
lua_log_debug(lua_State* luastate) {
	int nargs = lua_gettop(luastate);
	std::string t;
	for (int i = 1; i <= nargs; i++)
	{
		if (lua_istable(luastate, i))
			t += "table";
		else if (lua_isnone(luastate, i))
			t += "none";
		else if (lua_isnil(luastate, i))
			t += "nil";
		else if (lua_isboolean(luastate, i))
		{
			if (lua_toboolean(luastate, i) != 0)
				t += "true";
			else
				t += "false";
		}
		else if (lua_isfunction(luastate, i))
			t += "function";
		else if (lua_islightuserdata(luastate, i))
			t += "lightuserdata";
		else if (lua_isthread(luastate, i))
			t += "thread";
		else
		{
			const char* str = lua_tostring(luastate, i);
			if (str)
				t += lua_tostring(luastate, i);
			else
				t += lua_typename(luastate, lua_type(luastate, i));
		}
		if (i != nargs)
			t += "\t";
	}
	do_log_message(print_debug, t.c_str());
	return 0;
}

static int
lua_log_warning(lua_State* luastate) {
	int nargs = lua_gettop(luastate);
	std::string t;
	for (int i = 1; i <= nargs; i++)
	{
		if (lua_istable(luastate, i))
			t += "table";
		else if (lua_isnone(luastate, i))
			t += "none";
		else if (lua_isnil(luastate, i))
			t += "nil";
		else if (lua_isboolean(luastate, i))
		{
			if (lua_toboolean(luastate, i) != 0)
				t += "true";
			else
				t += "false";
		}
		else if (lua_isfunction(luastate, i))
			t += "function";
		else if (lua_islightuserdata(luastate, i))
			t += "lightuserdata";
		else if (lua_isthread(luastate, i))
			t += "thread";
		else
		{
			const char* str = lua_tostring(luastate, i);
			if (str)
				t += lua_tostring(luastate, i);
			else
				t += lua_typename(luastate, lua_type(luastate, i));
		}
		if (i != nargs)
			t += "\t";
	}
	do_log_message(print_warning, t.c_str());
	return 0;
}

int lua_log_error(lua_State* luastate) {
	int nargs = lua_gettop(luastate);
	std::string t;
	for (int i = 1; i <= nargs; i++)
	{
		if (lua_istable(luastate, i))
			t += "table";
		else if (lua_isnone(luastate, i))
			t += "none";
		else if (lua_isnil(luastate, i))
			t += "nil";
		else if (lua_isboolean(luastate, i))
		{
			if (lua_toboolean(luastate, i) != 0)
				t += "true";
			else
				t += "false";
		}
		else if (lua_isfunction(luastate, i))
			t += "function";
		else if (lua_islightuserdata(luastate, i))
			t += "lightuserdata";
		else if (lua_isthread(luastate, i))
			t += "thread";
		else
		{
			const char* str = lua_tostring(luastate, i);
			if (str)
				t += lua_tostring(luastate, i);
			else
				t += lua_typename(luastate, lua_type(luastate, i));
		}
		if (i != nargs)
			t += "\t";
	}
	do_log_message(print_error, t.c_str());
	return 0;
}

static int
lua_logger_init(lua_State* tolua_S) {
	if (3 != lua_gettop(tolua_S))
	{
		log_error("函数调用错误");
		return 0;
	}

	const char* path = lua_tostring(tolua_S, 1);
	if (path == NULL) {
		return 0;
	}

	const char* prefix = lua_tostring(tolua_S, 2);
	if (prefix == NULL) {
		return 0;
	}

	bool std_out = lua_toboolean(tolua_S, 3);
	logger::init(path, prefix, std_out);

	return 0;
}

int register_logger_export(lua_State* tolua_S)
{

	//重定义终止函数，默认是直接终止
	lua_atpanic(tolua_S, lua_panic);

	//重载print
	lua_wrapper::ExportFunc2Lua("print", lua_log_debug);

	lua_getglobal(tolua_S, "_G");
	if (lua_istable(tolua_S, -1)) {
		tolua_open(tolua_S);
		tolua_module(tolua_S, "Debug", 0);
		tolua_beginmodule(tolua_S, "Debug");

		tolua_function(tolua_S, "LogInit", lua_logger_init);
		tolua_function(tolua_S, "Log", lua_log_debug);
		tolua_function(tolua_S, "LogWarning", lua_log_warning);
		tolua_function(tolua_S, "LogError", lua_log_error);
		tolua_endmodule(tolua_S);
	}
	lua_pop(tolua_S, 1);
	return 0;
}


text:
#include "timer_export_to_lua.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "tolua++.h"
#ifdef __cplusplus
}
#endif // __cplusplus

#include "tolua_fix.h"
#include "lua_wrapper.h"
#include <cstdlib>

#include "../utils/timer/time_list.h"
#include "../utils/cache_alloc/small_alloc.h"
#include "../utils/logger/logger.h"

#define my_alloc small_alloc
#define my_free small_free

struct timer_repeat
{
	int handler;
	int repeat_count;
};

static void on_lua_repeat_func(void* udata)
{
	auto tr = (timer_repeat*)udata;
	lua_wrapper::ExeScriptHandle(tr->handler,0);
	if (tr->repeat_count-- <= -1)
	{
		return;
	}
	if (tr->repeat_count == 0)
	{
		lua_wrapper::RemoveScriptHandle(tr->handler);
		my_free(tr);
	}
}

// handler,delay,times,delta
static int lua_timer_repeat(lua_State* lua)
{
	if (4 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto handle = toluafix_ref_function(lua, 1, 0);

	if (!handle)
	{
		lua_pushnil(lua);
		return 1;
	}
	auto after_msec = (int)lua_tointeger(lua, 2, 0);
	if (after_msec < 0)
	{
		if (handle)
		{
			lua_wrapper::RemoveScriptHandle(handle);
		}
		lua_pushnil(lua);
		return 1;
	}
	auto repeatCount = (int)lua_tointeger(lua, 3, );
	if (repeatCount == 0)
	{
		if (handle)
		{
			lua_wrapper::RemoveScriptHandle(handle);
		}
		lua_pushnil(lua);
		return 1;
	}
	else if (repeatCount < 0)
	{
		repeatCount = -1;
	}

	auto repeate_msec = (int)lua_tointeger(lua, 4, 0);
	if (repeate_msec <= 0)
	{
		repeate_msec = after_msec;
	}

	auto tr = (timer_repeat*)my_alloc(sizeof(timer_repeat));
	tr->handler = handle;
	tr->repeat_count = repeatCount;

	auto t = schedule_repeat(on_lua_repeat_func, tr, after_msec, repeatCount, repeate_msec);
	tolua_pushuserdata(lua, t);
	return 1;
}
static int lua_timer_once(lua_State* lua)
{
	if (2 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto handle = toluafix_ref_function(lua, 1, 0);
	if (!handle)
	{
		lua_pushnil(lua);
		return 1;
	}
	auto after_msec = (int)lua_tointeger(lua, 2, 0);
	if (after_msec < 0)
	{
		if (handle)
		{
			lua_wrapper::RemoveScriptHandle(handle);
		}
		lua_pushnil(lua);
		return 1;
	}
	auto tr = (timer_repeat*)my_alloc(sizeof(timer_repeat));
	tr->handler = handle;
	tr->repeat_count = 1;

	auto t = schedule_once(on_lua_repeat_func, tr, after_msec);
	tolua_pushuserdata(lua, t);
	return 1;
}
static int lua_timer_cancel(lua_State* lua)
{
	if (1 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	if (!lua_isuserdata(lua, 1))
	{
		return 0;
	}
	auto t = (timer*)lua_touserdata(lua, 1);
	auto tr = (timer_repeat*)get_timer_udata(t);
	lua_wrapper::RemoveScriptHandle(tr->handler);
	my_free(tr);
	cancel_timer(t);
	return 0;
}

void register_timer_export(lua_State* tolua_S)
{
	lua_getglobal(tolua_S, "_G");
	if (lua_istable(tolua_S, -1)) {
		tolua_open(tolua_S);
		tolua_module(tolua_S, "Timer", 0);
		tolua_beginmodule(tolua_S, "Timer");

		tolua_function(tolua_S, "Repeat", lua_timer_repeat);
		tolua_function(tolua_S, "Once", lua_timer_once);
		tolua_function(tolua_S, "Cancel", lua_timer_cancel);
		tolua_endmodule(tolua_S);
	}
	lua_pop(tolua_S, 1);
}


text:
#ifndef __SERVICE_EXPORT_TO_LUA_H__
#define __SERVICE_EXPORT_TO_LUA_H__

#include "../netbus/service/AbstractService.h"

struct lua_State;
int register_service_export(lua_State* lua);

class LuaService :
	public AbstractService
{
public:
	unsigned int luaRecvCmdPackageHandle;
	unsigned int luaConnFuncHandle;
	unsigned int luaDisconnectFuncHandle;
	unsigned int luaRecvRawPackageHandle;

	//Session接收到RawPackage时调用
	virtual bool OnSessionRecvRawPackage(const AbstractSession* session, const RawPackage* package)const override;

	//Session接收到CmdPackage时调用
	virtual bool OnSessionRecvCmdPackage(const AbstractSession* session, const CmdPackage* package)const override;
	//Session关闭时调用
	virtual bool OnSessionDisconnected(const AbstractSession* session,const int& serviceType)const override;

	virtual void OnSessionConnected(const AbstractSession* session, const int& serviceType)const override;

};

#endif // !__SERVICE_EXPORT_TO_LUA_H__


text:
#ifndef __LOGGER_EXPORT_TO_LUA_H__
#define __LOGGER_EXPORT_TO_LUA_H__

struct lua_State;

int register_logger_export(lua_State* lua);
int lua_log_error(lua_State* lua);

#endif // !__LOGGER_EXPORT_TO_LUA_H__


text:
#include "netbus_export_to_lua.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "tolua++.h"
#ifdef __cplusplus
}
#endif // __cplusplus

#include "tolua_fix.h"

#include "../netbus/Netbus.h"
#include "lua_wrapper.h"
#include "../utils/logger/logger.h"

static void on_tcp_connect(int err, AbstractSession* s, void* udata)
{
	auto lua = lua_wrapper::lua_state();
	if (err)
	{
		lua_pushnil(lua);
	}
	else {
		tolua_pushuserdata(lua, s);
	}
	lua_wrapper::ExeScriptHandle((int)udata, 1);
	lua_wrapper::RemoveScriptHandle((int)udata);
}

static void on_tcp_listen(AbstractSession* s, void* udata)
{
	//如果没有自定义参数就是没有传递第二第三参数
	if (udata == NULL)
		return;
	auto lua = lua_wrapper::lua_state();
	tolua_pushuserdata(lua, s);
	lua_wrapper::ExeScriptHandle((int)udata, 1);
	//lua_wrapper::RemoveScriptHandle((int)udata);
}

static void on_ws_listen(AbstractSession* s, void* udata)
{
	//如果没有自定义参数就是没有传递第二第三参数
	if (udata == NULL)
		return;
	auto lua = lua_wrapper::lua_state();
	tolua_pushuserdata(lua, s);
	lua_wrapper::ExeScriptHandle((int)udata, 1);
	//lua_wrapper::RemoveScriptHandle((int)udata);
}

// ip port lua_func
static int lua_tcp_connect(lua_State* lua)
{
	if (3 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto ip = luaL_checkstring(lua, 1);
	if (NULL == ip)
		return 0;
	auto port = luaL_checkinteger(lua, 2);
	auto handle = toluafix_ref_function(lua, 3, 0);
	if (0 == handle)
		return 0;

	Netbus::Instance()->TcpConnect(ip, port, on_tcp_connect, (void*)handle);
	return 0;
}

static int lua_tcp(lua_State* lua)
{
	auto cout = lua_gettop(lua);
	auto port = luaL_checkinteger(lua, 1);
	if (cout == 1)
	{
		Netbus::Instance()->TcpListen(port);
	}
	else if(cout == 2)
	{
		auto handle = toluafix_ref_function(lua, 2, 0);
		if (0 == handle)
		{
			log_error("TcpListen_函数句柄无效");
			return 0;
		}

		Netbus::Instance()->TcpListen(port, on_tcp_listen, (void*)handle);
	}else
	{
		log_error("TcpListen_函数调用错误");
	}

	return 0;
}
static int lua_udp(lua_State* lua)
{
	if (1 != lua_gettop(lua))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto port = (int)lua_tointeger(lua, 1);
	Netbus::Instance()->UdpListen(port);

	return 0;
}
static int lua_websocket(lua_State* lua)
{
	auto cout = lua_gettop(lua);
	auto port = luaL_checkinteger(lua, 1);
	if (cout == 1)
	{
		Netbus::Instance()->WebSocketListen(port);
	}
	else if (cout == 2)
	{
		auto handle = toluafix_ref_function(lua, 2, 0);
		if (0 == handle)
			return 0;

		Netbus::Instance()->WebSocketListen(port, on_ws_listen, (void*)handle);
	}else
	{
		log_error("函数调用错误");
		return 0;
	}

	return 0;
}

#include<map>
#include<string>
using std::map;
using std::string;
void register_netbus_export(lua_State* tolua_S)
{
	lua_getglobal(tolua_S, "_G");
	if (lua_istable(tolua_S, -1)) {
		tolua_open(tolua_S);
		tolua_module(tolua_S, "Netbus", 0);
		tolua_beginmodule(tolua_S, "Netbus");

		tolua_function(tolua_S, "TcpListen", lua_tcp);
		tolua_function(tolua_S, "UdpListen", lua_udp);
		tolua_function(tolua_S, "WebsocketListen", lua_websocket);
		tolua_function(tolua_S, "TcpConnect", lua_tcp_connect);
		tolua_endmodule(tolua_S);
	}
	lua_pop(tolua_S, 1);
}


text:
#ifndef __LUA_WRAPPER_H__
#define __LUA_WRAPPER_H__

#include <lua.hpp>
#include <string>

class lua_wrapper
{
public:
	static void Init();
	static void Exit();

	static lua_State* lua_state();

	//执行lua文件
	static bool DoFile(const std::string& luaFile);
	//调用脚本函数
	static int ExeScriptHandle(int handle, int numArgs);
	//移除脚本函数
	static void RemoveScriptHandle(int handle);
	static void AddSearchPath(const std::string& path);
	//导出C/C++函数
	static void ExportFunc2Lua(
		const char* name,
		int (*func)(lua_State*));

};

#endif // !__LUA_WRAPPER_H__


text:
#ifndef __NETBUS_EXPORT_TO_LUA_H__
#define __NETBUS_EXPORT_TO_LUA_H__

struct lua_State;

void register_netbus_export(lua_State* lua);

#endif // !__NETBUS_EXPORT_TO_LUA_H__


text:
#include "redis_export_to_lua.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "tolua++.h"
#ifdef __cplusplus
}
#endif // __cplusplus

#include "tolua_fix.h"
#include "../database/rediswarpper.h"
#include "../utils/logger/logger.h"
#include "lua_wrapper.h"

static void push_result_to_lua(redisReply* result)
{
	auto lua = lua_wrapper::lua_state();
	int index = 1;
	switch (result->type)
	{
	case REDIS_REPLY_ARRAY:
		lua_newtable(lua);
		for (auto i = 0; i < result->elements; i++)
		{
			push_result_to_lua(result->element[i]);
			lua_rawseti(lua, -2, index);
			++index;
		}

		break;
	case REDIS_REPLY_INTEGER:
		lua_pushinteger(lua, result->integer);
		break;
	case REDIS_REPLY_NIL:
		lua_pushnil(lua);
		break;
	case REDIS_REPLY_STATUS:
	case REDIS_REPLY_STRING:
		lua_pushstring(lua, result->str);
		break;
	}
}

#pragma region Callback
static void
on_open_cb(const char* err, RedisContext* context) {
	if (err) {
		lua_pushstring(lua_wrapper::lua_state(), err);
		lua_pushnil(lua_wrapper::lua_state());
	}
	else {
		lua_pushnil(lua_wrapper::lua_state());
		tolua_pushuserdata(lua_wrapper::lua_state(), context);
	}

	lua_wrapper::ExeScriptHandle((int)context->udata, 2);
	lua_wrapper::RemoveScriptHandle((int)context->udata);
}

static void
on_lua_query_cb(const char* err, RedisReply* result)
{
	auto lua = lua_wrapper::lua_state();
	if (err)
	{
		lua_pushstring(lua, err);
		lua_pushnil(lua);
	}
	else
	{
		lua_pushnil(lua);
		if (result->reply)
		{// 把查询到的结果push成一个表
			push_result_to_lua(result->reply);
		}
		else
		{
			lua_pushnil(lua_wrapper::lua_state());
		}
	}

	lua_wrapper::ExeScriptHandle((int)result->udata, 2);
	lua_wrapper::RemoveScriptHandle((int)result->udata);
}
#pragma endregion

static int
lua_redis_connect(lua_State* tolua_S) {
	if (3 != lua_gettop(tolua_S))
	{
		log_error("函数调用错误");
		return 0;
	}
	char* ip = (char*)tolua_tostring(tolua_S, 1, 0);
	if (ip == NULL) {
		return 0;
	}

	int port = (int)tolua_tonumber(tolua_S, 2, 0);

	int handler = toluafix_ref_function(tolua_S, 3, 0);
	redis_wrapper::connect(ip, port, on_open_cb, (void*)handler, false);
	return 0;
}

static int
lua_redis_close(lua_State* tolua_S) {
	if (1 != lua_gettop(tolua_S))
	{
		log_error("函数调用错误");
		return 0;
	}
	void* context = tolua_touserdata(tolua_S, 1, 0);
	if (context) {
		redis_wrapper::close_redis((RedisContext*)context);
	}
	else
	{
		log_error("Redis 关闭异常");
	}

	return 0;
}

static int
lua_redis_query(lua_State* tolua_S) {
	if (3 != lua_gettop(tolua_S))
	{
		log_error("函数调用错误");
		return 0;
	}
	auto context = tolua_touserdata(tolua_S, 1, 0);
	if (!context)
		return 0;
	auto cmd = tolua_tostring(tolua_S, 2, 0);
	if (!cmd)
		return 0;
	auto handle = toluafix_ref_function(tolua_S, 3, 0);
	if (!handle)
		return 0;
	redis_wrapper::query(
		(RedisContext*)context,
		(char*)cmd,
		on_lua_query_cb,
		(void*)handle,
		false);
	return 0;
}

int register_redis_export(lua_State* tolua_S)
{
	lua_getglobal(tolua_S, "_G");
	if (lua_istable(tolua_S, -1)) {
		tolua_open(tolua_S);
		tolua_module(tolua_S, "Redis", 0);
		tolua_beginmodule(tolua_S, "Redis");

		tolua_function(tolua_S, "Connect", lua_redis_connect);
		tolua_function(tolua_S, "Close", lua_redis_close);
		tolua_function(tolua_S, "Query", lua_redis_query);
		tolua_endmodule(tolua_S);
	}
	lua_pop(tolua_S, 1);
	return 0;
}


text:
#ifndef __UTILS_EXPORT_TO_LUA_H__
#define __UTILS_EXPORT_TO_LUA_H__

struct lua_State;
void register_utils_export(lua_State* lua);

#endif // !__UTILS_EXPORT_TO_LUA_H__


text:
#include "utils_export_to_lua.h"

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "tolua++.h"
#ifdef __cplusplus
}
#endif // __cplusplus

#include "tolua_fix.h"
#include "lua_wrapper.h"
#include "../utils/timestamp/timestamp.h"

static int lua_timestamp(lua_State* lua)
{
	auto ts = timestamp();
	lua_pushinteger(lua, ts);
	return 1;
}
static int lua_today(lua_State* lua)
{
	auto ts = timestamp_today();
	lua_pushinteger(lua, ts);
	return 1;

}
static int lua_yesterday(lua_State* lua)
{
	auto ts = timestamp_yesterday();
	lua_pushinteger(lua, ts);
	return 1;

}

void register_utils_export(lua_State* tolua_S)
{
	lua_getglobal(tolua_S, "_G");
	if (lua_istable(tolua_S, -1)) {
		tolua_open(tolua_S);
		tolua_module(tolua_S, "Utils", 0);
		tolua_beginmodule(tolua_S, "Utils");

		tolua_function(tolua_S, "TimeStamp", lua_timestamp);
		tolua_function(tolua_S, "Today", lua_today);
		tolua_function(tolua_S, "Yesterday", lua_yesterday);
		tolua_endmodule(tolua_S);
	}
	lua_pop(tolua_S, 1);
}


text:
#ifndef __REDIS_EXPORT_TO_LUA_H__
#define __REDIS_EXPORT_TO_LUA_H__

struct lua_State;
int register_redis_export(lua_State* lua);

#endif // !__REDIS_EXPORT_TO_LUA_H__