mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-01 23:35:41 +00:00
* Add preliminary work for HTTP health endpoint * Http: Fix infinite loop bug in Tx509KeypairGenerator::generateKey() * update commandline * Add TLS Support class for use with http server * Add preliminary HTTP Server; TLS still broken; fix in later commit * Fix TLS handshake, due to server being unable to serve key/certfile in 'Http.h/Http.cpp'; Cause was httlib not being threadsafe due to being a blocking http library * Run clang format * Add option to configure http server port via ServerConfig * TConfig: add HTTPServerPort to config parsing step * Fix SSL Cert / Key path not auto generating when not existing * Add health endpoint; Fix SSL Cert serial no. not refreshing when regenerating * Switch arround status codes in /health route * Run clang format Co-authored-by: Lion Kortlepel <development@kortlepel.com>
132 lines
5.3 KiB
C++
132 lines
5.3 KiB
C++
#include "THeartbeatThread.h"
|
|
|
|
#include "Client.h"
|
|
#include "Http.h"
|
|
//#include "SocketIO.h"
|
|
#include <sstream>
|
|
|
|
void THeartbeatThread::operator()() {
|
|
return;/*
|
|
RegisterThread("Heartbeat");
|
|
std::string Body;
|
|
std::string T;
|
|
|
|
// these are "hot-change" related variables
|
|
static std::string Last;
|
|
|
|
static std::chrono::high_resolution_clock::time_point LastNormalUpdateTime = std::chrono::high_resolution_clock::now();
|
|
bool isAuth = false;
|
|
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();
|
|
bool Unchanged = Last == Body;
|
|
auto TimePassed = (Now - LastNormalUpdateTime);
|
|
auto Threshold = Unchanged ? 30 : 5;
|
|
if (TimePassed < std::chrono::seconds(Threshold)) {
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
continue;
|
|
}
|
|
beammp_debug("heartbeat (after " + std::to_string(std::chrono::duration_cast<std::chrono::seconds>(TimePassed).count()) + "s)");
|
|
|
|
Last = Body;
|
|
LastNormalUpdateTime = Now;
|
|
if (!Application::Settings.CustomIP.empty()) {
|
|
Body += "&ip=" + Application::Settings.CustomIP;
|
|
}
|
|
|
|
Body += "&pps=" + Application::PPS();
|
|
|
|
beammp_trace("heartbeat body: '" + Body + "'");
|
|
|
|
auto SentryReportError = [&](const std::string& transaction, int status) {
|
|
auto Lock = Sentry.CreateExclusiveContext();
|
|
Sentry.SetContext("heartbeat",
|
|
{ { "response-body", T },
|
|
{ "request-body", Body } });
|
|
Sentry.SetTransaction(transaction);
|
|
beammp_trace("sending log to sentry: " + std::to_string(status) + " for " + transaction);
|
|
Sentry.Log(SentryLevel::Error, "default", Http::Status::ToString(status) + " (" + std::to_string(status) + ")");
|
|
};
|
|
|
|
auto Target = "/heartbeat";
|
|
unsigned int ResponseCode = 0;
|
|
T = Http::POST(Application::GetBackendHostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
|
|
|
|
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
|
|
beammp_trace("got " + T + " from backend");
|
|
SentryReportError(Application::GetBackendHostname() + Target, ResponseCode);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
T = Http::POST(Application::GetBackup1Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
|
|
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
|
|
SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
T = Http::POST(Application::GetBackup2Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
|
|
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
|
|
beammp_warn("Backend system refused server! Server will not show in the public server list.");
|
|
|
|
isAuth = false;
|
|
SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isAuth) {
|
|
if (T == "2000") {
|
|
beammp_info(("Authenticated!"));
|
|
isAuth = true;
|
|
} else if (T == "200") {
|
|
beammp_info(("Resumed authenticated session!"));
|
|
isAuth = true;
|
|
}
|
|
}
|
|
|
|
//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::ServerVersionString()
|
|
<< "&clientversion=" << Application::ClientVersionString()
|
|
<< "&name=" << Application::Settings.ServerName
|
|
<< "&modlist=" << mResourceManager.TrimmedList()
|
|
<< "&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([&] {
|
|
if (mThread.joinable()) {
|
|
mShutdown = true;
|
|
mThread.join();
|
|
}
|
|
});
|
|
Start();
|
|
}
|
|
std::string THeartbeatThread::GetPlayers() {
|
|
std::string Return;
|
|
mServer.ForEachClient([&](const std::weak_ptr<TClient>& ClientPtr) -> bool {
|
|
ReadLock Lock(mServer.GetClientMutex());
|
|
if (!ClientPtr.expired()) {
|
|
Return += ClientPtr.lock()->GetName() + ";";
|
|
}
|
|
return true;
|
|
});
|
|
return Return;
|
|
}
|
|
/*THeartbeatThread::~THeartbeatThread() {
|
|
}*/
|