diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b894d7e --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +*.*\~ +*.*~ +*.*\# +*.*# +\#* +\.\#* +~*.* +\#*.* +*.pb.* +CMakeCache.txt +cmake_install.cmake +CMakeFiles +Makefile +server/bin +__pycache__ +*pb2.py +*.pyc +*.out +.vs +.user +game.py +*.cxx +compile_commands.json \ No newline at end of file diff --git a/server/textserver/CMakeLists.txt b/server/textserver/CMakeLists.txt new file mode 100644 index 0000000..7b453c6 --- /dev/null +++ b/server/textserver/CMakeLists.txt @@ -0,0 +1,117 @@ +project(textserver) +cmake_minimum_required(VERSION 2.8) + +set(GAME_ID 9006) + +if (${RELEASE}) + set(CMAKE_BUILD_TYPE "Release") + message("release mode") +else() + set(CMAKE_BUILD_TYPE "Debug") + message("debug mode") +endif() +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -g -std=gnu++11 -DNDEBUG -DGAME_ID=${GAME_ID} ") +set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -std=gnu++11 -DDEBUG -DGAME_ID=${GAME_ID} ") + +include_directories( + AFTER + ../../third_party/a8engine + /usr/include/mysql + /usr/include/jsoncpp + /usr/include/hiredis + /usr/include/eigen3 + /usr/include/glm + ../../third_party + ../../third_party/behaviac/inc + ../../third_party/recastnavigation/Recast/Include + ../../third_party/recastnavigation/Detour/Include + ../../third_party/recastnavigation/DetourTileCache/Include + . +) + +link_directories( + /usr/lib64/mysql + /usr/local/lib + ../../third_party/behaviac/lib +) + +aux_source_directory(../../third_party/a8engine/a8 + SRC_LIST +) + +aux_source_directory(../../third_party/framework/cpp + SRC_LIST +) + +aux_source_directory(../../third_party/recastnavigation/Detour/Source + SRC_LIST +) + +aux_source_directory(../../third_party/recastnavigation/Recast/Source + SRC_LIST +) + +aux_source_directory(../../third_party/recastnavigation/DetourTileCache/Source + SRC_LIST +) + +aux_source_directory(. + SRC_LIST +) + +execute_process( + COMMAND touch -a metatable.pb.h + COMMAND touch -a metatable.pb.cc + ) +add_executable( + textserver ${SRC_LIST} +) + +add_custom_target(script_pb_protocol ALL) +add_custom_command(TARGET script_pb_protocol + PRE_BUILD + COMMAND python ../../third_party/tools/scripts/construct/build_pb.py --cpp_out=. --pb_files=metatable +) +add_dependencies(textserver script_pb_protocol) + +set(EXECUTABLE_OUTPUT_PATH + ${PROJECT_BINARY_DIR}/../bin +) + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + target_link_libraries( + textserver + pthread + mysqlclient + protobuf + rt + dl + util + crypto + ssl + jsoncpp + curl + hiredis + tinyxml2 + behaviac_gcc_debug + ) +else() + target_link_libraries( + textserver + pthread + mysqlclient + protobuf + rt + dl + util + crypto + ssl + jsoncpp + curl + hiredis + tinyxml2 + tcmalloc + behaviac_gcc_release + ) +endif() + diff --git a/server/textserver/app.cc b/server/textserver/app.cc new file mode 100755 index 0000000..c9d5ecb --- /dev/null +++ b/server/textserver/app.cc @@ -0,0 +1,429 @@ +#include "precompile.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "framework/cpp/netmsghandler.h" + +#include "app.h" +#include "jsondatamgr.h" +#include "handlermgr.h" +#include "perfmonitor.h" +#include "metamgr.h" + +#include "ss_msgid.pb.h" +#include "ss_proto.pb.h" + +#include "framework/cpp/msgqueue.h" +#include "framework/cpp/tglog.h" + +struct MsgNode +{ + SocketFrom_e sockfrom; + int sockhandle; + unsigned short msgid; + unsigned int seqid; + long ip_saddr; + char* buf; + int buflen; + MsgNode* next; +}; + +struct IMMsgNode +{ + unsigned short msgid; + a8::XParams params; + IMMsgNode* next = nullptr; + +}; + +const char* const PROJ_LOG_ROOT_FMT = "/data/logs/%s/logs"; +const char* const PROJ_LOG_FILENAME_FMT = "log_$pid_%Y%m%d.log"; + +void App::Init(int argc, char* argv[]) +{ + nowtime = time(nullptr); + signal(SIGPIPE, SIG_IGN); + this->argc = argc; + this->argv = argv; + + if (!ParseOpt()) { + terminated = true; + if (instance_id <= 0) { + a8::XPrintf("friend_rankserver启动失败,缺少-i参数\n", {}); + } else if (instance_id > MAX_INSTANCE_ID) { + a8::XPrintf("friend_rankserver启动失败,-i参数不能大于%d\n", {MAX_INSTANCE_ID}); + } + return; + } + a8::XPrintf("rankserver starting instance_id:%d pid:%d\n", {instance_id, getpid()}); + + loop_mutex_ = new std::mutex(); + loop_cond_ = new std::condition_variable(); + msg_mutex_ = new std::mutex(); + im_msg_mutex_ = new std::mutex(); + + srand(time(nullptr)); + InitLog(); + HandlerMgr::Instance()->Init(); + a8::Timer::Instance()->Init(); + PerfMonitor::Instance()->Init(); + f8::MsgQueue::Instance()->Init(); + f8::TGLog::Instance()->Init(a8::Format(PROJ_NAME_FMT, {}), false); + JsonDataMgr::Instance()->Init(); + uuid.SetMachineId(instance_id); + MetaMgr::Instance()->Init(); + + a8::UdpLog::Instance()->Info("rankserver starting instance_id:%d pid:%d", {instance_id, getpid()}); +} + +void App::UnInit() +{ + if (terminated) { + return; + } + MetaMgr::Instance()->UnInit(); + JsonDataMgr::Instance()->UnInit(); + f8::MsgQueue::Instance()->UnInit(); + PerfMonitor::Instance()->UnInit(); + a8::Timer::Instance()->UnInit(); + HandlerMgr::Instance()->UnInit(); + f8::TGLog::Instance()->UnInit(); + UnInitLog(); + + A8_SAFE_DELETE(im_msg_mutex_); + A8_SAFE_DELETE(msg_mutex_); + A8_SAFE_DELETE(loop_cond_); + A8_SAFE_DELETE(loop_mutex_); +} + +int App::Run() +{ + if (terminated) { + return 0; + } + int ret = 0; + a8::UdpLog::Instance()->Info("rankserver running", {}); + last_run_tick_ = a8::XGetTickCount(); + int delta_time = 0; + while (!terminated) { + a8::tick_t begin_tick = a8::XGetTickCount(); + nowtime = time(nullptr); + QuickExecute(delta_time); + SlowerExecute(delta_time); + Schedule(); + a8::tick_t end_tick = a8::XGetTickCount(); + if (end_tick - begin_tick > PerfMonitor::Instance()->max_run_delay_time) { + PerfMonitor::Instance()->max_run_delay_time = end_tick - begin_tick; + } + delta_time = end_tick - begin_tick; + } + return ret; +} + +void App::AddSocketMsg(SocketFrom_e sockfrom, + int sockhandle, + long ip_saddr, + unsigned short msgid, + unsigned int seqid, + const char *msgbody, + int bodylen) +{ + MsgNode *p = (MsgNode*) malloc(sizeof(MsgNode)); + memset(p, 0, sizeof(MsgNode)); + p->sockfrom = sockfrom; + p->ip_saddr = ip_saddr; + p->sockhandle = sockhandle; + p->msgid = msgid; + p->seqid = seqid; + p->buf = nullptr; + p->buflen = bodylen; + if (bodylen > 0) { + p->buf = (char*)malloc(bodylen); + memmove(p->buf, msgbody, bodylen); + } + msg_mutex_->lock(); + if (bot_node_) { + bot_node_->next = p; + bot_node_ = p; + } else { + top_node_ = p; + bot_node_ = p; + } + ++msgnode_size_; + msg_mutex_->unlock(); + NotifyLoopCond(); +} + +void App::AddIMMsg(unsigned short imcmd, a8::XParams params) +{ + IMMsgNode *p = new IMMsgNode; + p->msgid = imcmd; + p->params = params; + p->next = nullptr; + im_msg_mutex_->lock(); + if (im_bot_node_) { + im_bot_node_->next = p; + im_bot_node_ = p; + } else { + im_top_node_ = p; + im_bot_node_ = p; + } + im_msg_mutex_->unlock(); + NotifyLoopCond(); +} + +void App::QuickExecute(int delta_time) +{ + ProcessIMMsg(); + DispatchMsg(); + a8::Timer::Instance()->Update(); +} + +void App::SlowerExecute(int delta_time) +{ +} + +void App::NotifyLoopCond() +{ + std::unique_lock lk(*loop_mutex_); + loop_cond_->notify_all(); +} + +void App::Schedule() +{ + #if 1 + { + std::unique_lock lk(*loop_mutex_); + loop_cond_->wait_for(lk, std::chrono::milliseconds(1)); + } + #else + std::unique_lock lk(*loop_mutex_); + if (!HasTask()) { + int sleep_time = a8::Timer::Instance()->GetIdleableMillSeconds(); + loop_cond_->wait_for(lk, std::chrono::milliseconds(sleep_time)); + if (sleep_time > perf.max_timer_idle) { + perf.max_timer_idle = sleep_time; + } + } + #endif +} + +bool App::HasTask() +{ + { + if (!im_work_node_) { + im_msg_mutex_->lock(); + if (!im_work_node_ && im_top_node_) { + im_work_node_ = im_top_node_; + im_top_node_ = nullptr; + im_bot_node_ = nullptr; + } + im_msg_mutex_->unlock(); + } + if (im_work_node_) { + return true; + } + } + { + if (!work_node_) { + msg_mutex_->lock(); + if (!work_node_ && top_node_) { + work_node_ = top_node_; + top_node_ = nullptr; + bot_node_ = nullptr; + } + msg_mutex_->unlock(); + } + if (work_node_) { + return true; + } + } + return false; +} + +void App::DispatchMsg() +{ + long long starttick = a8::XGetTickCount(); + if (!work_node_ && top_node_) { + msg_mutex_->lock(); + work_node_ = top_node_; + top_node_ = nullptr; + bot_node_ = nullptr; + working_msgnode_size_ = msgnode_size_; + msg_mutex_->unlock(); + } + + f8::MsgHdr hdr; + while (work_node_) { + MsgNode *pdelnode = work_node_; + work_node_ = pdelnode->next; + hdr.msgid = pdelnode->msgid; + hdr.seqid = pdelnode->seqid; + hdr.socket_handle = pdelnode->sockhandle; + hdr.buf = pdelnode->buf; + hdr.buflen = pdelnode->buflen; + hdr.offset = 0; + hdr.ip_saddr = pdelnode->ip_saddr; + switch (pdelnode->sockfrom) { + case SF_IMServer: + { + ProcessIMServerMsg(hdr); + } + break; + } + if (pdelnode->buf) { + free(pdelnode->buf); + } + free(pdelnode); + working_msgnode_size_--; + if (a8::XGetTickCount() - starttick > 200) { + break; + } + }//end while + + if (!work_node_) { + working_msgnode_size_ = 0; + } +} + +void App::ProcessIMServerMsg(f8::MsgHdr& hdr) +{ + f8::NetMsgHandler* handler = f8::GetNetMsgHandler(&HandlerMgr::Instance()->immsghandler, + hdr.msgid); + if (handler) { + #ifdef DEBUG + f8::DumpMsgToLog(hdr, handler, ">>>>>>IMS "); + #endif + } +} + +void App::ProcessIMMsg() +{ + if (!im_work_node_ && im_top_node_) { + im_msg_mutex_->lock(); + im_work_node_ = im_top_node_; + im_top_node_ = nullptr; + im_bot_node_ = nullptr; + im_msg_mutex_->unlock(); + } + while (im_work_node_) { + IMMsgNode *pdelnode = im_work_node_; + switch (im_work_node_->msgid) { + case f8::IM_SysMsgQueue: + { + const a8::XParams* param = (const a8::XParams*)pdelnode->params.param1.GetUserData(); + f8::MsgQueue::Instance()->ProcessMsg(pdelnode->params.sender.GetInt(), + *param + ); + delete param; + } + break; + case IM_ClientSocketDisconnect: + { + #if 0 + PlayerMgr::Instance()->OnClientDisconnect(pdelnode->params); + #endif + } + break; + case IM_IMSSocketDisconnect: + { + } + break; + case IM_ExecGM: + { + HandlerMgr::Instance()->ProcGMMsg(pdelnode->params.param3, + pdelnode->params.sender, + pdelnode->params.param1.GetString(), + pdelnode->params.param2.GetString() + ); + } + break; + } + im_work_node_ = im_work_node_->next; + delete pdelnode; + } +} + +void App::InitLog() +{ + std::string filename_fmt = PROJ_LOG_FILENAME_FMT; + a8::ReplaceString(filename_fmt, "$pid", a8::XValue(getpid())); + + std::string proj_root_dir = a8::Format(PROJ_ROOT_FMT, {a8::Format(PROJ_NAME_FMT,{})}); + std::string proj_log_root_dir = a8::Format(PROJ_LOG_ROOT_FMT, {a8::Format(PROJ_NAME_FMT, {})}); + std::string log_file_name = a8::Format(PROJ_LOG_ROOT_FMT, + {a8::Format(PROJ_NAME_FMT, {})}) + "/" + filename_fmt; + + a8::MkDir(proj_root_dir); + a8::MkDir(proj_log_root_dir); + a8::UdpLog::Instance()->SetLogFileName(log_file_name); + a8::UdpLog::Instance()->Init(); + a8::UdpLog::Instance()->Info("proj_root_dir:%s", {proj_root_dir}); + a8::UdpLog::Instance()->Info("proj_log_root_dir:%s", {proj_log_root_dir}); + a8::UdpLog::Instance()->Info("log_file_name:%s", {log_file_name}); +} + +void App::UnInitLog() +{ + a8::UdpLog::Instance()->UnInit(); +} + +bool App::ParseOpt() +{ + int ch = 0; + while ((ch = getopt(argc, argv, "n:i:t:r:f:")) != -1) { + switch (ch) { + case 'i': + { + instance_id = a8::XValue(optarg); + } + break; + case 't': + { + is_test_mode = true; + test_param = a8::XValue(optarg); + } + break; + case 'f': + { + std::vector strings; + a8::Split(optarg, strings, ','); + for (auto& str : strings) { + flags.insert(a8::XValue(str).GetInt()); + } + } + break; + } + } + return instance_id > 0; +} + +long long App::NewUuid() +{ + return uuid.Generate(); +} + +a8::XParams* App::AddContext(long long context_id) +{ + context_hash_[context_id] = a8::XParams(); + return GetContext(context_id); +} + +void App::DelContext(long long context_id) +{ + context_hash_.erase(context_id); +} + +a8::XParams* App::GetContext(long long context_id) +{ + auto itr = context_hash_.find(context_id); + return itr != context_hash_.end() ? &(itr->second) : nullptr; +} diff --git a/server/textserver/app.h b/server/textserver/app.h new file mode 100644 index 0000000..26963ab --- /dev/null +++ b/server/textserver/app.h @@ -0,0 +1,86 @@ +#pragma once + +#include + +struct MsgNode; +struct IMMsgNode; +class App : public a8::Singleton +{ +private: + App() {}; + friend class a8::Singleton; + +public: + + void Init(int argc, char* argv[]); + void UnInit(); + + int Run(); + + void AddSocketMsg(SocketFrom_e sockfrom, + int sockhandle, + long ip_saddr, + unsigned short msgid, + unsigned int seqid, + const char *msgbody, + int bodylen); + void AddIMMsg(unsigned short imcmd, a8::XParams params); + + void NotifyLoopCond(); + + long long NewUuid(); + a8::XParams* AddContext(long long context_id); + void DelContext(long long context_id); + a8::XParams* GetContext(long long context_id); + +private: + void QuickExecute(int delta_time); + void SlowerExecute(int delta_time); + void Schedule(); + bool HasTask(); + + void DispatchMsg(); + void ProcessIMMsg(); + + void ProcessIMServerMsg(f8::MsgHdr& hdr); + + void InitLog(); + void UnInitLog(); + + bool ParseOpt(); + +public: + int argc = 0; + char** argv = nullptr; + volatile bool terminated = false; + a8::uuid::SnowFlake uuid; + time_t nowtime = 0; + +public: + int instance_id = 0; + bool is_test_mode = false; + int test_param = 0; + std::set flags; + +private: + long long last_run_tick_ = 0; + std::mutex *loop_mutex_ = nullptr; + std::condition_variable *loop_cond_ = nullptr; + + std::mutex *msg_mutex_ = nullptr; + MsgNode* top_node_ = nullptr; + MsgNode* bot_node_ = nullptr; + MsgNode* work_node_ = nullptr; + + std::mutex* im_msg_mutex_ = nullptr; + IMMsgNode* im_top_node_ = nullptr; + IMMsgNode* im_bot_node_ = nullptr; + IMMsgNode* im_work_node_ = nullptr; + + std::map context_hash_; + +public: + int msgnode_size_ = 0 ; + int working_msgnode_size_ = 0; + +}; diff --git a/server/textserver/constant.h b/server/textserver/constant.h new file mode 100755 index 0000000..5d8717d --- /dev/null +++ b/server/textserver/constant.h @@ -0,0 +1,27 @@ +#pragma once + +enum SocketFrom_e +{ + SF_IMServer, +}; + +enum InnerMesssage_e +{ + IM_ClientSocketDisconnect = 100, + IM_IMSSocketDisconnect, + IM_ExecGM, + IM_HttpResponse, +}; + +//网络处理对象 +enum NetHandler_e +{ + HID_IMSMgr, +}; + +const char* const PROJ_NAME_FMT = "textserver"; +const char* const PROJ_ROOT_FMT = "/data/logs/%s"; + +const float TEN_W = 10000 * 10; + +const int MAX_INSTANCE_ID = 1023; diff --git a/server/textserver/handlermgr.cc b/server/textserver/handlermgr.cc new file mode 100644 index 0000000..e337e10 --- /dev/null +++ b/server/textserver/handlermgr.cc @@ -0,0 +1,80 @@ +#include "precompile.h" + +#include + +#include "handlermgr.h" + +#include "app.h" +#include "perfmonitor.h" + +static void _GMOpsSelfChecking(f8::JsonHttpRequest* request) +{ + request->resp_xobj->SetVal("errcode", 0); + request->resp_xobj->SetVal("errmsg", ""); + request->resp_xobj->SetVal("healthy", 1); + request->resp_xobj->SetVal("max_rundelay", PerfMonitor::Instance()->max_run_delay_time); + request->resp_xobj->SetVal("max_timer_idle", PerfMonitor::Instance()->max_timer_idle); +} + +static void _GMOpsReload(f8::JsonHttpRequest* request) +{ + request->resp_xobj->SetVal("errcode", 0); + request->resp_xobj->SetVal("errmsg", ""); + a8::UdpLog::Instance()->Warning("reload config files", {}); +} + +void HandlerMgr::Init() +{ + RegisterNetMsgHandlers(); + RegisterGMMsgHandler("Ops@selfChecking", _GMOpsSelfChecking); + RegisterGMMsgHandler("Ops@reload", _GMOpsReload); +} + +void HandlerMgr::UnInit() +{ +} + +void HandlerMgr::RegisterNetMsgHandlers() +{ +} + +void HandlerMgr::ProcGMMsg(unsigned long saddr, int sockhandle, + const std::string& url, const std::string& querystr) +{ + if (url != "/webapp/index.php") { + //IMListener::Instance()->SendText(sockhandle, a8::HttpResponse(404, "")); + return; + } + + a8::HTTPRequest request; + a8::ParserUrlQueryString(querystr.c_str(), request); + + std::string msgname = a8::Get(request, "c").GetString() + "@" + a8::Get(request, "a").GetString(); + auto itr = gmhandlers_.find(msgname); + if (itr != gmhandlers_.end()) { + f8::JsonHttpRequest* request = new f8::JsonHttpRequest; + request->saddr = saddr; + request->socket_handle = sockhandle; + request->query_str = querystr; + request->request.ReadFromUrlQueryString(querystr); + request->resp_xobj->SetVal("errcode", 0); + request->resp_xobj->SetVal("errmsg", ""); + itr->second(request); + + if (!request->pending){ + std::string response; + request->resp_xobj->ToJsonStr(response); + //IMListener::Instance()->SendText(sockhandle, a8::HttpResponse(response)); + + delete request; + } + } else { + //IMListener::Instance()->SendText(sockhandle, a8::HttpResponse("{}")); + } +} + +void HandlerMgr::RegisterGMMsgHandler(const std::string& msgname, + void (*handler)(f8::JsonHttpRequest*)) +{ + gmhandlers_[msgname] = handler; +} diff --git a/server/textserver/handlermgr.h b/server/textserver/handlermgr.h new file mode 100644 index 0000000..4b9fc01 --- /dev/null +++ b/server/textserver/handlermgr.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "framework/cpp/netmsghandler.h" + +namespace a8 +{ + class MutableXObject; +} + +class HandlerMgr : public a8::Singleton +{ + + private: + HandlerMgr() {}; + friend class a8::Singleton; + + public: + + void Init(); + void UnInit(); + + f8::NetMsgHandlerObject wsmsghandler; + f8::NetMsgHandlerObject immsghandler; + + void ProcGMMsg(unsigned long saddr, int sockhandle, + const std::string& url, const std::string& quyerstr); + + private: + void RegisterNetMsgHandlers(); + void RegisterGMMsgHandler(const std::string& msgname, + void (*)(f8::JsonHttpRequest*)); + + std::map gmhandlers_; +}; diff --git a/server/textserver/jsondatamgr.cc b/server/textserver/jsondatamgr.cc new file mode 100644 index 0000000..dc1653e --- /dev/null +++ b/server/textserver/jsondatamgr.cc @@ -0,0 +1,62 @@ +#include "precompile.h" + +#include "jsondatamgr.h" +#include "app.h" + +#include "framework/cpp/utils.h" + +void JsonDataMgr::Init() +{ + if (!f8::IsOnlineEnv()) { + if (f8::IsTestEnv()) { + work_path_ = a8::Format("/root/pub/%d/%d/conf_test/game%d/rankserver.test", + { + GAME_ID, + App::Instance()->instance_id, + GAME_ID + }); + } else { + work_path_ = a8::Format("/root/pub/%d/%d/conf_test/game%d/rankserver.dev", + { + GAME_ID, + App::Instance()->instance_id, + GAME_ID + }); + } + } + std::string rankserver_cluster_json_file; + std::string mysql_cluster_json_file; + mysql_cluster_json_file = a8::Format("%s/node1/friend.rankserver.mysql.cluster.json", + { + work_path_, + }); + + rankserver_cluster_json_file = a8::Format("%s/node1/friend.rankserver.cluster.json", + { + work_path_, + }); + rankserver_cluster_json_.ReadFromFile(rankserver_cluster_json_file); + mysql_cluster_json_.ReadFromFile(mysql_cluster_json_file); +} + +void JsonDataMgr::UnInit() +{ +} + +std::shared_ptr JsonDataMgr::GetConf() +{ + if (App::Instance()->instance_id < 1 || App::Instance()->instance_id > rankserver_cluster_json_.Size()) { + abort(); + } + return rankserver_cluster_json_[App::Instance()->instance_id - 1]; +} + +std::shared_ptr JsonDataMgr::GetMysqlClusterConf() +{ + return std::make_shared(mysql_cluster_json_); +} + +std::shared_ptr JsonDataMgr::GetMysqlConf(int instance_id) +{ + return mysql_cluster_json_[instance_id - 1]; +} diff --git a/server/textserver/jsondatamgr.h b/server/textserver/jsondatamgr.h new file mode 100644 index 0000000..8668e3f --- /dev/null +++ b/server/textserver/jsondatamgr.h @@ -0,0 +1,21 @@ +#pragma once + +class JsonDataMgr : public a8::Singleton +{ + private: + JsonDataMgr() {}; + friend class a8::Singleton; + + public: + void Init(); + void UnInit(); + + std::shared_ptr GetMysqlClusterConf(); + std::shared_ptr GetConf(); + std::shared_ptr GetMysqlConf(int instance_id); + + private: + std::string work_path_ = "../config"; + a8::XObject mysql_cluster_json_; + a8::XObject rankserver_cluster_json_; +}; diff --git a/server/textserver/main.cc b/server/textserver/main.cc new file mode 100644 index 0000000..81d0bc0 --- /dev/null +++ b/server/textserver/main.cc @@ -0,0 +1,14 @@ +#include "precompile.h" + +#include +#include +#include "app.h" + +int main(int argc, char* argv[]) +{ + int exitcode = 0; + App::Instance()->Init(argc, argv); + exitcode = App::Instance()->Run(); + App::Instance()->UnInit(); + return exitcode; +} diff --git a/server/textserver/metadata.cc b/server/textserver/metadata.cc new file mode 100644 index 0000000..e69de29 diff --git a/server/textserver/metadata.h b/server/textserver/metadata.h new file mode 100644 index 0000000..37e43ee --- /dev/null +++ b/server/textserver/metadata.h @@ -0,0 +1,3 @@ +#pragma once + +#include "metatable.pb.h" diff --git a/server/textserver/metamgr.cc b/server/textserver/metamgr.cc new file mode 100644 index 0000000..b8f83a4 --- /dev/null +++ b/server/textserver/metamgr.cc @@ -0,0 +1,180 @@ +#include "precompile.h" + +#include + +#include +#include + +#include "framework/cpp/utils.h" + +#include "metamgr.h" +#include "app.h" +#include "jsondatamgr.h" + +#define METAMGR_READ(field_name, def_val) MetaMgr::Instance()->field_name = \ + a8::XValue(MetaMgr::Instance()->GetSysParamAsString(#field_name, #def_val)); + +#define METAMGR_READ_STR(field_name, def_val) MetaMgr::Instance()->field_name = \ + a8::XValue(MetaMgr::Instance()->GetSysParamAsString(#field_name, def_val)).GetString(); + +static bool PureEnglishName(const std::string& role_name) +{ + for (size_t i = 0; i < role_name.size(); i++) { + if (role_name[i] >= 0 && role_name[i] <= 127) { + continue; + } else { + return false; + } + } + return true; +} + +class MetaDataLoader +{ +public: + std::map > dirty_words; + std::list text_meta_list; + + std::map text_hash; + + void Load() + { + if (!f8::IsOnlineEnv()) { + if (f8::IsTestEnv()) { + res_path = a8::Format("/root/pub/%d/%d/conf_test/game%d/rankserver.test/res%d/", + { + GAME_ID, + App::Instance()->instance_id, + GAME_ID, + App::Instance()->instance_id + }); + } else { + res_path = a8::Format("/root/pub/%d/%d/conf_test/game%d/rankserver.dev/res%d/", + { + GAME_ID, + App::Instance()->instance_id, + GAME_ID, + App::Instance()->instance_id + }); + } + } else { + res_path = "../res/"; + } + f8::ReadCsvMetaFile(res_path + "text@text.csv", text_meta_list); + LoadDirtyWordTable(); + BindToMetaData(); + Check(); + } + +private: + + void LoadDirtyWordTable() + { + a8::CsvReader reader; + reader.Load(res_path + "dirtyWord@dirtyWord.csv"); + while (reader.NextLine()) { + std::string strword = reader.GetValue("word").GetString(); + if (strword == " " || strword.empty()) { //忽略空格 + continue; + } + std::transform(strword.begin(), strword.end(), strword.begin(), ::tolower); + auto itr = dirty_words.find(strword.size()); + if (dirty_words.find(strword.size()) != dirty_words.end()) { + itr->second[strword] = strword; + } else { + std::map words; + words[strword] = strword; + dirty_words[strword.size()] = words; + } + } + } + + void Check() + { + } + + void BindToMetaData() + { + for (auto& meta : text_meta_list) { + text_hash[meta.textid()] = meta.text(); + } + } + +private: + std::string res_path; +}; + +void MetaMgr::Init() +{ + loader_ = new MetaDataLoader(); + loader_->Load(); +} + +void MetaMgr::UnInit() +{ + delete loader_; + loader_ = nullptr; +} + +void MetaMgr::Reload() +{ + delete loader_; + loader_ = nullptr; + + loader_ = new MetaDataLoader(); + loader_->Load(); +} + +bool MetaMgr::HasDirtyWord(const std::string& text) +{ + for (size_t i = 0; i < text.size(); i++) { + for (auto itr = loader_->dirty_words.begin(); itr != loader_->dirty_words.end(); ++itr) { + if (itr->first <= text.size() - i) { + std::string substr = text.substr(i, itr->first); + // 如果是纯英文,则先转为小写,根据策划说明,屏蔽字大小写不敏感 + std::transform(substr.begin(), substr.end(), substr.begin(), ::tolower); + if (substr.size() > 0 && itr->second.find(substr) != itr->second.end()) { + return true; + } + } + } + } + return false; +} + +std::string MetaMgr::ReplaceDirtyWord(const std::string& text, char c) +{ + std::string result; + result.reserve(text.size()); + for (size_t i = 0; i < text.size(); i++) { + bool found = false; + for (auto itr = loader_->dirty_words.begin(); itr != loader_->dirty_words.end(); ++itr) { + if (itr->first <= text.size() - i) { + std::string substr = text.substr(i, itr->first); + // 如果是纯英文,则先转为小写,根据策划说明,屏蔽字大小写不敏感 + if (PureEnglishName(substr)) { + transform(substr.begin(), substr.end(), substr.begin(), ::tolower); + } + if (substr.size() > 0 && itr->second.find(substr) != itr->second.end()) { + int str_len = a8::GetUtf8Length(substr.c_str()); + for (int j = 0; j < str_len; j++) { + result.push_back(c); + } + i += substr.size() - 1; + found = true; + break; + } + } + }//endfor map + if (!found) { + result.push_back(text[i]); + } + } + return result; +} + +std::string MetaMgr::GetText(const std::string& textid, const std::string& def_text) +{ + auto itr = loader_->text_hash.find(textid); + return itr != loader_->text_hash.end() ? itr->second : def_text; +} diff --git a/server/textserver/metamgr.h b/server/textserver/metamgr.h new file mode 100644 index 0000000..b24120e --- /dev/null +++ b/server/textserver/metamgr.h @@ -0,0 +1,29 @@ +#pragma once + +#include "metadata.h" + +#define TEXT(textid, def_text) MetaMgr::Instance()->GetText(textid, def_text) + +class MetaDataLoader; +class MetaMgr : public a8::Singleton +{ + + private: + MetaMgr() {}; + friend class a8::Singleton; + + public: + + void Init(); + void UnInit(); + void Reload(); + + bool HasDirtyWord(const std::string& text); + std::string ReplaceDirtyWord(const std::string& text, char c); + std::string GetText(const std::string& textid, const std::string& def_text=""); + + private: + MetaDataLoader* loader_ = nullptr; + + friend class MetaDataLoader; +}; diff --git a/server/textserver/perfmonitor.cc b/server/textserver/perfmonitor.cc new file mode 100644 index 0000000..42123fa --- /dev/null +++ b/server/textserver/perfmonitor.cc @@ -0,0 +1,64 @@ +#include "precompile.h" + +#include +#include + +#include "perfmonitor.h" +#include "app.h" + +static void SavePerfLog() +{ + a8::UdpLog::Instance()->Info + ("max_run_delay_time:%d max_timer_idle:%d " + "in_data_size:%d out_data_size:%d msgnode_size:%d " + "cache_friend_num:%d alloc_node_total_times:%d alloc_node_ok_times:%d " + "alloc_node_fail_times:%d " , + { + PerfMonitor::Instance()->max_run_delay_time, + PerfMonitor::Instance()->max_timer_idle, + PerfMonitor::Instance()->in_data_size, + PerfMonitor::Instance()->out_data_size, + App::Instance()->msgnode_size_, + PerfMonitor::Instance()->read_count, + PerfMonitor::Instance()->alloc_node_total_times, + PerfMonitor::Instance()->alloc_node_ok_times, + PerfMonitor::Instance()->alloc_node_fail_times + }); + a8::UdpLog::Instance()->Info + ("run_times:%d timer_times:%d event_times:%d free_times:%d " + "shutdown_times:%d connect_times:%d close_times:%d " + "send_times:%d recv_times:%d error_times:%d immsg_times:%d", + { + (long long)a8::IoLoop::Instance()->run_times, + (long long)a8::IoLoop::Instance()->timer_times, + (long long)a8::IoLoop::Instance()->event_times, + (long long)a8::IoLoop::Instance()->free_times, + (long long)a8::IoLoop::Instance()->shutdown_times, + (long long)a8::IoLoop::Instance()->connect_times, + (long long)a8::IoLoop::Instance()->close_times, + (long long)a8::IoLoop::Instance()->send_times, + (long long)a8::IoLoop::Instance()->recv_times, + (long long)a8::IoLoop::Instance()->error_times, + (long long)a8::IoLoop::Instance()->immsg_times + }); + PerfMonitor::Instance()->max_run_delay_time = 0; + PerfMonitor::Instance()->max_timer_idle = 0; +} + +void PerfMonitor::Init() +{ + { + int perf_log_time = 1000 * 60 * 5; + a8::Timer::Instance()->AddRepeatTimer(perf_log_time, + a8::XParams(), + [] (const a8::XParams& param) + { + SavePerfLog(); + }); + } +} + +void PerfMonitor::UnInit() +{ + +} diff --git a/server/textserver/perfmonitor.h b/server/textserver/perfmonitor.h new file mode 100644 index 0000000..8c537e5 --- /dev/null +++ b/server/textserver/perfmonitor.h @@ -0,0 +1,22 @@ +#pragma once + +class PerfMonitor : public a8::Singleton +{ + private: + PerfMonitor() {}; + friend class a8::Singleton; + + public: + int max_run_delay_time = 0; + int max_timer_idle = 0; + int max_dispatchmsg_time = 0; + long long out_data_size = 0; + long long in_data_size = 0; + long long read_count = 0; + long long alloc_node_total_times = 0; + long long alloc_node_ok_times = 0; + long long alloc_node_fail_times = 0; + + void Init(); + void UnInit(); +}; diff --git a/server/textserver/precompile.h b/server/textserver/precompile.h new file mode 100644 index 0000000..7846db5 --- /dev/null +++ b/server/textserver/precompile.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "constant.h" +#include "types.h" + +namespace google +{ + namespace protobuf + { + class Message; + } +} + +#include "framework/cpp/types.h" +#include "framework/cpp/utils.h" +#include "framework/cpp/protoutils.h" diff --git a/server/textserver/typeconvert.cc b/server/textserver/typeconvert.cc new file mode 100644 index 0000000..ef6c5bc --- /dev/null +++ b/server/textserver/typeconvert.cc @@ -0,0 +1,3 @@ +#include "precompile.h" + +#include "typeconvert.h" diff --git a/server/textserver/typeconvert.h b/server/textserver/typeconvert.h new file mode 100644 index 0000000..c4614b0 --- /dev/null +++ b/server/textserver/typeconvert.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +class TypeConvert +{ + public: +}; diff --git a/server/textserver/types.cc b/server/textserver/types.cc new file mode 100644 index 0000000..981bc36 --- /dev/null +++ b/server/textserver/types.cc @@ -0,0 +1,3 @@ +#include "precompile.h" + + diff --git a/server/textserver/types.h b/server/textserver/types.h new file mode 100755 index 0000000..6f70f09 --- /dev/null +++ b/server/textserver/types.h @@ -0,0 +1 @@ +#pragma once diff --git a/server/tools/protobuild/metatable.proto b/server/tools/protobuild/metatable.proto new file mode 100644 index 0000000..b12e6b3 --- /dev/null +++ b/server/tools/protobuild/metatable.proto @@ -0,0 +1,13 @@ +package metatable; + +message MFPair +{ + optional int32 key = 1; //key + optional int32 value = 2; //val +} + +message Text +{ + optional string textid = 1; + optional string text = 2; +}