From 417f6a4d829943f94e001fd17d2cf0cb0595382d Mon Sep 17 00:00:00 2001 From: xx Date: Sat, 1 Jun 2024 14:08:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9B=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E9=A2=84=E7=BC=96=E8=AF=91=E5=AD=97=E8=8A=82=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/bytecodemanager.cpp | 80 -------- src/core/bytecodemanager.h | 45 ----- src/core/config.cpp | 29 ++- src/core/config.h | 7 +- src/core/define.h | 1 - src/core/entry.cpp | 12 +- src/core/entry.h | 3 +- src/core/fastweb.cpp | 346 ++------------------------------ src/core/fastweb.h | 43 +--- src/core/global.cpp | 15 ++ src/core/global.h | 1 + src/core/interceptormanager.cpp | 75 +++++++ src/core/interceptormanager.h | 31 +++ src/core/lualibdetecter.cpp | 45 +++++ src/core/lualibdetecter.h | 28 +++ src/core/statemanager.cpp | 106 ++++------ src/core/statemanager.h | 19 +- src/core/structs.h | 16 ++ src/core/subscribemanager.cpp | 194 ++++++++++++++++++ src/core/subscribemanager.h | 44 ++++ src/module/imodule.h | 2 + src/module/localstorage.cpp | 8 +- src/module/localstorage.h | 2 + src/module/mutex.h | 3 +- src/module/mysql.cpp | 8 +- src/module/mysql.h | 5 +- src/utils/luautils.cpp | 37 +--- src/utils/luautils.h | 8 +- tests/main.cpp | 16 +- 29 files changed, 608 insertions(+), 621 deletions(-) delete mode 100644 src/core/bytecodemanager.cpp delete mode 100644 src/core/bytecodemanager.h create mode 100644 src/core/interceptormanager.cpp create mode 100644 src/core/interceptormanager.h create mode 100644 src/core/lualibdetecter.cpp create mode 100644 src/core/lualibdetecter.h create mode 100644 src/core/subscribemanager.cpp create mode 100644 src/core/subscribemanager.h diff --git a/src/core/bytecodemanager.cpp b/src/core/bytecodemanager.cpp deleted file mode 100644 index 4963f31..0000000 --- a/src/core/bytecodemanager.cpp +++ /dev/null @@ -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 bc; - if (m_bytescodes.get(name, bc)) - { - m_lastErrorDesc = "The bytecode already exists, name: " + name; - return false; - } - bc = std::make_shared(); - 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 bc; - if (m_bytescodes.get(name, bc) == false) - { - return return_empty; - } - return bc->value; -} - -std::map> 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 \ No newline at end of file diff --git a/src/core/bytecodemanager.h b/src/core/bytecodemanager.h deleted file mode 100644 index 8b8e3dd..0000000 --- a/src/core/bytecodemanager.h +++ /dev/null @@ -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" - -/// -/// 字节码管理器 -/// -class bytecode_manager:public ylib::error_base,private ylib::ithread { -public: - bytecode_manager(); - ~bytecode_manager(); - /// - /// 创建字节码 - /// - /// - /// - /// - /// - bool create(const std::string& name,const std::string& filepath,bool auto_update); - /// - /// 取字节码 - /// - /// - /// - const std::string& get(const std::string& name); - - std::map> map(); -private: - // ServiceLUA文件 - ylib::map> m_bytescodes; - - // 通过 ithread 继承 - bool run() override; -}; -#endif \ No newline at end of file diff --git a/src/core/config.cpp b/src/core/config.cpp index b6bc8b7..8aa67d4 100644 --- a/src/core/config.cpp +++ b/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 config::lua_app_files() { - for_iter(iter, domain) + std::vector results; + auto luas = ylib::file::traverse(sConfig->scripts.app_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 config::lua_lib_files() +{ + std::vector results; + auto luas = ylib::file::traverse(sConfig->scripts.lib_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 config::extractVariableNames(const std::string& text) { diff --git a/src/core/config.h b/src/core/config.h index 58c7e7a..1179b3a 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -37,11 +37,8 @@ public: config() = default; bool open(const std::string& ini_filepath); - /// - /// 是否含有https - /// - /// - bool have_https(); + std::vector lua_app_files(); + std::vector lua_lib_files(); private: // INI配置文件 ylib::ini m_ini; diff --git a/src/core/define.h b/src/core/define.h index 5804420..885c7f8 100644 --- a/src/core/define.h +++ b/src/core/define.h @@ -30,4 +30,3 @@ #define VarType sol::object -#define ENABLE_BYTECODE 0 \ No newline at end of file diff --git a/src/core/entry.cpp b/src/core/entry.cpp index 291bfda..192f64b 100644 --- a/src/core/entry.cpp +++ b/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; } -} \ No newline at end of file +#ifdef _WIN32 + DLL_EXPORT +#endif + void fastweb_close() + { + fastweb::getInstance()->stop(); + } +} + diff --git a/src/core/entry.h b/src/core/entry.h index 152bdde..ba48fbd 100644 --- a/src/core/entry.h +++ b/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(); } \ No newline at end of file diff --git a/src/core/fastweb.cpp b/src/core/fastweb.cpp index df08af5..ffeaa80 100644 --- a/src/core/fastweb.cpp +++ b/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::optional route_pattern_param = router[1]; - sol::optional 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::optional route_pattern_param = router[1]; - sol::optional 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(); - } - 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"); - } -} +} \ No newline at end of file diff --git a/src/core/fastweb.h b/src/core/fastweb.h index 3ea751f..8486d58 100644 --- a/src/core/fastweb.h +++ b/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 { public: fastweb() = default; bool start(); void stop(); - - /// - /// 发送文件 - /// - /// - /// - void send_file(network::http::response* response, std::string filepath); - /// - /// 发送404 - /// - /// - void send_404(network::http::response* response); private: /// /// 初始化执行脚本 /// /// bool initialization_script(); - /// - /// 服务回调 - /// - /// - /// - static void subscribe_service(network::http::request* request, network::http::response* response, void* extra); - /// - /// 拦截器回调 - /// - 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 interceptor; -#endif + // 订阅管理器 + subscribe_manager m_subscribe; + // 拦截器管理器 + interceptor_manager m_interceptor; }; \ No newline at end of file diff --git a/src/core/global.cpp b/src/core/global.cpp index 33e1a2b..d71bdce 100644 --- a/src/core/global.cpp +++ b/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(iter->second); + // im->delete_global(); + //} + //m_value_ptr.unlock(); + //m_value_ptr.clear(); +} diff --git a/src/core/global.h b/src/core/global.h index 1b9af61..ea365a6 100644 --- a/src/core/global.h +++ b/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 m_value_ptr; diff --git a/src/core/interceptormanager.cpp b/src/core/interceptormanager.cpp new file mode 100644 index 0000000..40dbe49 --- /dev/null +++ b/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 interceptor_manager::interceptor = std::map(); +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(); + } + 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; +} diff --git a/src/core/interceptormanager.h b/src/core/interceptormanager.h new file mode 100644 index 0000000..df735e1 --- /dev/null +++ b/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" +/// +/// 拦截器管理器 +/// +class interceptor_manager{ +public: + interceptor_manager(); + ~interceptor_manager(); + + void load(network::http::router* router); + void clear(); +private: + /// + /// 服务回调 + /// + /// + /// + static bool callback(network::http::reqpack* reqpack, const std::string& express_string); +private: + network::http::router* m_router = nullptr; +public: + static std::map interceptor; +}; \ No newline at end of file diff --git a/src/core/lualibdetecter.cpp b/src/core/lualibdetecter.cpp new file mode 100644 index 0000000..2b869a7 --- /dev/null +++ b/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; +} diff --git a/src/core/lualibdetecter.h b/src/core/lualibdetecter.h new file mode 100644 index 0000000..c9d70b5 --- /dev/null +++ b/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" + +/// +/// LUALIB库变动检测 +/// +class lualib_detecter { +public: + lualib_detecter(); + ~lualib_detecter(); + /// + /// 是否变化 + /// + /// + bool changed(); +private: + std::map m_files; +}; \ No newline at end of file diff --git a/src/core/statemanager.cpp b/src/core/statemanager.cpp index 56a5fae..91b7b5f 100644 --- a/src/core/statemanager.cpp +++ b/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 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 } diff --git a/src/core/statemanager.h b/src/core/statemanager.h index 7a22b5d..2f55d60 100644 --- a/src/core/statemanager.h +++ b/src/core/statemanager.h @@ -10,6 +10,7 @@ #include "util/map.hpp" #include "core/structs.h" +#include "core/lualibdetecter.h" /// /// LUA状态管理器 @@ -27,21 +28,29 @@ public: /// 取虚拟机 /// /// - sol::state* get_state(); + luastate* get(); /// /// 归还虚拟机 /// /// - void push_state(sol::state* state); + void push(luastate* state); private: // 虚拟机 - ylib::queue m_states; - ylib::queue m_delete_states; + ylib::queue m_states; + // 版本FLAT + size_t m_flag = 0; + // LIB变化检测 + lualib_detecter m_lib_detecter; private: // 通过 ithread 继承 bool run() override; + /// + /// 创建虚拟机 + /// + /// + luastate* create(); + - sol::state* create_state(); }; \ No newline at end of file diff --git a/src/core/structs.h b/src/core/structs.h index 1de86b5..4639867 100644 --- a/src/core/structs.h +++ b/src/core/structs.h @@ -1,5 +1,6 @@ #pragma once #include "base/define.h" +#include "sol/sol.hpp" /// /// LUA字节码 /// @@ -12,4 +13,19 @@ struct bytecode { std::string value; // 自动更新 bool auto_update = false; +}; +/// +/// 包装虚拟机 +/// +struct luastate { + luastate() + { + state = new sol::state(); + } + ~luastate() + { + delete state; + } + sol::state* state = nullptr; + size_t flag = 0; }; \ No newline at end of file diff --git a/src/core/subscribemanager.cpp b/src/core/subscribemanager.cpp new file mode 100644 index 0000000..60dad21 --- /dev/null +++ b/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::optional route_pattern_param = router[1]; + sol::optional 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()); +} diff --git a/src/core/subscribemanager.h b/src/core/subscribemanager.h new file mode 100644 index 0000000..bf1300e --- /dev/null +++ b/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" +/// +/// 订阅管理器 +/// +class subscribe_manager{ +public: + subscribe_manager(); + ~subscribe_manager(); + + void load(network::http::router* router); + void clear(); +private: + /// + /// 初始化订阅 + /// + /// + /// + void init_subscribe(const std::string& filepath); +private: + /// + /// 服务回调 + /// + /// + /// + static void callback(network::http::request* request, network::http::response* response, void* extra); + /// + /// 其它 + /// + /// + /// + /// + static void other(network::http::request* request, network::http::response* response); +private: + network::http::router* m_router = nullptr; + std::vector m_subextra; +}; \ No newline at end of file diff --git a/src/module/imodule.h b/src/module/imodule.h index 9a68107..f8f2912 100644 --- a/src/module/imodule.h +++ b/src/module/imodule.h @@ -9,12 +9,14 @@ namespace module /// class imodule { public: + virtual ~imodule() {}; /// /// 注册全局变量 /// /// /// virtual void regist_global(const std::string& name,sol::state* lua) = 0; + virtual void delete_global() = 0; /// /// 全局变量阶段获取自身指针 /// diff --git a/src/module/localstorage.cpp b/src/module/localstorage.cpp index bb4b1fd..b8f9640 100644 --- a/src/module/localstorage.cpp +++ b/src/module/localstorage.cpp @@ -4,6 +4,11 @@ module::local_storage::local_storage() { } +module::local_storage::~local_storage() +{ + ::ylib::local_storage::close(); +} + sol::optional 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 ); } diff --git a/src/module/localstorage.h b/src/module/localstorage.h index 48ce007..1610d5f 100644 --- a/src/module/localstorage.h +++ b/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; /// /// 取数据 /// @@ -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; } }; } diff --git a/src/module/mutex.h b/src/module/mutex.h index 8594d71..e40e013 100644 --- a/src/module/mutex.h +++ b/src/module/mutex.h @@ -10,7 +10,7 @@ namespace module class mutex:public module::imodule { public: mutex(); - ~mutex(); + ~mutex() override; /// /// 加锁 /// @@ -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; }; diff --git a/src/module/mysql.cpp b/src/module/mysql.cpp index 979a159..09e7295 100644 --- a/src/module/mysql.cpp +++ b/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::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::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) { diff --git a/src/module/mysql.h b/src/module/mysql.h index 8514db9..d5c5630 100644 --- a/src/module/mysql.h +++ b/src/module/mysql.h @@ -154,7 +154,7 @@ namespace module class mysql :public imodule { public: mysql(); - ~mysql(); + ~mysql() override; /// /// 启动 /// @@ -177,10 +177,11 @@ namespace module std::shared_ptr update(); std::shared_ptr delete_(); private: - ylib::mysql::pool* m_pool = nullptr; + std::shared_ptr m_pool; // 通过 imodule 继承 virtual void regist_global(const std::string& name, sol::state* lua); + virtual void delete_global() { delete this; } }; } diff --git a/src/utils/luautils.cpp b/src/utils/luautils.cpp index 7315c4e..3378693 100644 --- a/src/utils/luautils.cpp +++ b/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" \ No newline at end of file diff --git a/src/utils/luautils.h b/src/utils/luautils.h index 0cfb5e8..a1a1cd9 100644 --- a/src/utils/luautils.h +++ b/src/utils/luautils.h @@ -2,11 +2,5 @@ #include namespace LuaUtils { - /// - /// 创建服务字节码 - /// - /// - /// - /// - bool make_bytecode(const std::string& filepath,std::string& bytecode); + } \ No newline at end of file diff --git a/tests/main.cpp b/tests/main.cpp index 071027f..f3fdcc2 100644 --- a/tests/main.cpp +++ b/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; }