diff --git a/server/masterserver/CMakeLists.txt b/server/masterserver/CMakeLists.txt new file mode 100644 index 0000000..ebdc98d --- /dev/null +++ b/server/masterserver/CMakeLists.txt @@ -0,0 +1,136 @@ +project(masterserver) +cmake_minimum_required(VERSION 2.8) + +set(GAME_ID 2006) + +if (${RELEASE}) + set(CMAKE_BUILD_TYPE "Release") + message("release mode") +else() + set(CMAKE_BUILD_TYPE "Debug") + message("debug mode") +endif() + +set(LIB_DIR "ubuntu20.04_g++-9") +message(LIB_DIR: ${LIB_DIR} ) + +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -g -std=gnu++1z -DGAME_ID=${GAME_ID} -DNDEBUG") +set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -std=gnu++1z -DGAME_ID=${GAME_ID} -DDEBUG") + +include_directories( + AFTER + ../../third_party/a8 + ../../third_party/f8 + /usr/include/mysql + /usr/include/jsoncpp + /usr/include/hiredis + /usr/include/glm + ../../third_party + ../../third_party/behaviac/inc + ../../third_party/recastnavigation/Recast/Include + ../../third_party/recastnavigation/Detour/Include + ../../third_party/recastnavigation/DetourTileCache/Include + behaviac_generated/types + behaviac_generated/types/internal + . +) + +link_directories( + /usr/lib64/mysql + /usr/local/lib + ../../third_party/behaviac/lib/${LIB_DIR} +) + +aux_source_directory(../../third_party/a8/a8 + SRC_LIST +) + +aux_source_directory(../../third_party/f8/f8 + SRC_LIST +) + +aux_source_directory(../../third_party/recastnavigation/Recast/Source + SRC_LIST +) + +aux_source_directory(../../third_party/recastnavigation/Detour/Source + SRC_LIST +) + +aux_source_directory(../../third_party/recastnavigation/DetourTileCache/Source + SRC_LIST +) + +aux_source_directory(behaviac_generated/types/internal + SRC_LIST +) + +aux_source_directory(mtb + SRC_LIST +) + +aux_source_directory(mt + SRC_LIST +) + +aux_source_directory(buff + SRC_LIST +) + +execute_process( + COMMAND touch -a cs_proto.pb.h + COMMAND touch -a cs_proto.pb.cc + COMMAND touch -a cs_msgid.pb.h + COMMAND touch -a cs_msgid.pb.cc + COMMAND touch -a ss_proto.pb.h + COMMAND touch -a ss_proto.pb.cc + COMMAND touch -a ss_msgid.pb.h + COMMAND touch -a ss_msgid.pb.cc + ) +aux_source_directory(. + SRC_LIST +) + +set(EXECUTABLE_OUTPUT_PATH + ${PROJECT_BINARY_DIR}/../bin +) + +add_executable( + masterserver${GAME_ID} ${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=cs_proto,cs_msgid,ss_proto,ss_msgid) +# add_dependencies(masterserver${GAME_ID} script_pb_protocol) + +target_link_libraries( + masterserver${GAME_ID} + pthread + mysqlclient + protobuf + rt + dl + util + crypto + ssl + jsoncpp + curl + hiredis + tinyxml2 + backtrace + ) + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + target_link_libraries( + masterserver${GAME_ID} + behaviac_gcc_debug + ) +else() + target_link_libraries( + masterserver${GAME_ID} + tcmalloc + behaviac_gcc_release + ) +endif() diff --git a/server/masterserver/GGListener.cc b/server/masterserver/GGListener.cc new file mode 100644 index 0000000..352852a --- /dev/null +++ b/server/masterserver/GGListener.cc @@ -0,0 +1,163 @@ +#include "precompile.h" + +#include +#include +#include + +#include "GGListener.h" + +#include +#include +#include + +#include "app.h" +#include "handlermgr.h" + +class GCClientSession: public a8::MixedSession +{ +public: + + virtual void DecodeUserPacket(char* buf, int& offset, unsigned int buflen) override + { + #if 1 + is_activite = true; + #endif + bool warning = false; + while (buflen - offset >= sizeof(f8::WSProxyPackHead_C)) { + f8::WSProxyPackHead_C* p = (f8::WSProxyPackHead_C*)&buf[offset]; + if (p->magic_code == f8::MAGIC_CODE) { + if (buflen - offset < sizeof(f8::WSProxyPackHead_C) + p->packlen) { + break; + } + App::Instance()->AddSocketMsg(SF_GameGate, + (socket_handle << 16) + p->socket_handle, + p->ip_saddr, + p->msgid, + p->seqid, + &buf[offset + sizeof(f8::WSProxyPackHead_C)], + p->packlen); + offset += sizeof(f8::WSProxyPackHead_C) + p->packlen; + } else { + warning = true; + offset++; + continue; + } + } + + if (warning) { + f8::UdpLog::Instance()->Warning("收到client非法数据包", {}); + } + } + + virtual void OnRawHttpGet(const std::string& url, const std::string& querystr, + std::string& response) override + { + f8::MsgQueue::Instance()->PostMsg + (IM_ExecGM, + a8::Args + ( + { + socket_handle, + a8::XValue(url).GetString(), + a8::XValue(querystr).GetString(), + saddr + } + )); + } + + virtual void OnDisConnect() override + { + f8::MsgQueue::Instance()->PostMsg + (IM_ClientSocketDisconnect, + a8::Args + ( + { + socket_handle + } + )); + } + +}; + +static void CreateGameClientSocket(a8::TcpSession **p) +{ + *p = new GCClientSession(); + (*p)->SetMaxPacketLen(1024 * 1024 * 10); +} + +static void GSListeneron_error(a8::TcpListener*, int type, int errorid) +{ + f8::UdpLog::Instance()->Debug("GGListeneron_error %d %d", {type, errorid}); + f8::MsgQueue::Instance()->PostMsg + (IM_GGListenerError, + a8::Args + ( + { + errorid + } + )); + abort(); +} + +void GGListener::Init() +{ + tcp_listener_ = std::make_shared(); + tcp_listener_->on_create_client_socket = CreateGameClientSocket; + tcp_listener_->on_error = GSListeneron_error; + + tcp_listener_->bind_address = "0.0.0.0"; + #if 0 + tcp_listener_->bind_port = JsonDataMgr::Instance()->GetConf()->At("listen_port")->AsXValue(); + tcp_listener_->Open(); + #endif + + f8::MsgQueue::Instance()->RegisterCallBack + (IM_GGListenerError, + [] (const a8::Args& args) + { + int error_id = args.Get(0); + GGListener::Instance()->OnListenError(error_id); + }); +} + +void GGListener::UnInit() +{ + tcp_listener_ = nullptr; +} + +void GGListener::SendText(int sockhandle, const std::string& text) +{ + tcp_listener_->SendClientMsg(sockhandle, text.data(), text.size()); +} + +void GGListener::ForceCloseClient(int sockhandle) +{ + tcp_listener_->ForceCloseClient(sockhandle); +} + +void GGListener::MarkClient(int sockhandle, bool is_active) +{ + tcp_listener_->MarkClient(sockhandle, is_active); +} + +long long GGListener::GetSendNodeNum() +{ + return tcp_listener_->send_node_num; +} + +long long GGListener::GetSentNodeNum() +{ + return tcp_listener_->sent_node_num; +} + +long long GGListener::GetSentBytesNum() +{ + return tcp_listener_->sent_bytes_num; +} + +void GGListener::OnListenError(int errorid) +{ + a8::XPrintf("GGListeneron_error %d\n", {errorid}); + App::Instance()->terminated = true; + exit(1); +} diff --git a/server/masterserver/GGListener.h b/server/masterserver/GGListener.h new file mode 100644 index 0000000..0fe8fd9 --- /dev/null +++ b/server/masterserver/GGListener.h @@ -0,0 +1,64 @@ +#pragma once + +#include + +#include +#include + +//game client listener +namespace a8 +{ + class TcpListener; +} + +class GGListener : public a8::Singleton +{ +private: + GGListener() {}; + friend class a8::Singleton; + +public: + enum { HID = HID_GGListener }; + +public: + void Init(); + void UnInit(); + + int max_packet_size = 0; + int his_max_packet_size = 0; + + template + void SendProxyMsg(int sockhandle, T& msg) + { + static int msgid = f8::Net_GetMessageId(msg); + f8::Net_SendProxyMsg(tcp_listener_.get(), sockhandle, 0, 0, msgid, msg); + } + + template + void SendToClient(int sockhandle, unsigned int seqid, T& msg) + { + static int msgid = f8::Net_GetMessageId(msg); + int packet_size = f8::Net_SendProxyMsg(tcp_listener_.get(), sockhandle, seqid, 0, msgid, msg); + if (packet_size > max_packet_size) { + max_packet_size = packet_size; + } + } + void SendText(int sockhandle, const std::string& text); + + void SendError(int sockhandle, unsigned int seqid, + int error_code, const std::string& error_msg, + const char* file = nullptr, int lineno = 0, int error_param = 0); + + void ForceCloseClient(int sockhandle); + void ForceCloseChildSocket(int sockhandle); + void MarkClient(int sockhandle, bool is_active); + long long GetSendNodeNum(); + long long GetSentNodeNum(); + long long GetSentBytesNum(); + +private: + void OnListenError(int errorid); + +private: + std::shared_ptr tcp_listener_; +}; diff --git a/server/masterserver/app.cc b/server/masterserver/app.cc new file mode 100644 index 0000000..ddad45c --- /dev/null +++ b/server/masterserver/app.cc @@ -0,0 +1,442 @@ +#include "precompile.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "app.h" +#include "handlermgr.h" +#if 0 +#include "ss_msgid.pb.h" +#include "ss_proto.pb.h" +#endif +#include "GGListener.h" +#include "selfchecker.h" +#include "httpproxy.h" + +#include "mt/MetaMgr.h" + +struct MsgNode +{ + SocketFrom_e sockfrom; + int sockhandle; + unsigned short msgid; + unsigned int seqid; + long ip_saddr; + char* buf; + int buflen; + MsgNode* next; +}; + +const char* const PROJ_LOG_ROOT_FMT = "/data/logs/%s/logs"; +const char* const PROJ_LOG_FILENAME_FMT = "log_$pid_%Y%m%d.log"; + +static void SavePerfLog() +{ +} + +bool App::Init(int argc, char* argv[]) +{ + signal(SIGPIPE, SIG_IGN); + this->argc = argc; + this->argv = argv; + + if (!ParseOpt()) { + if (node_id <= 0) { + a8::XPrintf("imserver启动失败,缺少-n参数\n", {}); + } else if (node_id > MAX_NODE_ID) { + a8::XPrintf("imserver启动失败,-n参数不能大于%d\n", {MAX_NODE_ID}); + } else if (instance_id <= 0) { + a8::XPrintf("imserver启动失败,缺少-i参数\n", {}); + } else if (instance_id > MAX_INSTANCE_ID) { + a8::XPrintf("imserver启动失败,-i参数不能大于%d\n", {MAX_INSTANCE_ID}); + } + return false; + } + int debug_mode = 0; +#ifdef DEBUG + debug_mode = 1; +#endif + a8::XPrintf("imserver starting node_id: %d instance_id:%d pid:%d game_id:%d debug_mode:%d\n", + { + node_id, + instance_id, + getpid(), + GAME_ID, + debug_mode + }); + + loop_mutex_ = new std::mutex(); + loop_cond_ = new std::condition_variable(); + msg_mutex_ = new std::mutex(); + + srand(time(nullptr)); + InitLog(); + f8::MsgQueue::Instance()->Init(); + HandlerMgr::Instance()->Init(); + f8::Timer::Instance()->Init(); + f8::TGLog::Instance()->Init(a8::Format(PROJ_NAME_FMT, {GAME_ID}), false, 0); + f8::HttpClientPool::Instance()->Init(MAX_ALL_HTTP_NUM, MAX_SYS_HTTP_NUM, MAX_USER_HTTP_NUM); + mt::MetaMgr::Instance()->Init(); + SelfChecker::Init(); + uuid.SetMachineId((node_id - 1) * MAX_NODE_ID + instance_id); + GGListener::Instance()->Init(); + HttpProxy::Instance()->Init(); + + #if 0 + f8::UdpLog::Instance()->Info("imserver starting instance_id:%d pid:%d debug_mode:%d channel:%d", + { + instance_id, + getpid(), + debug_mode, + JsonDataMgr::Instance()->channel + }); + #endif + { + int perf_log_time = 1000 * 30; + f8::Timer::Instance()->SetInterval + (perf_log_time, + [] (int event, const a8::Args* args) + { + if (a8::TIMER_EXEC_EVENT == event) { + SavePerfLog(); + } + }); + } + if (HasFlag(7)) { + f8::Timer::Instance()->SetTimeout + ( + 1000 * 60 * 1, + [] (int event, const a8::Args* args) + { + if (a8::TIMER_EXEC_EVENT == event) { + App::Instance()->terminated = true; + } + } + ); + } + return true; +} + +void App::UnInit() +{ + HttpProxy::Instance()->UnInit(); + GGListener::Instance()->UnInit(); + SelfChecker::UnInit(); + mt::MetaMgr::Instance()->UnInit(); + f8::HttpClientPool::Instance()->UnInit(); + HandlerMgr::Instance()->UnInit(); + f8::MsgQueue::Instance()->UnInit(); + f8::Timer::Instance()->UnInit(); + f8::TGLog::Instance()->UnInit(); + UnInitLog(); + + FreeSocketMsgQueue(); + A8_SAFE_DELETE(msg_mutex_); + A8_SAFE_DELETE(loop_cond_); + A8_SAFE_DELETE(loop_mutex_); +} + +int App::Run() +{ + int ret = 0; + f8::UdpLog::Instance()->Info("imserver running", {}); + last_run_tick_ = a8::XGetTickCount(); + int delta_time = 0; + while (!terminated) { + a8::tick_t begin_tick = a8::XGetTickCount(); + #if 0 + Global::g_nowtime = time(nullptr); + #endif + QuickExecute(delta_time); + SlowerExecute(delta_time); + Schedule(); + a8::tick_t end_tick = a8::XGetTickCount(); + #if 0 + if (end_tick - begin_tick > PerfMonitor::Instance()->max_run_delay_time) { + PerfMonitor::Instance()->max_run_delay_time = end_tick - begin_tick; + } + #endif + 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::QuickExecute(int delta_time) +{ + f8::MsgQueue::Instance()->Update(); + DispatchMsg(); + f8::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() +{ + std::unique_lock lk(*loop_mutex_); + loop_cond_->wait_for(lk, std::chrono::milliseconds(1)); +} + +bool App::HasTask() +{ + { + 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 begin_tick = 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_GameGate: + { + ProcessGameGateMsg(hdr); + } + break; + } + if (pdelnode->buf) { + free(pdelnode->buf); + } + free(pdelnode); + working_msgnode_size_--; + if (a8::XGetTickCount() - begin_tick > 200) { + break; + } + }//end while + + if (!work_node_) { + working_msgnode_size_ = 0; + } + a8::tick_t end_tick = a8::XGetTickCount(); + #if 0 + if (end_tick - begin_tick > PerfMonitor::Instance()->max_dispatchmsg_time) { + PerfMonitor::Instance()->max_dispatchmsg_time = end_tick - begin_tick; + } + #endif +} + +void App::ProcessGameGateMsg(f8::MsgHdr& hdr) +{ + #if 0 + if (hdr.msgid == ss::_SS_Ping) { + ss::SS_Pong pongmsg; + GGListener::Instance()->SendProxyMsg(hdr.socket_handle, pongmsg); + return; + } + #endif + f8::NetMsgHandler* handler = f8::GetNetMsgHandler(&HandlerMgr::Instance()->ggmsghandler, + hdr.msgid); + if (handler) { + switch (handler->handlerid) { + case HID_PlayerMgr: + { + #if 0 + ProcessNetMsg(handler, PlayerMgr::Instance(), hdr); + #endif + } + break; + case HID_Player: + { + #if 0 + Player* hum = PlayerMgr::Instance()->GetPlayerBySocket(hdr.socket_handle); + if (hum) { + hdr.hum = hum; + ProcessNetMsg(handler, hum, hdr); + } + #endif + } + break; + } + } +} + +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,{GAME_ID})}); + std::string proj_log_root_dir = a8::Format(PROJ_LOG_ROOT_FMT, {a8::Format(PROJ_NAME_FMT, {GAME_ID})}); + std::string log_file_name = a8::Format(PROJ_LOG_ROOT_FMT, + {a8::Format(PROJ_NAME_FMT, {GAME_ID})}) + "/" + filename_fmt; + + a8::MkDir(proj_root_dir); + a8::MkDir(proj_log_root_dir); + f8::UdpLog::Instance()->SetLogFileName(log_file_name); + f8::UdpLog::Instance()->Init(); + f8::UdpLog::Instance()->Info("proj_root_dir:%s", {proj_root_dir}); + f8::UdpLog::Instance()->Info("proj_log_root_dir:%s", {proj_log_root_dir}); + f8::UdpLog::Instance()->Info("log_file_name:%s", {log_file_name}); +} + +void App::UnInitLog() +{ + f8::UdpLog::Instance()->UnInit(); +} + +bool App::ParseOpt() +{ + int ch = 0; + while ((ch = getopt(argc, argv, "i:t:r:f:n:")) != -1) { + switch (ch) { + case 'n': + { + node_id = a8::XValue(optarg); + } + break; + 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 && node_id > 0; +} + +long long App::NewUuid() +{ + return uuid.Generate(); +} + +bool App::HasFlag(int flag) +{ + return flags.find(flag) != flags.end(); +} + +void App::SetFlag(int flag) +{ + flags.insert(flag); +} + +void App::UnSetFlag(int flag) +{ + flags.erase(flag); +} + +void App::FreeSocketMsgQueue() +{ + msg_mutex_->lock(); + if (!work_node_) { + work_node_ = top_node_; + top_node_ = nullptr; + bot_node_ = nullptr; + } + while (work_node_) { + MsgNode* pdelnode = work_node_; + work_node_ = work_node_->next; + if (pdelnode->buf) { + free(pdelnode->buf); + } + free(pdelnode); + if (!work_node_) { + work_node_ = top_node_; + top_node_ = nullptr; + bot_node_ = nullptr; + } + } + msg_mutex_->unlock(); +} diff --git a/server/masterserver/app.h b/server/masterserver/app.h new file mode 100644 index 0000000..1e70b37 --- /dev/null +++ b/server/masterserver/app.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include + +#include + +struct MsgNode; +class App : public a8::Singleton +{ +private: + App() {}; + friend class a8::Singleton; + +public: + #ifdef DEBUG + std::map debug_params; + #endif + + bool 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 NotifyLoopCond(); + + long long NewUuid(); + bool HasFlag(int flag); + void SetFlag(int flag); + void UnSetFlag(int flag); + +private: + void QuickExecute(int delta_time); + void SlowerExecute(int delta_time); + void Schedule(); + bool HasTask(); + + void DispatchMsg(); + + void ProcessGameGateMsg(f8::MsgHdr& hdr); + + void InitLog(); + void UnInitLog(); + + bool ParseOpt(); + void FreeSocketMsgQueue(); + +public: + int argc = 0; + char** argv = nullptr; + volatile bool terminated = false; + a8::uuid::SnowFlake uuid; + +public: + int instance_id = 0; + int node_id = 0; + bool is_test_mode = false; + int test_param = 0; + bool servicing = true; + +private: + /* + 1: 是否自动匹配机器人组队 + 2: 是否发布环境 + 3: battleReport环境 + 4: 打印性能日志 + 5: 压力测试 + 6: + 7: 内存泄露测试 + 8: httpclientpool压力测试 + */ + 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; + + long long curr_uniid_ = 0; + +public: + int msgnode_size_ = 0 ; + int working_msgnode_size_ = 0; + +}; diff --git a/server/masterserver/constant.h b/server/masterserver/constant.h new file mode 100644 index 0000000..9876137 --- /dev/null +++ b/server/masterserver/constant.h @@ -0,0 +1,35 @@ +#pragma once + +enum SocketFrom_e +{ + SF_GameGate, +}; + +enum InnerMesssage_e +{ + IM_ClientSocketDisconnect = 100, + IM_ExecGM, + IM_GGListenerError +}; + +//网络处理对象 +enum NetHandler_e +{ + HID_Player, + HID_PlayerMgr, + HID_Room, + HID_RoomMgr, + HID_MatchMgr, + HID_MatchTeam, + HID_GGListener, +}; + +const int MAX_NODE_ID = 8; +const int MAX_INSTANCE_ID = 500; + +const int MAX_SYS_HTTP_NUM = 2; +const int MAX_USER_HTTP_NUM = 8; +const int MAX_ALL_HTTP_NUM = MAX_SYS_HTTP_NUM + MAX_USER_HTTP_NUM; + +const char* const PROJ_NAME_FMT = "game%d_gameserver"; +const char* const PROJ_ROOT_FMT = "/data/logs/%s"; diff --git a/server/masterserver/handlermgr.cc b/server/masterserver/handlermgr.cc new file mode 100644 index 0000000..15b3380 --- /dev/null +++ b/server/masterserver/handlermgr.cc @@ -0,0 +1,145 @@ +#include "precompile.h" + +#include + +#include +#include +#include + +#include "handlermgr.h" + +#include "GGListener.h" +#include "app.h" +#include "cs_proto.pb.h" +#include "ss_proto.pb.h" + +static void _GMOpsSelfChecking(std::shared_ptr request) +{ + request->resp_xobj->SetVal("errcode", 0); + request->resp_xobj->SetVal("errmsg", ""); + request->resp_xobj->SetVal("healthy", 1); + request->resp_xobj->SetVal("servicing", App::Instance()->servicing ? 1 : 0); + #if 0 + request->resp_xobj->SetVal("max_rundelay", PerfMonitor::Instance()->max_run_delay_time); + request->resp_xobj->SetVal("max_timer_idle", PerfMonitor::Instance()->max_timer_idle); + #endif +} + +static void _GMOpsReload(std::shared_ptr request) +{ + request->resp_xobj->SetVal("errcode", 0); + request->resp_xobj->SetVal("errmsg", ""); + #if 0 + JsonDataMgr::Instance()->Reload(); + f8::UdpLog::Instance()->Info("reload config files", {}); + #endif +} + +static void _GMOpsStopService(std::shared_ptr request) +{ + request->resp_xobj->SetVal("errcode", 0); + request->resp_xobj->SetVal("errmsg", ""); + App::Instance()->servicing = false; +} + +static void _GMOpsStartService(std::shared_ptr request) +{ + request->resp_xobj->SetVal("errcode", 0); + request->resp_xobj->SetVal("errmsg", ""); + App::Instance()->servicing = true; +} + +static void _GMOpsServerInfo(std::shared_ptr request) +{ + request->resp_xobj->SetVal("errcode", 0); + request->resp_xobj->SetVal("errmsg", ""); + request->resp_xobj->SetVal("node_id", App::Instance()->node_id); + request->resp_xobj->SetVal("instance_id", App::Instance()->instance_id); +} + +static void _GMStatGetRealTimeOnline(std::shared_ptr request) +{ + request->resp_xobj->SetVal("errcode", 0); + request->resp_xobj->SetVal("errmsg", ""); +#if 0 + request->resp_xobj->SetVal("num", PerfMonitor::Instance()->entity_num[ET_Player]); + request->resp_xobj->SetVal("room_num", RoomMgr::Instance()->RoomNum()); +#endif +} + +void HandlerMgr::Init() +{ + RegisterNetMsgHandlers(); + RegisterGMMsgHandler("Ops@selfChecking", _GMOpsSelfChecking); + RegisterGMMsgHandler("Ops@reload", _GMOpsReload); + RegisterGMMsgHandler("Ops@stopService", _GMOpsStopService); + RegisterGMMsgHandler("Ops@startService", _GMOpsStartService); + RegisterGMMsgHandler("Ops@serverInfo", _GMOpsServerInfo); + RegisterGMMsgHandler("Stat@getRealTimeOnline", _GMStatGetRealTimeOnline); + f8::MsgQueue::Instance()->RegisterCallBack + ( + IM_ExecGM, + [] (const a8::Args& args) + { + int socket_handle = args.Get(0); + std::string url = args.Get(1); + std::string query_str = args.Get(2); + unsigned long saddr = args.Get(3); + + HandlerMgr::Instance()->ProcGMMsg + ( + saddr, + socket_handle, + url, + query_str + ); + }); +} + +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") { + GGListener::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()) { + auto request = std::make_shared(); + request->saddr = saddr; + request->socket_handle = sockhandle; + request->query_str = querystr; + request->params->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); + GGListener::Instance()->SendText(sockhandle, a8::HttpResponse(response)); + } + } else { + GGListener::Instance()->SendText(sockhandle, a8::HttpResponse("{}")); + } +} + +void HandlerMgr::RegisterGMMsgHandler(const std::string& msgname, + void (*handler)(std::shared_ptr)) +{ + gmhandlers_[msgname] = handler; +} diff --git a/server/masterserver/handlermgr.h b/server/masterserver/handlermgr.h new file mode 100644 index 0000000..41d5c65 --- /dev/null +++ b/server/masterserver/handlermgr.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +#include +#include + +namespace a8 +{ + class MutableXObject; +} + +class HandlerMgr : public a8::Singleton +{ + + private: + HandlerMgr() {}; + friend class a8::Singleton; + + public: + + void Init(); + void UnInit(); + + f8::NetMsgHandlerObject ggmsghandler; + + void RegisterGMMsgHandler(const std::string& msgname, + void (*)(std::shared_ptr)); + + private: + void RegisterNetMsgHandlers(); + void ProcGMMsg(unsigned long saddr, int sockhandle, + const std::string& url, const std::string& quyerstr); + + std::map)> gmhandlers_; +}; diff --git a/server/masterserver/httpproxy.cc b/server/masterserver/httpproxy.cc new file mode 100644 index 0000000..f552423 --- /dev/null +++ b/server/masterserver/httpproxy.cc @@ -0,0 +1,144 @@ +#include "precompile.h" + +#include +#include + +#include +#include + +#include "httpproxy.h" +#include "app.h" +#include "handlermgr.h" + +#include "f8/httpclientpool.h" + +struct HttpProxyRequest +{ + std::string req_id; + f8::HttpProxyCb cb; + std::string url; + a8::XObject url_params; + long long add_tick = 0; +}; + +static void _ProxyCallback(std::shared_ptr request) +{ + #ifdef DEBUG + f8::UdpLog::Instance()->Debug("ProxyCallbBack request:%s", + { + request->params->ToJsonStr() + }); + #endif + std::string seq_id = request->params->Get("seq_id"); + std::shared_ptr req = HttpProxy::Instance()->GetRequest(seq_id); + if (req) { + a8::XObject data; + + data.ReadFromJsonString(request->params->Get("data").GetString()); + if (data.GetType() == a8::XOT_SIMPLE) { + data.ReadFromJsonString("{}"); + } + f8::HttpContext ctx; + if (request->params->HasKey("errcode") && + request->params->Get("errcode").GetInt() == 0) { + req->cb(true, &data, &ctx); + } else { + req->cb(false, request->params.get(), &ctx); + } + HttpProxy::Instance()->DestoryRequest(req); + } +} + +void HttpProxy::Init() +{ + request_prefix_ = "game2006_" + a8::XValue(a8::GetMilliSecond()).GetString() + "_"; + HandlerMgr::Instance()->RegisterGMMsgHandler("Proxy@callback", _ProxyCallback); +} + +void HttpProxy::UnInit() +{ + +} + +std::string HttpProxy::HttpGet( + f8::HttpProxyCb cb, + const char* url, + a8::XObject url_params + ) +{ + std::shared_ptr request = std::make_shared(); + request->req_id = CreateRequestId(); + request->cb = cb; + request->url = url; + request->url_params = url_params; + request->add_tick = a8::XGetTickCount(); + if (request_hash_.find(request->req_id) != request_hash_.end()) { + abort(); + } + request_hash_[request->req_id] = request; + + + auto proxy_url_params = a8::MutableXObject::CreateObject(); + proxy_url_params->SetVal("seq_id", request->req_id); + proxy_url_params->SetVal("target_url", std::string(url)); + proxy_url_params->SetVal("params", url_params.ToJsonStr()); + #if 0 + proxy_url_params->SetVal("cb_url", a8::Format("http://%s:%d/webapp/index.php?c=Proxy&a=callback", + { + JsonDataMgr::Instance()->ip, + JsonDataMgr::Instance()->listen_port + })); + #endif + + std::string proxy_url; + #if 0 + JsonDataMgr::Instance()->GetHttpProxyUrl(proxy_url); + #endif + f8::HttpClientPool::Instance()->HttpGet + ( + [request] (bool ok, a8::XObject* rsp_obj, f8::HttpContext* ctx) + { + long long cost_time = a8::XGetTickCount() - request->add_tick; + if (ok) { +#ifdef DEBUG + f8::UdpLog::Instance()->Debug("ProxyHttpGet ok cost_time:%d url:%s params:%s", + { + cost_time, + request->url, + request->url_params.ToJsonStr(), + }); +#endif + } else { + f8::UdpLog::Instance()->Warning("ProxyHttpGet error cost_time:%d url:%s params:%s response:%s", + { + cost_time, + request->url, + request->url_params.ToJsonStr(), + ctx->response + }); + request->cb(false, rsp_obj, ctx); + HttpProxy::Instance()->DestoryRequest(request); + } + }, + proxy_url.c_str(), + *proxy_url_params, + rand() % MAX_SYS_HTTP_NUM + ); + return request->req_id; +} + +std::string HttpProxy::CreateRequestId() +{ + return request_prefix_ + a8::XValue(App::Instance()->NewUuid()).GetString(); +} + +std::shared_ptr HttpProxy::GetRequest(const std::string& req_id) +{ + auto itr = request_hash_.find(req_id); + return itr != request_hash_.end() ? itr->second : nullptr; +} + +void HttpProxy::DestoryRequest(std::shared_ptr request) +{ + request_hash_.erase(request->req_id); +} diff --git a/server/masterserver/httpproxy.h b/server/masterserver/httpproxy.h new file mode 100644 index 0000000..789ed01 --- /dev/null +++ b/server/masterserver/httpproxy.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "f8/httpclientpool.h" + +struct HttpProxyRequest; +class HttpProxy : public a8::Singleton +{ + + private: + HttpProxy() {}; + friend class a8::Singleton; + + public: + + void Init(); + void UnInit(); + + std::string HttpGet( + f8::HttpProxyCb cb, + const char* url, + a8::XObject url_params + ); + std::shared_ptr GetRequest(const std::string& req_id); + void DestoryRequest(std::shared_ptr request); + + private: + + std::string CreateRequestId(); + + private: + std::map> request_hash_; + std::string request_prefix_; + +}; diff --git a/server/masterserver/main.cc b/server/masterserver/main.cc new file mode 100644 index 0000000..3ca4bad --- /dev/null +++ b/server/masterserver/main.cc @@ -0,0 +1,12 @@ +#include "precompile.h" +#include "app.h" + +int main(int argc, char* argv[]) +{ + int exitcode = 0; + if (App::Instance()->Init(argc, argv)) { + exitcode = App::Instance()->Run(); + App::Instance()->UnInit(); + } + return exitcode; +} diff --git a/server/masterserver/mt/Forward.h b/server/masterserver/mt/Forward.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/server/masterserver/mt/Forward.h @@ -0,0 +1 @@ +#pragma once diff --git a/server/masterserver/mt/MetaMgr.cc b/server/masterserver/mt/MetaMgr.cc new file mode 100644 index 0000000..4d444d7 --- /dev/null +++ b/server/masterserver/mt/MetaMgr.cc @@ -0,0 +1,60 @@ +#include "precompile.h" + +#include "mt/MetaMgr.h" + +#include "app.h" + +namespace mt +{ + + void MetaMgr::Init() + { + if (!f8::IsOnlineEnv()) { + if (f8::IsTestEnv()) { + res_path_ = a8::Format("../../../conf_test/game%d/gameserver.test/res%d/", + { + GAME_ID, + App::Instance()->instance_id + }); + } else { + res_path_ = a8::Format("../../../conf_test/game%d/gameserver.dev/res%d/", + { + GAME_ID, + App::Instance()->instance_id + }); + } + } else { + res_path_ = "../res/"; + } + RegMetaTables(); + Load(); + } + + void MetaMgr::RegMetaTables() + { + } + + void MetaMgr::Load() + { + for (auto& itr : meta_tables) { + itr->static_pre_init_cb(); + itr->load_cb(); + } + for (size_t i = 0; i < 3; ++i) { + for (auto& itr : meta_tables) { + if (i < itr->init_cbs.size()) { + itr->init_cbs.at(i)(); + } + } + } + for (auto& itr : meta_tables) { + itr->static_post_init_cb(); + } + } + + void MetaMgr::UnInit() + { + + } + +} diff --git a/server/masterserver/mt/MetaMgr.h b/server/masterserver/mt/MetaMgr.h new file mode 100644 index 0000000..cc7c184 --- /dev/null +++ b/server/masterserver/mt/MetaMgr.h @@ -0,0 +1,162 @@ +#pragma once + +#include + +#include + +template +void SafeCallStaticPreInit(...) { }; +template +void SafeCallStaticPreInit(int) { T::StaticPreInit(); }; + +template +void SafeCallStaticPostInit(...) { }; +template +void SafeCallStaticPostInit(int) { T::StaticPostInit(); }; + +template +void SafeCallInit1(...) { }; +template +void SafeCallInit1(int) +{ + T::MutTraverse + ( + [] (T* meta, bool& stop) + { + meta->Init1(); + }); +}; + +template +void SafeCallInit2(...) { }; +template +void SafeCallInit2(int) +{ + T::MutTraverse + ( + [] (T* meta, bool& stop) + { + meta->Init2(); + }); +}; + +template +void SafeCallInit3(...) { }; +template +void SafeCallInit3(int) +{ + T::MutTraverse + ( + [] (T* meta, bool& stop) + { + meta->Init3(); + }); +}; + +namespace mt +{ + + struct MetaTable + { + std::function static_pre_init_cb; + std::function load_cb; + std::vector> init_cbs; + std::function static_post_init_cb; + }; + + class MetaMgr : public a8::Singleton + { + + private: + MetaMgr() {}; + friend class a8::Singleton; + + public: + void Init(); + void UnInit(); + + void RegMetaTables(); + void Load(); + + template + void RegMetaTable(const std::string& dir) + { + mt::MetaTable* p = new mt::MetaTable(); + p->static_pre_init_cb = + [] () + { + SafeCallStaticPreInit(0); + }; + p->load_cb = + [dir] () + { + f8::ReadJsonMetaFile(dir + T::table_name, T::raw_list); + T dummy; + a8::reflect::Class* cls = dummy.GetClass(); + a8::reflect::Field* pk_field = cls->GetFieldByName(T::prim_key); + int id = 0; + for (auto item : T::raw_list) { + switch (T::table_type) { + case 0: + { + T::id_hash[id++] = item; + } + break; + case 1: + { + long long key = cls->GetFieldValueAsInt64 + ( + pk_field, + (((char*)item)) + pk_field->offset + ); + T::id_hash[key] = item; + } + break; + case 2: + { + std::string key = cls->GetFieldValueAsString + ( + pk_field, + (((char*)item)) + pk_field->offset + ); + T::name_hash[key] = item; + } + break; + default: + { + abort(); + } + break; + } + } + }; + p->init_cbs = + { + [] () + { + SafeCallInit1(0); + }, + [] () + { + SafeCallInit2(0); + }, + [] () + { + SafeCallInit3(0); + }, + }; + p->static_post_init_cb = + [] () + { + SafeCallStaticPostInit(0); + }; + meta_tables.push_back(p); + } + + const std::string GetResDir() { return res_path_; } + private: + std::vector meta_tables; + std::string res_path_; + }; + +} diff --git a/server/masterserver/precompile.h b/server/masterserver/precompile.h new file mode 100644 index 0000000..079e622 --- /dev/null +++ b/server/masterserver/precompile.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include + +#include +#include + +#include "constant.h" +#include "mt/Forward.h" +#include "types.h" diff --git a/server/masterserver/selfchecker.cc b/server/masterserver/selfchecker.cc new file mode 100644 index 0000000..fc1d224 --- /dev/null +++ b/server/masterserver/selfchecker.cc @@ -0,0 +1,19 @@ +#include "precompile.h" + +#include + +#include "selfchecker.h" + +void SelfChecker::Init() +{ + Check(); +} + +void SelfChecker::UnInit() +{ + +} + +void SelfChecker::Check() +{ +} diff --git a/server/masterserver/selfchecker.h b/server/masterserver/selfchecker.h new file mode 100644 index 0000000..87e9048 --- /dev/null +++ b/server/masterserver/selfchecker.h @@ -0,0 +1,11 @@ +#pragma once + +class SelfChecker +{ + public: + static void Init(); + static void UnInit(); + + static void Check(); + +}; diff --git a/server/masterserver/types.h b/server/masterserver/types.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/server/masterserver/types.h @@ -0,0 +1 @@ +#pragma once