add PPSMonitor

This commit is contained in:
Lion Kortlepel 2021-02-16 13:19:39 +01:00 committed by Anonymous275
parent 72607583bf
commit f19a012509
15 changed files with 185 additions and 66 deletions

View File

@ -16,7 +16,7 @@ if (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -static-libstdc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -static-libstdc++")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -g") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -g")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -s -fno-builtin") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -s -fno-builtin")
if (SANITIZE) if (SANITIZE)
message(STATUS "sanitize is ON") message(STATUS "sanitize is ON")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,thread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,thread")
endif (SANITIZE) endif (SANITIZE)
@ -43,7 +43,8 @@ add_executable(BeamMP-Server
include/TResourceManager.h src/TResourceManager.cpp include/TResourceManager.h src/TResourceManager.cpp
include/THeartbeatThread.h src/THeartbeatThread.cpp include/THeartbeatThread.h src/THeartbeatThread.cpp
include/Http.h src/Http.cpp include/Http.h src/Http.cpp
include/SocketIO.h src/SocketIO.cpp) include/SocketIO.h src/SocketIO.cpp
include/TPPSMonitor.h src/TPPSMonitor.cpp)
target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline") target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline")

View File

@ -24,11 +24,11 @@ public:
std::string Resource; std::string Resource;
std::string MapName; std::string MapName;
std::string Key; std::string Key;
int MaxPlayers; int MaxPlayers {};
bool Private; bool Private {};
int MaxCars; int MaxCars {};
bool DebugModeEnabled; bool DebugModeEnabled;
int Port; int Port {};
std::string CustomIP; std::string CustomIP;
[[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); } [[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); }
@ -46,22 +46,33 @@ public:
static void GracefullyShutdown(); static void GracefullyShutdown();
static TConsole& Console() { return *mConsole; } static TConsole& Console() { return *mConsole; }
static std::string ServerVersion() { return "v1.20"; } static std::string ServerVersion() { return "v1.20"; }
static std::string ClientVersion() { return "v1.80"; }
static std::string PPS() { return mPPS; }
static void SetPPS(std::string NewPPS) { mPPS = NewPPS; }
static inline TSettings Settings {}; static inline TSettings Settings {};
private: private:
static inline std::string mPPS;
static std::unique_ptr<TConsole> mConsole; static std::unique_ptr<TConsole> mConsole;
static inline std::mutex mShutdownHandlersMutex {}; static inline std::mutex mShutdownHandlersMutex {};
static inline std::vector<TShutdownHandler> mShutdownHandlers {}; static inline std::vector<TShutdownHandler> mShutdownHandlers {};
}; };
#define warn(x) Application::Console().Write(std::string("[WARN] ") + (x)) static inline void warn(const std::string& str) {
#define error(x) Application::Console().Write(std::string("[ERROR] ") + (x)) Application::Console().Write(std::string("[WARN] ") + str);
#define info(x) Application::Console().Write(std::string("[INFO] ") + (x)) }
#define luaprint(x) Application::Console().Write(std::string("[LUA] ") + (x)) static inline void error(const std::string& str) {
#define debug(x) \ Application::Console().Write(std::string("[ERROR] ") + str);
do { \ }
if (Application::Settings.DebugModeEnabled) { \ static inline void info(const std::string& str) {
Application::Console().Write(std::string("[DEBUG] ") + (x)); \ Application::Console().Write(std::string("[INFO] ") + str);
} \ }
} while (false) static inline void debug(const std::string& str) {
if (Application::Settings.DebugModeEnabled) {
Application::Console().Write(std::string("[DEBUG] ") + str);
}
}
static inline void luaprint(const std::string& str) {
Application::Console().Write(std::string("[LUA] ") + str);
}

View File

@ -7,10 +7,10 @@ class IThreaded {
public: public:
IThreaded() IThreaded()
// invokes operator() on this object // invokes operator() on this object
: _Thread(std::thread([this] { (*this)(); })) { } : mThread(std::thread([this] { (*this)(); })) { }
virtual void operator()() = 0; virtual void operator()() = 0;
protected: protected:
std::thread _Thread; std::thread mThread;
}; };

View File

@ -5,6 +5,7 @@
#include <mutex> #include <mutex>
#include <sio_client.h> #include <sio_client.h>
#include <thread> #include <thread>
#include <memory>
/* /*
* We send relevant server events over socket.io to the backend. * We send relevant server events over socket.io to the backend.
@ -44,10 +45,10 @@ public:
~SocketIO(); ~SocketIO();
void SetAuthenticated(bool auth) { _Authenticated = auth; } void SetAuthenticated(bool auth) { mAuthenticated = auth; }
private: private:
SocketIO(); SocketIO() noexcept;
void ThreadMain(); void ThreadMain();
@ -57,12 +58,12 @@ private:
std::string Data; std::string Data;
}; };
bool _Authenticated { false }; bool mAuthenticated { false };
sio::client _Client; sio::client mClient;
std::thread _Thread; std::thread mThread;
std::atomic_bool _CloseThread { false }; std::atomic_bool mCloseThread { false };
std::mutex _QueueMutex; std::mutex mQueueMutex;
std::deque<Event> _Queue; std::deque<Event> mQueue;
friend std::unique_ptr<SocketIO> std::make_unique<SocketIO>(); friend std::unique_ptr<SocketIO> std::make_unique<SocketIO>();
}; };

View File

@ -7,6 +7,6 @@ public:
TConfig(const std::string& ConfigFile); TConfig(const std::string& ConfigFile);
private: private:
std::string RemoveComments(const std::string& Line); static std::string RemoveComments(const std::string& Line);
void SetValues(const std::string& Line, int Index); static void SetValues(const std::string& Line, int Index);
}; };

View File

@ -1,10 +1,21 @@
#pragma once #pragma once
#include "IThreaded.h"
#include "Common.h" #include "Common.h"
#include "IThreaded.h"
#include "TResourceManager.h"
#include "TServer.h"
class THeartbeatThread : public IThreaded { class THeartbeatThread : public IThreaded {
public: public:
THeartbeatThread(); THeartbeatThread(TResourceManager& ResourceManager, TServer& Server);
~THeartbeatThread();
void operator()() override; void operator()() override;
private:
std::string GenerateCall();
std::string GetPlayers();
bool mShutdown = false;
TResourceManager& mResourceManager;
TServer& mServer;
}; };

View File

@ -3,13 +3,12 @@
#include "Common.h" #include "Common.h"
#include "IThreaded.h" #include "IThreaded.h"
#include "TLuaFile.h"
#include "TServer.h" #include "TServer.h"
#include <lua.hpp> #include <lua.hpp>
#include <memory> #include <memory>
#include <set> #include <set>
class TLuaFile;
class TLuaEngine : public IThreaded { class TLuaEngine : public IThreaded {
public: public:
explicit TLuaEngine(TServer& Server); explicit TLuaEngine(TServer& Server);

View File

@ -1,7 +1,6 @@
#ifndef TLUAFILE_H #ifndef TLUAFILE_H
#define TLUAFILE_H #define TLUAFILE_H
#include "TLuaEngine.h"
#include <any> #include <any>
#include <filesystem> #include <filesystem>
#include <lua.hpp> #include <lua.hpp>
@ -17,6 +16,8 @@ struct TLuaArg {
void PushArgs(lua_State* State); void PushArgs(lua_State* State);
}; };
class TLuaEngine;
class TLuaFile { class TLuaFile {
public: public:
void Init(); void Init();

18
include/TPPSMonitor.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "Common.h"
#include "IThreaded.h"
#include "TServer.h"
class TPPSMonitor : public IThreaded {
public:
TPPSMonitor(TServer& Server);
void operator()() override;
private:
TServer& mServer;
bool mShutdown { false };
int mInternalPPS { 0 };
};

View File

@ -1,6 +1,6 @@
#include "Http.h" #include "Http.h"
#include "CustomAssert.h" #include "Common.h"
#include <boost/asio/connect.hpp> #include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/beast.hpp> #include <boost/beast.hpp>

View File

@ -1,6 +1,7 @@
#include "SocketIO.h" #include "SocketIO.h"
#include "Logger.h" #include "Common.h"
#include "Settings.h"
#include <iostream>
static std::unique_ptr<SocketIO> SocketIOInstance = std::make_unique<SocketIO>(); static std::unique_ptr<SocketIO> SocketIOInstance = std::make_unique<SocketIO>();
@ -8,19 +9,18 @@ SocketIO& SocketIO::Get() {
return *SocketIOInstance; return *SocketIOInstance;
} }
SocketIO::SocketIO() SocketIO::SocketIO() noexcept
: _Thread([this] { ThreadMain(); }) { : mThread([this] { ThreadMain(); }) {
_Client.socket("/")->on("Hello", [&](sio::event&) { mClient.socket("/")->on("Hello", [&](sio::event&) {
DebugPrintTIDInternal("Hello-handler");
info("Got 'Hello' from backend socket-io!"); info("Got 'Hello' from backend socket-io!");
}); });
_Client.connect("https://backend.beammp.com"); mClient.connect("https://backend.beammp.com");
_Client.set_logs_quiet(); mClient.set_logs_quiet();
} }
SocketIO::~SocketIO() { SocketIO::~SocketIO() {
_CloseThread.store(true); mCloseThread.store(true);
_Thread.join(); mThread.join();
} }
static constexpr auto RoomNameFromEnum(SocketIORoom Room) { static constexpr auto RoomNameFromEnum(SocketIORoom Room) {
@ -60,29 +60,28 @@ static constexpr auto EventNameFromEnum(SocketIOEvent Event) {
} }
void SocketIO::Emit(SocketIORoom Room, SocketIOEvent Event, const std::string& Data) { void SocketIO::Emit(SocketIORoom Room, SocketIOEvent Event, const std::string& Data) {
if (!_Authenticated) { if (!mAuthenticated) {
debug("trying to emit a socket.io event when not yet authenticated"); debug("trying to emit a socket.io event when not yet authenticated");
return; return;
} }
std::string RoomName = RoomNameFromEnum(Room); std::string RoomName = RoomNameFromEnum(Room);
std::string EventName = EventNameFromEnum(Event); std::string EventName = EventNameFromEnum(Event);
debug("emitting event \"" + EventName + "\" with data: \"" + Data + "\" in room \"/key/" + RoomName + "\""); debug("emitting event \"" + EventName + "\" with data: \"" + Data + "\" in room \"/key/" + RoomName + "\"");
std::unique_lock Lock(_QueueMutex); std::unique_lock Lock(mQueueMutex);
_Queue.push_back({ RoomName, EventName, Data }); mQueue.push_back({ RoomName, EventName, Data });
debug("queue now has " + std::to_string(_Queue.size()) + " events"); debug("queue now has " + std::to_string(mQueue.size()) + " events");
} }
void SocketIO::ThreadMain() { void SocketIO::ThreadMain() {
bool FirstTime = true; bool FirstTime = true;
while (!_CloseThread.load()) { while (!mCloseThread.load()) {
if (_Authenticated && FirstTime) { if (mAuthenticated && FirstTime) {
FirstTime = false; FirstTime = false;
DebugPrintTID();
} }
bool empty = false; bool empty = false;
{ // queue lock scope { // queue lock scope
std::unique_lock Lock(_QueueMutex); std::unique_lock Lock(mQueueMutex);
empty = _Queue.empty(); empty = mQueue.empty();
} // end queue lock scope } // end queue lock scope
if (empty) { if (empty) {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
@ -90,20 +89,20 @@ void SocketIO::ThreadMain() {
} else { } else {
Event TheEvent; Event TheEvent;
{ // queue lock scope { // queue lock scope
std::unique_lock Lock(_QueueMutex); std::unique_lock Lock(mQueueMutex);
TheEvent = _Queue.front(); TheEvent = mQueue.front();
_Queue.pop_front(); mQueue.pop_front();
} // end queue lock scope } // end queue lock scope
debug("sending \"" + TheEvent.Name + "\" event"); debug("sending \"" + TheEvent.Name + "\" event");
auto Room = "/" + TheEvent.Room; auto Room = "/" + TheEvent.Room;
_Client.socket("/")->emit(TheEvent.Name, TheEvent.Data); mClient.socket("/")->emit(TheEvent.Name, TheEvent.Data);
debug("sent \"" + TheEvent.Name + "\" event"); debug("sent \"" + TheEvent.Name + "\" event");
} }
} }
// using std::cout as this happens during static destruction and the logger might be dead already
std::cout << "closing " + std::string(__func__) << std::endl; std::cout << "closing " + std::string(__func__) << std::endl;
_Client.sync_close(); mClient.sync_close();
_Client.clear_con_listeners(); mClient.clear_con_listeners();
std::cout << "closed" << std::endl; std::cout << "closed" << std::endl;
} }

View File

@ -1,10 +1,9 @@
#include "THeartbeatThread.h" #include "THeartbeatThread.h"
#include "Client.h"
#include "Http.h" #include "Http.h"
#include "SocketIO.h" #include "SocketIO.h"
#include <sstream>
THeartbeatThread::THeartbeatThread() {
}
void THeartbeatThread::operator()() { void THeartbeatThread::operator()() {
std::string Body; std::string Body;
@ -15,7 +14,7 @@ void THeartbeatThread::operator()() {
static std::chrono::high_resolution_clock::time_point LastNormalUpdateTime = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point LastNormalUpdateTime = std::chrono::high_resolution_clock::now();
bool isAuth = false; bool isAuth = false;
while (true) { while (!mShutdown) {
Body = GenerateCall(); Body = GenerateCall();
// a hot-change occurs when a setting has changed, to update the backend of that change. // a hot-change occurs when a setting has changed, to update the backend of that change.
auto Now = std::chrono::high_resolution_clock::now(); auto Now = std::chrono::high_resolution_clock::now();
@ -55,3 +54,43 @@ void THeartbeatThread::operator()() {
SocketIO::Get().SetAuthenticated(isAuth); SocketIO::Get().SetAuthenticated(isAuth);
} }
} }
std::string THeartbeatThread::GenerateCall() {
std::stringstream Ret;
Ret << "uuid=" << Application::Settings.Key
<< "&players=" << mServer.ClientCount()
<< "&maxplayers=" << Application::Settings.MaxPlayers
<< "&port=" << Application::Settings.Port
<< "&map=" << Application::Settings.MapName
<< "&private=" << (Application::Settings.Private ? "true" : "false")
<< "&version=" << Application::ServerVersion()
<< "&clientversion=" << Application::ClientVersion()
<< "&name=" << Application::Settings.ServerName
<< "&pps=" << Application::PPS()
<< "&modlist=" << mResourceManager.FileList()
<< "&modstotalsize=" << mResourceManager.MaxModSize()
<< "&modstotal=" << mResourceManager.ModsLoaded()
<< "&playerslist=" << GetPlayers()
<< "&desc=" << Application::Settings.ServerDesc;
return Ret.str();
}
THeartbeatThread::THeartbeatThread(TResourceManager& ResourceManager, TServer& Server)
: mResourceManager(ResourceManager)
, mServer(Server) {
Application::RegisterShutdownHandler([&] { mShutdown = true; });
}
std::string THeartbeatThread::GetPlayers() {
std::string Return;
mServer.ForEachClient([&](std::weak_ptr<TClient> ClientPtr) -> bool {
if (!ClientPtr.expired()) {
Return += ClientPtr.lock()->GetName() + ";";
}
return true;
});
return Return;
}
THeartbeatThread::~THeartbeatThread() {
if (mThread.joinable()) {
mThread.join();
}
}

View File

@ -2,6 +2,7 @@
#include "Client.h" #include "Client.h"
#include "Common.h" #include "Common.h"
#include "CustomAssert.h" #include "CustomAssert.h"
#include "TLuaEngine.h"
#include "TServer.h" #include "TServer.h"
#include <future> #include <future>

35
src/TPPSMonitor.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "TPPSMonitor.h"
#include "Client.h"
TPPSMonitor::TPPSMonitor(TServer& Server)
: mServer(Server) {
Application::SetPPS("-");
Application::RegisterShutdownHandler([&] { mShutdown = true; });
}
void TPPSMonitor::operator()() {
while (!mShutdown) {
int C = 0, V = 0;
if (mServer.ClientCount() == 0) {
Application::SetPPS("-");
return;
}
mServer.ForEachClient([&](std::weak_ptr<TClient> ClientPtr) -> bool {
if (!ClientPtr.expired()) {
auto c = ClientPtr.lock();
if (c->GetCarCount() > 0) {
C++;
V += c->GetCarCount();
}
}
return true;
});
if (C == 0 || mInternalPPS == 0) {
Application::SetPPS("-");
} else {
int R = (mInternalPPS / C) / V;
Application::SetPPS(std::to_string(R));
}
mInternalPPS = 0;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}

View File

@ -3,9 +3,11 @@
#include "IThreaded.h" #include "IThreaded.h"
#include "TConfig.h" #include "TConfig.h"
#include "TConsole.h" #include "TConsole.h"
#include "THeartbeatThread.h"
#include "TLuaEngine.h" #include "TLuaEngine.h"
#include "TResourceManager.h" #include "TResourceManager.h"
#include "TServer.h" #include "TServer.h"
#include "TPPSMonitor.h"
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
@ -43,10 +45,11 @@ int main(int argc, char** argv) {
#endif // __unix #endif // __unix
TServer Server(argc, argv); TServer Server(argc, argv);
TConfig Config("Server.cfg"); [[maybe_unused]] TConfig Config("Server.cfg");
TLuaEngine LuaEngine(Server); TLuaEngine LuaEngine(Server);
TResourceManager ResourceManager; TResourceManager ResourceManager;
THeartbeatThread Heartbeat; [[maybe_unused]] TPPSMonitor PPSMonitor(Server);
THeartbeatThread Heartbeat(ResourceManager, Server);
// TODO: replace // TODO: replace
bool Shutdown = false; bool Shutdown = false;