Procházet zdrojové kódy

优化;删除预编译字节码

xx před 2 roky
rodič
revize
306852b476

+ 0 - 80
src/core/bytecodemanager.cpp

@@ -1,80 +0,0 @@
-
-#include "bytecodemanager.h"
-#if ENABLE_BYTECODE == 1
-#include "fastweb.h"
-#include "utils/luautils.h"
-#include "util/file.h"
-#include "util/system.h"
-#include "core/config.h"
-bytecode_manager::bytecode_manager()
-{
-	::ithread::start();
-}
-
-bytecode_manager::~bytecode_manager()
-{
-	::ithread::stop();
-	::ithread::wait();
-}
-
-bool bytecode_manager::create(const std::string& name, const std::string& filepath, bool auto_update)
-{
-	std::shared_ptr<bytecode> bc;
-	if (m_bytescodes.get(name, bc))
-	{
-		m_lastErrorDesc = "The bytecode already exists, name: " + name;
-		return false;
-	}
-	bc = std::make_shared<bytecode>();
-	if (LuaUtils::make_bytecode(filepath, bc->value) == false)
-	{
-		m_lastErrorDesc = "make bytecode failed.";
-		return false;
-	}
-	bc->filepath = filepath;
-	bc->auto_update = true;
-	bc->auto_update = auto_update;
-	bc->pre_modify_msec = ylib::file::last_write_time(filepath);
-	m_bytescodes.add(name, bc);
-	return true;
-}
-
-const std::string& bytecode_manager::get(const std::string& name)
-{
-	static std::string return_empty;
-	std::shared_ptr<bytecode> bc;
-	if (m_bytescodes.get(name, bc) == false)
-	{
-		return return_empty;
-	}
-	return bc->value;
-}
-
-std::map<std::string, std::shared_ptr<bytecode>> bytecode_manager::map()
-{
-	return *m_bytescodes.parent();
-}
-
-bool bytecode_manager::run()
-{
-	m_bytescodes.lock();
-	auto map = m_bytescodes.parent();
-	for_iter(iter, (*map))
-	{
-		if (iter->second->auto_update == false)
-			continue;
-
-		auto last_write_time = ylib::file::last_write_time(iter->second->filepath);
-		if (last_write_time != iter->second->pre_modify_msec)
-		{
-			LuaUtils::make_bytecode(iter->second->filepath, iter->second->value);
-			iter->second->pre_modify_msec = last_write_time;
-		}
-	}
-	m_bytescodes.unlock();
-
-	system::sleep_msec(sConfig->scripts.auto_update_sec);
-
-	return true;
-}
-#endif

+ 0 - 45
src/core/bytecodemanager.h

@@ -1,45 +0,0 @@
-#pragma once
-
-#include "core/define.h"
-#if ENABLE_BYTECODE == 1
-#include "sol/sol.hpp"
-
-#include "base/error.h"
-#include "base/singleton.hpp"
-#include "util/thread.h"
-#include "util/queue.hpp"
-#include "util/map.hpp"
-
-#include "core/structs.h"
-
-/// <summary>
-/// 字节码管理器
-/// </summary>
-class bytecode_manager:public ylib::error_base,private ylib::ithread {
-public:
-	bytecode_manager();
-	~bytecode_manager();
-	/// <summary>
-	/// 创建字节码
-	/// </summary>
-	/// <param name="name"></param>
-	/// <param name="filepath"></param>
-	/// <param name="auto_update"></param>
-	/// <returns></returns>
-	bool create(const std::string& name,const std::string& filepath,bool auto_update);
-	/// <summary>
-	/// 取字节码
-	/// </summary>
-	/// <param name="name"></param>
-	/// <returns></returns>
-	const std::string& get(const std::string& name);
-
-	std::map<std::string, std::shared_ptr<bytecode>> map();
-private:
-	// ServiceLUA文件
-	ylib::map<std::string, std::shared_ptr<bytecode>> m_bytescodes;
-
-	// 通过 ithread 继承
-	bool run() override;
-};
-#endif

+ 24 - 5
src/core/config.cpp

@@ -35,14 +35,33 @@ bool config::open(const std::string& ini_filepath)
 	cache();
 	return true;
 }
-bool config::have_https()
+std::vector<std::string> config::lua_app_files()
 {
-	for_iter(iter, domain)
+	std::vector<std::string> results;
+	auto luas = ylib::file::traverse(sConfig->scripts.app_dir, "(.*\\.lua)");
+	for_iter(iter, luas)
+	{
+		if (iter->second == IS_DIRECTORY)
+			continue;
+		std::string path = strutils::replace(iter->first, '\\', '/');
+
+		results.push_back(path);
+	}
+	return results;
+}
+std::vector<std::string> config::lua_lib_files()
+{
+	std::vector<std::string> results;
+	auto luas = ylib::file::traverse(sConfig->scripts.lib_dir, "(.*\\.lua)");
+	for_iter(iter, luas)
 	{
-		if (iter->second.https)
-			return true;
+		if (iter->second == IS_DIRECTORY)
+			continue;
+		std::string path = strutils::replace(iter->first, '\\', '/');
+
+		results.push_back(path);
 	}
-	return false;
+	return results;
 }
 std::vector<std::string> config::extractVariableNames(const std::string& text)
 {

+ 2 - 5
src/core/config.h

@@ -37,11 +37,8 @@ public:
 	config() = default;
 	bool open(const std::string& ini_filepath);
 
-	/// <summary>
-	/// 是否含有https
-	/// </summary>
-	/// <returns></returns>
-	bool have_https();
+	std::vector<std::string> lua_app_files();
+	std::vector<std::string> lua_lib_files();
 private:
 	// INI配置文件
 	ylib::ini m_ini;

+ 0 - 1
src/core/define.h

@@ -30,4 +30,3 @@
 #define VarType sol::object
 
 
-#define ENABLE_BYTECODE 0

+ 10 - 2
src/core/entry.cpp

@@ -8,7 +8,7 @@ extern "C" {
 #ifdef _WIN32
 	DLL_EXPORT
 #endif
-	int fastweb(const char* config_filepath)
+	int fastweb_start(const char* config_filepath)
 	{
 		std::cout << "=========== [fastweb engine] ============" << std::endl;
 		if (sConfig->open(config_filepath) == false)
@@ -25,4 +25,12 @@ extern "C" {
 		LOG_SUCC("success");
 		return 0;
 	}
-}
+#ifdef _WIN32
+	DLL_EXPORT
+#endif
+		void fastweb_close()
+	{
+		fastweb::getInstance()->stop();
+	}
+}
+

+ 2 - 1
src/core/entry.h

@@ -4,6 +4,7 @@
 #define DLL_EXPORT __attribute__((visibility("default")))
 #endif
 extern "C" {
-	DLL_EXPORT int fastweb(const char* config_filepath);
+	DLL_EXPORT int fastweb_start(const char* config_filepath);
+	DLL_EXPORT void fastweb_close();
 }
  

+ 22 - 324
src/core/fastweb.cpp

@@ -8,8 +8,10 @@
 #include "module/http/response.h"
 #include "module/globalfuns.h"
 #include "core/config.h"
+#include "core/global.h"
 #include "core/statemanager.h"
-
+#include "core/subscribemanager.h"
+#include "core/interceptormanager.h"
 bool fastweb::start()
 {
 
@@ -59,210 +61,34 @@ bool fastweb::start()
 	// 初始化脚本
 	if (initialization_script() == false)
 		return false;
-#if ENABLE_BYTECODE == 1
-	// 加载服务脚本
-	{
-		auto luas = ylib::file::traverse(sConfig->scripts.app_dir, "(.*\\.lua)");
-		for_iter(iter, luas) {
-			if (iter->second == IS_DIRECTORY)
-				continue;
-			std::string path = strutils::replace(iter->first, '\\', '/');
-			if (service_bytecode.create(path, sConfig->scripts.app_dir + "/" + path, true) == false)
-			{
-				m_lastErrorDesc = service_bytecode.last_error();
-				return false;
-			}
-		}
-	}
-
-	// 加载拦截器脚本
-	for_iter(iter, sConfig->website.interceptor_scripts) {
-		if (interceptor_bytecode.create(iter->regex_express, iter->filepath, true) == false)
-		{
-			m_lastErrorDesc = interceptor_bytecode.last_error();
-			return false;
-		}
-	}
-
-	// 加入LUA服务映射
-	{
-		auto map = service_bytecode.map();
-		for_iter(iter, map)
-		{
-			auto state = sStateMgr->get_state();
-			std::string route_pattern;
-			network::http::method method = network::http::ALL;
-			try
-			{
-				auto result = state->script_file(iter->second->filepath);
-				if (result.valid()) {
-					auto router = (*state)["route"];
-					auto type = router.get_type();
-					if (router.is<sol::table>())
-					{
-						sol::optional<std::string> route_pattern_param = router[1];
-						sol::optional<int> method_param = router[2];
-						if (route_pattern_param && route_pattern_param->empty() == false)
-							route_pattern = *route_pattern_param;
-						if (method_param)
-							method = (network::http::method)*method_param;
-					}
-				}
-			}
-			catch (const std::exception& e)
-			{
-				LOG_ERROR(e.what());
-			}
-			if (route_pattern.empty())
-				route_pattern = sConfig->scripts.app_mapping_dir + iter->first;
 
-			// OutPutLog
-			{
-				std::string log;
-				log = "[subscribe] lua: " + iter->first + "\t pattern: " + route_pattern + "\t method: ";
-				switch (method)
-				{
-				case ylib::network::http::GET:
-					log.append("GET");
-					break;
-				case ylib::network::http::POST:
-					log.append("POST");
-					break;
-				case ylib::network::http::PUT:
-					log.append("PUT");
-					break;
-				case ylib::network::http::DEL:
-					log.append("DEL");
-					break;
-				case ylib::network::http::HEAD:
-					log.append("HEAD");
-					break;
-				case ylib::network::http::ALL:
-					log.append("ALL");
-					break;
-				default:
-					break;
-				}
-				LOG_INFO(log);
-			}
-			router->subscribe(route_pattern, method, &fastweb::subscribe_service,new std::string(iter->first));
-		}
-			
-	}
-#else
-	// 加入LUA服务映射
-	{
-		auto luas = ylib::file::traverse(sConfig->scripts.app_dir, "(.*\\.lua)");
-		for_iter(iter, luas)
-		{
-			if (iter->second == IS_DIRECTORY)
-				continue;
-			std::string path = strutils::replace(iter->first, '\\', '/');
-			auto state = sStateMgr->get_state();
-			std::string route_pattern;
-			network::http::method method = network::http::ALL;
-			try
-			{
-				auto result = state->script_file(sConfig->scripts.app_dir+"/"+ path);
-				if (result.valid()) {
-					auto router = (*state)["route"];
-					auto type = router.get_type();
-					if (router.is<sol::table>())
-					{
-						sol::optional<std::string> route_pattern_param = router[1];
-						sol::optional<int> method_param = router[2];
-						if (route_pattern_param && route_pattern_param->empty() == false)
-							route_pattern = *route_pattern_param;
-						if (method_param)
-							method = (network::http::method)*method_param;
-					}
-				}
-			}
-			catch (const std::exception& e)
-			{
-				LOG_ERROR(e.what());
-			}
-			if (route_pattern.empty())
-				route_pattern = sConfig->scripts.app_mapping_dir + path;
-
-			// OutPutLog
-			{
-				std::string log;
-				log = "[subscribe] lua: " +path + "\t pattern: " + route_pattern + "\t method: ";
-				switch (method)
-				{
-				case ylib::network::http::GET:
-					log.append("GET");
-					break;
-				case ylib::network::http::POST:
-					log.append("POST");
-					break;
-				case ylib::network::http::PUT:
-					log.append("PUT");
-					break;
-				case ylib::network::http::DEL:
-					log.append("DEL");
-					break;
-				case ylib::network::http::HEAD:
-					log.append("HEAD");
-					break;
-				case ylib::network::http::ALL:
-					log.append("ALL");
-					break;
-				default:
-					break;
-				}
-				LOG_INFO(log);
-			}
-			router->subscribe(route_pattern, method, &fastweb::subscribe_service, new std::string(sConfig->scripts.app_dir+"/" +path));
-		}
 
-	}
-#endif
-	// 加入拦截器
-	for (size_t i = 0; i < sConfig->website.interceptor_scripts.size(); i++)
-	{
-#if ENABLE_BYTECODE == 0
-		interceptor.emplace(sConfig->website.interceptor_scripts[i].regex_express,sConfig->website.interceptor_scripts[i].filepath);
-#endif
-		router->interceptor()->add(sConfig->website.interceptor_scripts[i].regex_express, &fastweb::subscribe_interceptor);
-	}
+	// 加载订阅
+	m_subscribe.load(router);
+	// 加载拦截器
+	m_interceptor.load(router);
+	
 		
 
-
-	router->other([&](network::http::request* request, network::http::response* response) {
-		if (request->filepath() == "/")
-		{
-			bool find = false;
-			for (size_t i = 0; i < sConfig->website.default_index.size(); i++)
-			{
-				std::string filepath = sConfig->website.static_dir + request->filepath() + sConfig->website.default_index[i];
-				if (ylib::file::exist(filepath))
-				{
-					find = true;
-					response->send_file(filepath);
-					break;
-				}
-			}
-			if (find == false)
-				send_404(response);
-			return;
-		}
-
-		send_file(response,request->filepath());
-	});
-
-
 	return m_center->start();
 }
 
 void fastweb::stop()
 {
+	m_subscribe.clear();
+	m_interceptor.clear();
 	if (m_center != nullptr)
 	{
+		m_center->close();
 		delete m_center;
 	}
 	m_center = nullptr;
+
+	global::getInstance()->clear();
+	if (m_state_init != nullptr)
+		delete m_state_init;
+	m_state_init = nullptr;
+	sStateMgr->close();
 }
 
 bool fastweb::initialization_script()
@@ -275,11 +101,11 @@ bool fastweb::initialization_script()
 		m_lastErrorDesc = "Initialization script not found, filepath: " + script_filepath;
 		return false;
 	}
-	auto state = sStateMgr->get_state();
+	auto state = sStateMgr->get();
 	try
 	{
-		state->set_function("global_regist", module::global_regist);
-		auto result = state->script_file(script_filepath);
+		state->state->set_function("global_regist", module::global_regist);
+		auto result = state->state->script_file(script_filepath);
 		if (!result.valid()) {
 			sol::error err = result;
 			throw ylib::exception(err.what());
@@ -295,134 +121,6 @@ bool fastweb::initialization_script()
 	}
 	// 不可DELETE,否则注册的全局变量会被自动销毁
 	//delete state;
+	m_state_init = state;
 	return m_lastErrorDesc == "";
-}
-
-void fastweb::subscribe_service(network::http::request* request, network::http::response* response,void *extra)
-{
-	std::string lua_name = *(std::string*)extra;
-
-	// 文件原路径(非绝对路径)
-	//std::string lua_name = strutils::right(request->filepath(), request->filepath().length() - sConfig->scripts.app_mapping_dir.length());
-
-
-	auto lua = sStateMgr->get_state();
-	std::string exception_string;
-	try
-	{
-#if ENABLE_BYTECODE == 1
-		auto bytecode = sFastWeb->service_bytecode.get(lua_name);
-		if (bytecode.empty())
-			throw ylib::exception("Serious error: Bytecode not found, possibly due to pre compilation modification error. Please recheck the script file, "+lua_name);
-		auto lbResult = lua->load_buffer(bytecode.data(), bytecode.length(), "bytecode");
-#else
-		auto lbResult = lua->load_file(lua_name);
-#endif
-		if (lbResult.valid() == false)
-		{
-			sol::error err = lbResult;
-			throw ylib::exception("Failed to load bytecode, " + std::string(err.what()));
-		}
-		module::request m_request(request);
-		module::response m_response(response);
-		
-		lbResult();
-
-		(*lua)["response"] = &m_response;
-		(*lua)["request"] = &m_request;
-
-		auto result = (*lua)["access"]();
-		if (!result.valid()) {
-			sol::error err = result;
-			throw ylib::exception(err.what());
-		}
-	}
-	catch (const std::exception& e)
-	{
-		exception_string = e.what();
-		if(sConfig->website.debug)
-			LOG_ERROR("[subscribe_service]["+ request->filepath() + "]: "+e.what());
-	}
-	lua->collect_garbage();
-	sStateMgr->push_state(lua);
-
-	if (exception_string.empty() == false)
-		throw ylib::exception(exception_string);
-}
-
-bool fastweb::subscribe_interceptor(network::http::reqpack* reqpack, const std::string& express_string)
-{
-	
-	bool ok_continue = false;
-	auto lua = sStateMgr->get_state();
-	std::string exception_string;
-	try
-	{
-#if ENABLE_BYTECODE == 1
-		const std::string& bytecode = sFastWeb->interceptor_bytecode.get(express_string);
-		if (bytecode.empty())
-			throw ylib::exception("[interceptor] Serious error: Bytecode not found, possibly due to pre compilation modification error. Please recheck the script file, " + express_string);
-
-		auto lbResult = lua->load_buffer(bytecode.data(), bytecode.length(), "bytecode");
-#else
-		auto lbResult = lua->load_file(sFastWeb->interceptor[express_string]);
-#endif
-		if (lbResult.valid() == false)
-		{
-			sol::error err = lbResult;
-			throw ylib::exception("[interceptor] Failed to load bytecode, " + std::string(err.what()));
-		}
-		module::request m_request(reqpack->request());
-		module::response m_response(reqpack->response());
-
-		lbResult();
-
-		(*lua)["response"] = m_response;
-		(*lua)["request"] = m_request;
-
-		auto result = (*lua)["access"]();
-		if (!result.valid()) {
-			sol::error err = result;
-			throw ylib::exception(err.what());
-		}
-		ok_continue = result.get<bool>();
-	}
-	catch (const std::exception& e)
-	{
-		exception_string = e.what();
-		if (sConfig->website.debug)
-			LOG_ERROR("[subscribe_interceptor][" + reqpack->request()->filepath() + "]: " + e.what());
-	}
-	sStateMgr->push_state(lua);
-
-	if (exception_string.empty() == false)
-		throw ylib::exception(exception_string);
-
-	return ok_continue;
-}
-
-void fastweb::send_file(network::http::response* response, std::string filepath)
-{
-	filepath = sConfig->website.static_dir + filepath;
-	if (ylib::file::exist(filepath))
-	{
-		response->send_file(filepath);
-	}
-	else
-	{
-		send_404(response);
-	}
-}
-
-void fastweb::send_404(network::http::response* response)
-{
-	std::string default_404 = sConfig->website.static_dir + "\\" + sConfig->website.default_404;
-	if (sConfig->website.default_404 == "" || ylib::file::exist(default_404) == false)
-	{
-		response->send((std::string)"404 Not Found",404,"Not Found");
-	}
-	else
-	{
-		response->send_file(default_404,-1, 404, "Not Found");
-	}
-}
+}

+ 9 - 34
src/core/fastweb.h

@@ -3,51 +3,26 @@
 #include "base/error.h"
 #include "base/singleton.hpp"
 #include "net/http_center.h"
-#include "net/http_response.h"
-#include "net/http_request.h"
-#include "core/bytecodemanager.h"
+#include "core/subscribemanager.h"
+#include "core/interceptormanager.h"
 class fastweb:public ylib::error_base,public ylib::singleton<fastweb> {
 public:
 	fastweb() = default;
 	bool start();
 	void stop();
-
-	/// <summary>
-	/// 发送文件
-	/// </summary>
-	/// <param name="response"></param>
-	/// <param name="filepath"></param>
-	void send_file(network::http::response* response, std::string filepath);
-	/// <summary>
-	/// 发送404
-	/// </summary>
-	/// <param name="response"></param>
-	void send_404(network::http::response* response);
 private:
 	/// <summary>
 	/// 初始化执行脚本
 	/// </summary>
 	/// <returns></returns>
 	bool initialization_script();
-	/// <summary>
-	/// 服务回调
-	/// </summary>
-	/// <param name="request"></param>
-	/// <param name="response"></param>
-	static void subscribe_service(network::http::request* request, network::http::response* response, void* extra);
-	/// <summary>
-	/// 拦截器回调
-	/// </summary>
-	static bool subscribe_interceptor(network::http::reqpack* reqpack,const std::string& express_string);
 private:
+	// 初始化脚本虚拟机
+	luastate* m_state_init = nullptr;
+	// 网站服务核心
 	network::http::center *m_center = nullptr;
-public:
-#if ENABLE_BYTECODE == 1
-	// 服务字节码
-	bytecode_manager service_bytecode;
-	// 拦截器字节码
-	bytecode_manager interceptor_bytecode;
-#else
-	std::map<std::string, std::string> interceptor;
-#endif
+	// 订阅管理器
+	subscribe_manager m_subscribe;
+	// 拦截器管理器
+	interceptor_manager m_interceptor;
 };

+ 15 - 0
src/core/global.cpp

@@ -43,3 +43,18 @@ void global::set(const std::string& name, VarType value)
 {
 	m_values.set(name, value, true);
 }
+
+void global::clear()
+{ 
+	m_values.clear();
+	m_value_ptr.clear();
+
+	//m_value_ptr.lock();
+	//for_iter(iter, (*m_value_ptr.parent()))
+	//{
+	//	auto im = static_cast<module::imodule*>(iter->second);
+	//	im->delete_global();
+	//}
+	//m_value_ptr.unlock();
+	//m_value_ptr.clear();
+}

+ 1 - 0
src/core/global.h

@@ -16,6 +16,7 @@ public:
 	VarType get(const std::string& name, sol::this_state s);
 	void set(const std::string& name,VarType value);
 
+	void clear();
 private:
 	ylib::map<std::string, void*> m_value_ptr;
 

+ 75 - 0
src/core/interceptormanager.cpp

@@ -0,0 +1,75 @@
+#include "core/interceptormanager.h"
+#include "core/config.h"
+#include "core/statemanager.h"
+#include "module/http/request.h"
+#include "module/http/response.h"
+#include "net/http_interceptor.h"
+std::map<std::string, std::string> interceptor_manager::interceptor = std::map<std::string,std::string>();
+interceptor_manager::interceptor_manager()
+{
+}
+interceptor_manager::~interceptor_manager()
+{
+	clear();
+}
+void interceptor_manager::load(network::http::router* router)
+{
+	clear();
+	m_router = router;
+	for (size_t i = 0; i < sConfig->website.interceptor_scripts.size(); i++)
+	{
+		interceptor_manager::interceptor.emplace(sConfig->website.interceptor_scripts[i].regex_express, sConfig->website.interceptor_scripts[i].filepath);
+		router->interceptor()->add(sConfig->website.interceptor_scripts[i].regex_express, &interceptor_manager::callback);
+	}
+}
+
+void interceptor_manager::clear()
+{
+	if(m_router != nullptr)
+		m_router->interceptor()->clear();
+	interceptor_manager::interceptor.clear();
+	m_router = nullptr;
+}
+
+bool interceptor_manager::callback(network::http::reqpack* reqpack, const std::string& express_string)
+{
+	bool ok_continue = false;
+	auto lua = sStateMgr->get();
+	std::string exception_string;
+	try
+	{
+		auto lbResult = lua->state->load_file(interceptor_manager::interceptor[express_string]);
+		if (lbResult.valid() == false)
+		{
+			sol::error err = lbResult;
+			throw ylib::exception("[interceptor] Failed to load bytecode, " + std::string(err.what()));
+		}
+		module::request m_request(reqpack->request());
+		module::response m_response(reqpack->response());
+
+		lbResult();
+
+		(*lua->state)["response"] = m_response;
+		(*lua->state)["request"] = m_request;
+
+		auto result = (*lua->state)["access"]();
+		if (!result.valid()) {
+			sol::error err = result;
+			throw ylib::exception(err.what());
+		}
+		ok_continue = result.get<bool>();
+	}
+	catch (const std::exception& e)
+	{
+		exception_string = e.what();
+		if (sConfig->website.debug)
+			LOG_ERROR("[subscribe_interceptor][" + reqpack->request()->filepath() + "]: " + e.what());
+	}
+	lua->state->collect_garbage();
+	sStateMgr->push(lua);
+
+	if (exception_string.empty() == false)
+		throw ylib::exception(exception_string);
+
+	return ok_continue;
+}

+ 31 - 0
src/core/interceptormanager.h

@@ -0,0 +1,31 @@
+#pragma once
+
+
+#include "base/singleton.hpp"
+#include "core/structs.h"
+#include "net/http_reqpack.h"
+#include "net/http_request.h"
+#include "net/http_response.h"
+#include "net/http_router.h"
+/// <summary>
+/// 拦截器管理器
+/// </summary>
+class interceptor_manager{
+public:
+	interceptor_manager();
+	~interceptor_manager();
+
+	void load(network::http::router* router);
+	void clear();
+private:
+	/// <summary>
+	/// 服务回调
+	/// </summary>
+	/// <param name="reqpack"></param>
+	/// <param name="express_string"></param>
+	static bool callback(network::http::reqpack* reqpack, const std::string& express_string);
+private:
+	network::http::router* m_router = nullptr;
+public:
+	static std::map<std::string, std::string> interceptor;
+};

+ 45 - 0
src/core/lualibdetecter.cpp

@@ -0,0 +1,45 @@
+#include "lualibdetecter.h"
+#include "core/config.h"
+#include "util/file.h"
+lualib_detecter::lualib_detecter()
+{
+}
+
+lualib_detecter::~lualib_detecter()
+{
+}
+
+bool lualib_detecter::changed()
+{
+	auto lib_files = sConfig->lua_lib_files();
+	bool changed = false;
+	if (lib_files.size() == m_files.size())
+	{
+		for (size_t i = 0; i < lib_files.size(); i++)
+		{
+			auto iter = m_files.find(lib_files[i]);
+			if (iter == m_files.end())
+			{
+				changed = true;
+				break;
+			}
+			if (ylib::file::last_write_time(sConfig->scripts.lib_dir+"/"+ lib_files[i]) != iter->second)
+			{
+				changed = true;
+				break;
+			}
+		}
+	}
+	else
+		changed = true;
+
+
+	if (changed == false)
+		return false;
+
+	m_files.clear();
+	for (size_t i = 0; i < lib_files.size(); i++)
+		m_files.emplace(lib_files[i], ylib::file::last_write_time(sConfig->scripts.lib_dir + "/" + lib_files[i]));
+
+	return true;
+}

+ 28 - 0
src/core/lualibdetecter.h

@@ -0,0 +1,28 @@
+#pragma once
+
+
+#include "sol/sol.hpp"
+
+#include "base/error.h"
+#include "base/singleton.hpp"
+#include "util/thread.h"
+#include "util/queue.hpp"
+#include "util/map.hpp"
+
+#include "core/structs.h"
+
+/// <summary>
+/// LUALIB库变动检测
+/// </summary>
+class lualib_detecter {
+public:
+	lualib_detecter();
+	~lualib_detecter();
+	/// <summary>
+	/// 是否变化
+	/// </summary>
+	/// <returns></returns>
+	bool changed();
+private:
+	std::map<std::string, timestamp> m_files;
+};

+ 41 - 65
src/core/statemanager.cpp

@@ -26,28 +26,24 @@
 #define LOOP_STATE_USE 1
 bool state_manager::start()
 {
-#if LOOP_STATE_USE ==  0
 	close();
 	::ithread::start();
-#endif
 	return true;
 }
 
 void state_manager::close()
 {
-#if LOOP_STATE_USE ==  0
 	::ithread::stop();
 	::ithread::wait();
-#endif
-	sol::state* state = nullptr;
+	luastate* state = nullptr;
 	while (m_states.pop(state))
 		delete state;
-
 }
-sol::state* state_manager::create_state()
+luastate* state_manager::create()
 {
-	sol::state* lua = new sol::state();
-	lua->open_libraries(
+	luastate* lua = new luastate();
+	lua->flag = m_flag;
+	lua->state->open_libraries(
 		sol::lib::base, 
 		sol::lib::package, 
 		sol::lib::math, 
@@ -64,82 +60,62 @@ sol::state* state_manager::create_state()
 	);
 	{
 		// 获取当前的package.path,添加新的搜索路径
-		std::string current_path = (*lua)["package"]["path"];  // 获取当前的路径
+		std::string current_path = (*lua->state)["package"]["path"];  // 获取当前的路径
 		current_path += ";"+ sConfig->scripts.lib_dir +"/?.lua";  // 添加新的路径
-		(*lua)["package"]["path"] = current_path;  // 设置修改后的路径
+		(*lua->state)["package"]["path"] = current_path;  // 设置修改后的路径
 	}
-	module::request::regist(*lua);
-	module::response::regist(*lua);
-	module::session::regist(*lua);
-	module::httpclient::regist(*lua);
-	module::mysql_regist(*lua);
+	module::request::regist(*lua->state);
+	module::response::regist(*lua->state);
+	module::session::regist(*lua->state);
+	module::httpclient::regist(*lua->state);
+	module::mysql_regist(*lua->state);
 	#ifdef _WIN32
-	module::mssql::regist(*lua);
+	module::mssql::regist(*lua->state);
 	#endif
-	module::regist_globalfuns(*lua);
-	module::local_storage::regist(lua);
-	module::mutex::regist(lua);
-	module::auto_lock::regist(lua);
-	module::codec::regist(lua);
-	module::time::regist(lua);
-	module::file::regist(lua);
-	module::sys::regist(lua);
+	module::regist_globalfuns(*lua->state);
+	module::local_storage::regist(lua->state);
+	module::mutex::regist(lua->state);
+	module::auto_lock::regist(lua->state);
+	module::codec::regist(lua->state);
+	module::time::regist(lua->state);
+	module::file::regist(lua->state);
+	module::sys::regist(lua->state);
 
-	global::getInstance()->regist_lua(lua);
+	global::getInstance()->regist_lua(lua->state);
 	return lua;
 }
 
-sol::state* state_manager::get_state()
+luastate* state_manager::get()
 {
-	sol::state* result = nullptr;
-	if (m_states.pop(result))
-		return result;
-	return create_state();
+	luastate* result = nullptr;
+	while (m_states.pop(result))
+	{
+		if (result->flag != m_flag)
+			delete result;
+		else
+			return result;
+	}
+	return create();
 }
 
-void state_manager::push_state(sol::state* state)
+void state_manager::push(luastate* state)
 {
 	if (state == nullptr)
 		return;
-#if LOOP_STATE_USE == 1
+	if (state->flag != m_flag)
+	{
+		delete state;
+		return;
+	}
 	m_states.push(state);
-#else
-	m_delete_states.push(state);
-#endif
-	
-	
 }
 
 
 bool state_manager::run()
 {
-#if LOOP_STATE_USE == 0
-	auto now_msec = time::now_msec();
-	// 虚拟机缓冲保证
-	if(sConfig->scripts.lua_cache_size > m_states.size())
-	{
-		std::vector<sol::state*> bhvalues;
-		auto bhcount = sConfig->scripts.lua_cache_size - m_states.size();
-		if (bhcount > 0 && bhcount <= sConfig->scripts.lua_cache_size)
-		{
-			for (size_t i = 0; i < bhcount; i++)
-				bhvalues.push_back(create_state());
-		}
-		for(size_t i=0;i< bhvalues.size();i++)
-			m_states.push(bhvalues[i]);
-	}
-
-	// 释放虚拟机
-	{
-		sol::state* state = nullptr;
-		while (m_delete_states.pop(state))
-			delete state;
-	}
-
-	system::sleep_msec(100);
+	if (m_lib_detecter.changed())
+		m_flag++;
+	system::sleep_msec(3000);
 	return true;
-#else
-	return false;
-#endif
 }
 

+ 14 - 5
src/core/statemanager.h

@@ -10,6 +10,7 @@
 #include "util/map.hpp"
 
 #include "core/structs.h"
+#include "core/lualibdetecter.h"
 
 /// <summary>
 /// LUA状态管理器
@@ -27,21 +28,29 @@ public:
 	/// 取虚拟机
 	/// </summary>
 	/// <returns></returns>
-	sol::state* get_state();
+	luastate* get();
 	/// <summary>
 	/// 归还虚拟机
 	/// </summary>
 	/// <param name="state"></param>
-	void push_state(sol::state* state);
+	void push(luastate* state);
 private:
 	// 虚拟机
-	ylib::queue<sol::state*> m_states;
-	ylib::queue<sol::state*> m_delete_states;
+	ylib::queue<luastate*> m_states;
+	// 版本FLAT
+	size_t m_flag = 0;
+	// LIB变化检测
+	lualib_detecter m_lib_detecter;
 private:
 	// 通过 ithread 继承
 	bool run() override;
+	/// <summary>
+	/// 创建虚拟机
+	/// </summary>
+	/// <returns></returns>
+	luastate* create();
+
 
-	sol::state* create_state();
 
 
 };

+ 16 - 0
src/core/structs.h

@@ -1,5 +1,6 @@
 #pragma once
 #include "base/define.h"
+#include "sol/sol.hpp"
 /// <summary>
 /// LUA字节码
 /// </summary>
@@ -12,4 +13,19 @@ struct bytecode {
 	std::string value;
 	// 自动更新
 	bool auto_update = false;
+};
+/// <summary>
+/// 包装虚拟机
+/// </summary>
+struct luastate {
+	luastate()
+	{
+		state = new sol::state();
+	}
+	~luastate()
+	{
+		delete state;
+	}
+	sol::state* state = nullptr;
+	size_t flag = 0;
 };

+ 194 - 0
src/core/subscribemanager.cpp

@@ -0,0 +1,194 @@
+#include "subscribemanager.h"
+#include "core/config.h"
+#include "core/statemanager.h"
+#include "module/http/request.h"
+#include "module/http/response.h"
+subscribe_manager::subscribe_manager()
+{
+}
+subscribe_manager::~subscribe_manager()
+{
+	clear();
+}
+void subscribe_manager::load(network::http::router* router)
+{
+	clear();
+	m_router = router;
+	// 初始化全部订阅
+	auto files = sConfig->lua_app_files();
+	for (size_t i = 0; i < files.size(); i++)
+	{
+		init_subscribe(files[i]);
+	}
+	// 其它绑定
+	router->other(&subscribe_manager::other);
+}
+
+void subscribe_manager::clear()
+{
+	if (m_router != nullptr)
+	{
+		m_router->clear_subscribe();
+	}
+	for (size_t i = 0; i < m_subextra.size(); i++)
+		delete m_subextra[i];
+	m_subextra.clear();
+	m_router = nullptr;
+}
+
+void subscribe_manager::init_subscribe(const std::string& filepath)
+{
+	auto state = sStateMgr->get();
+	std::string route_pattern;
+	network::http::method method = network::http::ALL;
+	try
+	{
+		auto result = state->state->script_file(sConfig->scripts.app_dir + "/" + filepath);
+		if (result.valid()) {
+			auto router = (*state->state)["route"];
+			auto type = router.get_type();
+			if (router.is<sol::table>())
+			{
+				sol::optional<std::string> route_pattern_param = router[1];
+				sol::optional<int> method_param = router[2];
+				if (route_pattern_param && route_pattern_param->empty() == false)
+					route_pattern = *route_pattern_param;
+				if (method_param)
+					method = (network::http::method)*method_param;
+			}
+		}
+	}
+	catch (const std::exception& e)
+	{
+		LOG_ERROR(e.what());
+	}
+
+	sStateMgr->push(state);
+	if (route_pattern.empty())
+		route_pattern = sConfig->scripts.app_mapping_dir + filepath;
+
+	// OutPutLog
+	{
+		std::string log;
+		log = "[subscribe] lua: " + filepath + "\t pattern: " + route_pattern + "\t method: ";
+		switch (method)
+		{
+		case ylib::network::http::GET:
+			log.append("GET");
+			break;
+		case ylib::network::http::POST:
+			log.append("POST");
+			break;
+		case ylib::network::http::PUT:
+			log.append("PUT");
+			break;
+		case ylib::network::http::DEL:
+			log.append("DEL");
+			break;
+		case ylib::network::http::HEAD:
+			log.append("HEAD");
+			break;
+		case ylib::network::http::ALL:
+			log.append("ALL");
+			break;
+		default:
+			break;
+		}
+		LOG_INFO(log);
+	}
+
+
+	std::string* extra = new std::string(sConfig->scripts.app_dir + "/" + filepath);
+	m_subextra.push_back(extra);
+	m_router->subscribe(route_pattern, method, &subscribe_manager::callback, extra);
+}
+
+void subscribe_manager::callback(network::http::request* request, network::http::response* response, void* extra)
+{
+	std::string lua_filepath = *(std::string*)extra;
+
+	auto lua = sStateMgr->get();
+	std::string exception_string;
+	try
+	{
+		auto lbResult = lua->state->load_file(lua_filepath);
+		if (lbResult.valid() == false)
+		{
+			sol::error err = lbResult;
+			throw ylib::exception("Failed to load bytecode, " + std::string(err.what()));
+		}
+		module::request m_request(request);
+		module::response m_response(response);
+
+		lbResult();
+
+		(*lua->state)["response"] = &m_response;
+		(*lua->state)["request"] = &m_request;
+
+		auto result = (*lua->state)["access"]();
+		if (!result.valid()) {
+			sol::error err = result;
+			throw ylib::exception(err.what());
+		}
+	}
+	catch (const std::exception& e)
+	{
+		exception_string = e.what();
+		if (sConfig->website.debug)
+			LOG_ERROR("[subscribe_service][" + request->filepath() + "]: " + e.what());
+	}
+	// 清理
+	lua->state->collect_garbage();
+	sStateMgr->push(lua);
+
+	if (exception_string.empty() == false)
+		throw ylib::exception(exception_string);
+}
+
+void subscribe_manager::other(network::http::request* request, network::http::response* response)
+{
+	auto send_404 = [](network::http::response* response) {
+		std::string default_404 = sConfig->website.static_dir + "\\" + sConfig->website.default_404;
+		if (sConfig->website.default_404 == "" || ylib::file::exist(default_404) == false)
+		{
+			response->send((std::string)"404 Not Found", 404, "Not Found");
+		}
+		else
+		{
+			response->send_file(default_404, -1, 404, "Not Found");
+		}
+	};
+	auto send_file = [&](network::http::response* response, std::string filepath)
+	{
+		filepath = sConfig->website.static_dir + filepath;
+		if (ylib::file::exist(filepath))
+		{
+			response->send_file(filepath);
+		}
+		else
+		{
+			send_404(response);
+		}
+	};
+
+	if (request->filepath() == "/")
+	{
+		bool find = false;
+		for (size_t i = 0; i < sConfig->website.default_index.size(); i++)
+		{
+			std::string filepath = sConfig->website.static_dir + request->filepath() + sConfig->website.default_index[i];
+			if (ylib::file::exist(filepath))
+			{
+				find = true;
+				response->send_file(filepath);
+				break;
+			}
+		}
+		if (find == false)
+		{
+			send_404(response);
+		}
+		return;
+	}
+	send_file(response, request->filepath());
+}

+ 44 - 0
src/core/subscribemanager.h

@@ -0,0 +1,44 @@
+#pragma once
+
+
+#include "sol/sol.hpp"
+#include "base/singleton.hpp"
+#include "core/structs.h"
+#include "net/http_request.h"
+#include "net/http_response.h"
+#include "net/http_router.h"
+/// <summary>
+/// 订阅管理器
+/// </summary>
+class subscribe_manager{
+public:
+	subscribe_manager();
+	~subscribe_manager();
+
+	void load(network::http::router* router);
+	void clear();
+private:
+	/// <summary>
+	/// 初始化订阅
+	/// </summary>
+	/// <param name="filepath"></param>
+	/// <returns></returns>
+	void init_subscribe(const std::string& filepath);
+private:
+	/// <summary>
+	/// 服务回调
+	/// </summary>
+	/// <param name="request"></param>
+	/// <param name="response"></param>
+	static void callback(network::http::request* request, network::http::response* response, void* extra);
+	/// <summary>
+	/// 其它
+	/// </summary>
+	/// <param name="request"></param>
+	/// <param name="response"></param>
+	/// <param name="extra"></param>
+	static void other(network::http::request* request, network::http::response* response);
+private:
+	network::http::router* m_router = nullptr;
+	std::vector<std::string*> m_subextra;
+};

+ 2 - 0
src/module/imodule.h

@@ -9,12 +9,14 @@ namespace module
 	/// </summary>
 	class imodule {
 	public:
+		virtual ~imodule() {};
 		/// <summary>
 		/// 注册全局变量
 		/// </summary>
 		/// <param name="name"></param>
 		/// <param name="lua"></param>
 		virtual void regist_global(const std::string& name,sol::state* lua) = 0;
+		virtual void delete_global() = 0;
 		/// <summary>
 		/// 全局变量阶段获取自身指针
 		/// </summary>

+ 7 - 1
src/module/localstorage.cpp

@@ -4,6 +4,11 @@ module::local_storage::local_storage()
 {
 }
 
+module::local_storage::~local_storage()
+{
+    ::ylib::local_storage::close();
+}
+
 sol::optional<std::string> module::local_storage::readex(const std::string& name)
 {
     std::string value;
@@ -23,7 +28,8 @@ void module::local_storage::regist(sol::state* lua)
         "open", &module::local_storage::open,
         "read", &module::local_storage::readex,
         "write", &module::local_storage::write,
-        "self", &module::local_storage::self
+        "self", &module::local_storage::self,
+        "last_error", &module::local_storage::last_error
     );
 }
 

+ 2 - 0
src/module/localstorage.h

@@ -9,6 +9,7 @@ namespace module
 	class local_storage : public ylib::local_storage,public module::imodule {
 	public:
 		local_storage();
+		~local_storage() override;
 		/// <summary>
 		/// 取数据
 		/// </summary>
@@ -20,6 +21,7 @@ namespace module
 	private:
 		// 通过 imodule 继承
 		virtual void regist_global(const std::string& name, sol::state* lua);
+		virtual void delete_global() { delete this; }
 	};
 }
 

+ 2 - 1
src/module/mutex.h

@@ -10,7 +10,7 @@ namespace module
 	class mutex:public module::imodule {
 	public:
 		mutex();
-		~mutex();
+		~mutex() override;
 		/// <summary>
 		/// 加锁
 		/// </summary>
@@ -28,6 +28,7 @@ namespace module
 	private:
 		// 通过 imodule 继承
 		virtual void regist_global(const std::string& name, sol::state* lua);
+		virtual void delete_global() { delete this; }
 		std::mutex m_mutex;
 	};
 

+ 3 - 5
src/module/mysql.cpp

@@ -448,12 +448,13 @@ module::mysql::mysql()
 
 module::mysql::~mysql()
 {
+    close();
 }
 
 bool module::mysql::start(const std::string& ipaddress, const std::string& username, const std::string& password, const std::string& database, const std::string& charset, ushort port, int32 size)
 {
     close();
-    m_pool = new ylib::mysql::pool();
+    m_pool = std::make_shared<ylib::mysql::pool>();
     ylib::mysql::mysql_conn_info info;
     info.ipaddress = ipaddress;
     info.username = username;
@@ -466,9 +467,7 @@ bool module::mysql::start(const std::string& ipaddress, const std::string& usern
 
 void module::mysql::close()
 {
-    if (m_pool != nullptr)
-        delete m_pool;
-    m_pool = nullptr;
+
 }
 
 std::shared_ptr<module::select> module::mysql::select()
@@ -496,7 +495,6 @@ void module::mysql::regist_global(const std::string& name, sol::state* lua)
     lua->registry()[name] = this;
     (*lua)[name] = this;
 }
-
 module::mysql_result::mysql_result(ylib::mysql::result* result):m_result(result)
 {
 

+ 3 - 2
src/module/mysql.h

@@ -154,7 +154,7 @@ namespace module
 	class mysql :public imodule {
 	public:
 		mysql();
-		~mysql();
+		~mysql()  override;
 		/// <summary>
 		/// 启动
 		/// </summary>
@@ -177,10 +177,11 @@ namespace module
 		std::shared_ptr<module::update> update();
 		std::shared_ptr<module::delete_> delete_();
 	private:
-		ylib::mysql::pool* m_pool = nullptr;
+		std::shared_ptr<ylib::mysql::pool> m_pool;
 
 		// 通过 imodule 继承
 		virtual void regist_global(const std::string& name, sol::state* lua);
+		virtual void delete_global() { delete this; }
 	};
 
 }

+ 1 - 36
src/utils/luautils.cpp

@@ -1,38 +1,3 @@
 #include "luautils.h"
 #include "core/define.h"
-#include "core/statemanager.h"
-bool LuaUtils::make_bytecode(const std::string& filepath, std::string& bytecode)
-{
-	auto lua = sStateMgr->get_state();
-	try
-	{
-		auto result = lua->load_file(filepath);
-		if (!result.valid()) {
-			sol::error err = result;
-			LOG_ERROR(err.what() + std::string(", filepath: " + filepath));
-			return false;
-		}
-		result();
-		sol::function func = result;
-		if (!func.valid()) {
-			LOG_ERROR("Pre execution script failed before compilation. filepath: " + filepath);
-			return false;
-		}
-		sol::function dump = (*lua)["string"]["dump"];
-		sol::protected_function_result result2 = dump(func);
-		if (!result2.valid()) {
-			sol::error err = result2;
-			LOG_ERROR("failed to dump. " + std::string(err.what()) + ", filepath: " + filepath);
-			return false;
-		}
-		LOG_INFO("update lua script, filepath: " + filepath);
-		bytecode = result2;
-		return true;
-	}
-	catch (const std::exception& e)
-	{
-		LOG_INFO(std::string(e.what()) + ", filepath: " + filepath);
-			}
-	sStateMgr->push_state(lua);
-	return false;
-}
+#include "core/statemanager.h"

+ 1 - 7
src/utils/luautils.h

@@ -2,11 +2,5 @@
 #include <string>
 namespace LuaUtils {
 
-	/// <summary>
-	/// 创建服务字节码
-	/// </summary>
-	/// <param name="filepath"></param>
-	/// <param name="bytecode"></param>
-	/// <returns></returns>
-	bool make_bytecode(const std::string& filepath,std::string& bytecode);
+
 }

+ 14 - 2
tests/main.cpp

@@ -5,10 +5,22 @@
 int main()
 {
 	std::string config_filepath = std::filesystem::current_path().string()+"/config.ini";
-	if (fastweb(config_filepath.c_str()) != 0)
+	if (fastweb_start(config_filepath.c_str()) != 0)
 		return -1;
 
 	while (true)
-		std::cin.get();
+	{
+		std::string input;
+		std::cin >> input;
+
+		if (input == "quit" || input == "exit")
+		{
+			fastweb_close();
+			std::cout << "closed";
+			break;
+		}
+		else
+			std::cout << "Enter \"quit\" or \"exit\" to exit the application" << std::endl;
+	}
 	return 0;
 }