mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-08-17 08:46:22 +00:00
add PPSMonitor
This commit is contained in:
parent
72607583bf
commit
f19a012509
@ -43,7 +43,8 @@ add_executable(BeamMP-Server
|
||||
include/TResourceManager.h src/TResourceManager.cpp
|
||||
include/THeartbeatThread.h src/THeartbeatThread.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")
|
||||
|
||||
|
@ -24,11 +24,11 @@ public:
|
||||
std::string Resource;
|
||||
std::string MapName;
|
||||
std::string Key;
|
||||
int MaxPlayers;
|
||||
bool Private;
|
||||
int MaxCars;
|
||||
int MaxPlayers {};
|
||||
bool Private {};
|
||||
int MaxCars {};
|
||||
bool DebugModeEnabled;
|
||||
int Port;
|
||||
int Port {};
|
||||
std::string CustomIP;
|
||||
[[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); }
|
||||
|
||||
@ -46,22 +46,33 @@ public:
|
||||
static void GracefullyShutdown();
|
||||
static TConsole& Console() { return *mConsole; }
|
||||
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 {};
|
||||
|
||||
private:
|
||||
static inline std::string mPPS;
|
||||
static std::unique_ptr<TConsole> mConsole;
|
||||
static inline std::mutex mShutdownHandlersMutex {};
|
||||
static inline std::vector<TShutdownHandler> mShutdownHandlers {};
|
||||
};
|
||||
|
||||
#define warn(x) Application::Console().Write(std::string("[WARN] ") + (x))
|
||||
#define error(x) Application::Console().Write(std::string("[ERROR] ") + (x))
|
||||
#define info(x) Application::Console().Write(std::string("[INFO] ") + (x))
|
||||
#define luaprint(x) Application::Console().Write(std::string("[LUA] ") + (x))
|
||||
#define debug(x) \
|
||||
do { \
|
||||
if (Application::Settings.DebugModeEnabled) { \
|
||||
Application::Console().Write(std::string("[DEBUG] ") + (x)); \
|
||||
} \
|
||||
} while (false)
|
||||
static inline void warn(const std::string& str) {
|
||||
Application::Console().Write(std::string("[WARN] ") + str);
|
||||
}
|
||||
static inline void error(const std::string& str) {
|
||||
Application::Console().Write(std::string("[ERROR] ") + str);
|
||||
}
|
||||
static inline void info(const std::string& str) {
|
||||
Application::Console().Write(std::string("[INFO] ") + str);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ class IThreaded {
|
||||
public:
|
||||
IThreaded()
|
||||
// invokes operator() on this object
|
||||
: _Thread(std::thread([this] { (*this)(); })) { }
|
||||
: mThread(std::thread([this] { (*this)(); })) { }
|
||||
|
||||
virtual void operator()() = 0;
|
||||
|
||||
protected:
|
||||
std::thread _Thread;
|
||||
std::thread mThread;
|
||||
};
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <mutex>
|
||||
#include <sio_client.h>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
|
||||
/*
|
||||
* We send relevant server events over socket.io to the backend.
|
||||
@ -44,10 +45,10 @@ public:
|
||||
|
||||
~SocketIO();
|
||||
|
||||
void SetAuthenticated(bool auth) { _Authenticated = auth; }
|
||||
void SetAuthenticated(bool auth) { mAuthenticated = auth; }
|
||||
|
||||
private:
|
||||
SocketIO();
|
||||
SocketIO() noexcept;
|
||||
|
||||
void ThreadMain();
|
||||
|
||||
@ -57,12 +58,12 @@ private:
|
||||
std::string Data;
|
||||
};
|
||||
|
||||
bool _Authenticated { false };
|
||||
sio::client _Client;
|
||||
std::thread _Thread;
|
||||
std::atomic_bool _CloseThread { false };
|
||||
std::mutex _QueueMutex;
|
||||
std::deque<Event> _Queue;
|
||||
bool mAuthenticated { false };
|
||||
sio::client mClient;
|
||||
std::thread mThread;
|
||||
std::atomic_bool mCloseThread { false };
|
||||
std::mutex mQueueMutex;
|
||||
std::deque<Event> mQueue;
|
||||
|
||||
friend std::unique_ptr<SocketIO> std::make_unique<SocketIO>();
|
||||
};
|
||||
|
@ -7,6 +7,6 @@ public:
|
||||
TConfig(const std::string& ConfigFile);
|
||||
|
||||
private:
|
||||
std::string RemoveComments(const std::string& Line);
|
||||
void SetValues(const std::string& Line, int Index);
|
||||
static std::string RemoveComments(const std::string& Line);
|
||||
static void SetValues(const std::string& Line, int Index);
|
||||
};
|
||||
|
@ -1,10 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "IThreaded.h"
|
||||
#include "Common.h"
|
||||
#include "IThreaded.h"
|
||||
#include "TResourceManager.h"
|
||||
#include "TServer.h"
|
||||
|
||||
class THeartbeatThread : public IThreaded {
|
||||
public:
|
||||
THeartbeatThread();
|
||||
THeartbeatThread(TResourceManager& ResourceManager, TServer& Server);
|
||||
~THeartbeatThread();
|
||||
void operator()() override;
|
||||
|
||||
private:
|
||||
std::string GenerateCall();
|
||||
std::string GetPlayers();
|
||||
|
||||
bool mShutdown = false;
|
||||
TResourceManager& mResourceManager;
|
||||
TServer& mServer;
|
||||
};
|
@ -3,13 +3,12 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "IThreaded.h"
|
||||
#include "TLuaFile.h"
|
||||
#include "TServer.h"
|
||||
#include <lua.hpp>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
class TLuaFile;
|
||||
|
||||
class TLuaEngine : public IThreaded {
|
||||
public:
|
||||
explicit TLuaEngine(TServer& Server);
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef TLUAFILE_H
|
||||
#define TLUAFILE_H
|
||||
|
||||
#include "TLuaEngine.h"
|
||||
#include <any>
|
||||
#include <filesystem>
|
||||
#include <lua.hpp>
|
||||
@ -17,6 +16,8 @@ struct TLuaArg {
|
||||
void PushArgs(lua_State* State);
|
||||
};
|
||||
|
||||
class TLuaEngine;
|
||||
|
||||
class TLuaFile {
|
||||
public:
|
||||
void Init();
|
||||
|
18
include/TPPSMonitor.h
Normal file
18
include/TPPSMonitor.h
Normal 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 };
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
#include "Http.h"
|
||||
|
||||
#include "CustomAssert.h"
|
||||
#include "Common.h"
|
||||
#include <boost/asio/connect.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/beast.hpp>
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "SocketIO.h"
|
||||
#include "Logger.h"
|
||||
#include "Settings.h"
|
||||
#include "Common.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static std::unique_ptr<SocketIO> SocketIOInstance = std::make_unique<SocketIO>();
|
||||
|
||||
@ -8,19 +9,18 @@ SocketIO& SocketIO::Get() {
|
||||
return *SocketIOInstance;
|
||||
}
|
||||
|
||||
SocketIO::SocketIO()
|
||||
: _Thread([this] { ThreadMain(); }) {
|
||||
_Client.socket("/")->on("Hello", [&](sio::event&) {
|
||||
DebugPrintTIDInternal("Hello-handler");
|
||||
SocketIO::SocketIO() noexcept
|
||||
: mThread([this] { ThreadMain(); }) {
|
||||
mClient.socket("/")->on("Hello", [&](sio::event&) {
|
||||
info("Got 'Hello' from backend socket-io!");
|
||||
});
|
||||
_Client.connect("https://backend.beammp.com");
|
||||
_Client.set_logs_quiet();
|
||||
mClient.connect("https://backend.beammp.com");
|
||||
mClient.set_logs_quiet();
|
||||
}
|
||||
|
||||
SocketIO::~SocketIO() {
|
||||
_CloseThread.store(true);
|
||||
_Thread.join();
|
||||
mCloseThread.store(true);
|
||||
mThread.join();
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!_Authenticated) {
|
||||
if (!mAuthenticated) {
|
||||
debug("trying to emit a socket.io event when not yet authenticated");
|
||||
return;
|
||||
}
|
||||
std::string RoomName = RoomNameFromEnum(Room);
|
||||
std::string EventName = EventNameFromEnum(Event);
|
||||
debug("emitting event \"" + EventName + "\" with data: \"" + Data + "\" in room \"/key/" + RoomName + "\"");
|
||||
std::unique_lock Lock(_QueueMutex);
|
||||
_Queue.push_back({ RoomName, EventName, Data });
|
||||
debug("queue now has " + std::to_string(_Queue.size()) + " events");
|
||||
std::unique_lock Lock(mQueueMutex);
|
||||
mQueue.push_back({ RoomName, EventName, Data });
|
||||
debug("queue now has " + std::to_string(mQueue.size()) + " events");
|
||||
}
|
||||
|
||||
void SocketIO::ThreadMain() {
|
||||
bool FirstTime = true;
|
||||
while (!_CloseThread.load()) {
|
||||
if (_Authenticated && FirstTime) {
|
||||
while (!mCloseThread.load()) {
|
||||
if (mAuthenticated && FirstTime) {
|
||||
FirstTime = false;
|
||||
DebugPrintTID();
|
||||
}
|
||||
bool empty = false;
|
||||
{ // queue lock scope
|
||||
std::unique_lock Lock(_QueueMutex);
|
||||
empty = _Queue.empty();
|
||||
std::unique_lock Lock(mQueueMutex);
|
||||
empty = mQueue.empty();
|
||||
} // end queue lock scope
|
||||
if (empty) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
@ -90,20 +89,20 @@ void SocketIO::ThreadMain() {
|
||||
} else {
|
||||
Event TheEvent;
|
||||
{ // queue lock scope
|
||||
std::unique_lock Lock(_QueueMutex);
|
||||
TheEvent = _Queue.front();
|
||||
_Queue.pop_front();
|
||||
std::unique_lock Lock(mQueueMutex);
|
||||
TheEvent = mQueue.front();
|
||||
mQueue.pop_front();
|
||||
} // end queue lock scope
|
||||
debug("sending \"" + TheEvent.Name + "\" event");
|
||||
auto Room = "/" + TheEvent.Room;
|
||||
_Client.socket("/")->emit(TheEvent.Name, TheEvent.Data);
|
||||
mClient.socket("/")->emit(TheEvent.Name, TheEvent.Data);
|
||||
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;
|
||||
|
||||
_Client.sync_close();
|
||||
_Client.clear_con_listeners();
|
||||
mClient.sync_close();
|
||||
mClient.clear_con_listeners();
|
||||
std::cout << "closed" << std::endl;
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
#include "THeartbeatThread.h"
|
||||
|
||||
#include "Client.h"
|
||||
#include "Http.h"
|
||||
#include "SocketIO.h"
|
||||
|
||||
THeartbeatThread::THeartbeatThread() {
|
||||
}
|
||||
#include <sstream>
|
||||
|
||||
void THeartbeatThread::operator()() {
|
||||
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();
|
||||
bool isAuth = false;
|
||||
while (true) {
|
||||
while (!mShutdown) {
|
||||
Body = GenerateCall();
|
||||
// a hot-change occurs when a setting has changed, to update the backend of that change.
|
||||
auto Now = std::chrono::high_resolution_clock::now();
|
||||
@ -55,3 +54,43 @@ void THeartbeatThread::operator()() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "Client.h"
|
||||
#include "Common.h"
|
||||
#include "CustomAssert.h"
|
||||
#include "TLuaEngine.h"
|
||||
#include "TServer.h"
|
||||
|
||||
#include <future>
|
||||
|
35
src/TPPSMonitor.cpp
Normal file
35
src/TPPSMonitor.cpp
Normal 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));
|
||||
}
|
||||
}
|
@ -3,9 +3,11 @@
|
||||
#include "IThreaded.h"
|
||||
#include "TConfig.h"
|
||||
#include "TConsole.h"
|
||||
#include "THeartbeatThread.h"
|
||||
#include "TLuaEngine.h"
|
||||
#include "TResourceManager.h"
|
||||
#include "TServer.h"
|
||||
#include "TPPSMonitor.h"
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
@ -43,10 +45,11 @@ int main(int argc, char** argv) {
|
||||
#endif // __unix
|
||||
|
||||
TServer Server(argc, argv);
|
||||
TConfig Config("Server.cfg");
|
||||
[[maybe_unused]] TConfig Config("Server.cfg");
|
||||
TLuaEngine LuaEngine(Server);
|
||||
TResourceManager ResourceManager;
|
||||
THeartbeatThread Heartbeat;
|
||||
[[maybe_unused]] TPPSMonitor PPSMonitor(Server);
|
||||
THeartbeatThread Heartbeat(ResourceManager, Server);
|
||||
|
||||
// TODO: replace
|
||||
bool Shutdown = false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user