Fully implement TOML config file, delete .idea folder

The new config is called "ServerConfig.toml" and uses the TOML library.
It's nice.
This commit is contained in:
Lion Kortlepel 2021-06-22 00:20:12 +02:00 committed by Lion
parent f626474b4f
commit 1abf6d5adf
8 changed files with 217 additions and 103 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.idea/
*.toml
boost_*
Resources
## Ignore Visual Studio temporary files, build results, and

1
.idea/.name generated
View File

@ -1 +0,0 @@
Server

4
.idea/misc.xml generated
View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

16
.idea/vcs.xml generated
View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/asio" vcs="Git" />
<mapping directory="$PROJECT_DIR$/include/commandline" vcs="Git" />
<mapping directory="$PROJECT_DIR$/rapidjson" vcs="Git" />
<mapping directory="$PROJECT_DIR$/rapidjson/thirdparty/gtest" vcs="Git" />
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp" vcs="Git" />
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/asio" vcs="Git" />
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/catch" vcs="Git" />
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/rapidjson" vcs="Git" />
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/rapidjson/thirdparty/gtest" vcs="Git" />
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/websocketpp" vcs="Git" />
</component>
</project>

View File

@ -53,7 +53,7 @@ add_executable(BeamMP-Server
target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline")
find_package(Lua REQUIRED)
target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} "socket.io-client-cpp/src")
target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} "socket.io-client-cpp/src" "include/tomlplusplus")
find_package(OpenSSL REQUIRED)

View File

@ -2,14 +2,18 @@
#include "Common.h"
#include <atomic>
class TConfig {
public:
explicit TConfig(const std::string& ConfigFile);
explicit TConfig();
bool Failed() const { return mFailed; }
private:
static void ReadJson();
static void PrintDebug();
static void ManageJson();
static std::string RemoveComments(const std::string& Line);
static void SetValues(const std::string& Line, int Index);
void CreateConfigFile(std::string_view name);
void ParseFromFile(std::string_view name);
void PrintDebug();
bool mFailed { false };
};

View File

@ -1,16 +1,34 @@
#include <toml.hpp> // header-only version of TOML++
#include "TConfig.h"
#include <fstream>
#include "Json.h"
#include <iostream>
TConfig::TConfig(const std::string& ConfigFile) {
if(fs::exists("Config.json")){
info("New Config found updating values");
ReadJson();
return;
static const char* ConfigFileName = static_cast<const char*>("ServerConfig.toml");
static constexpr std::string_view StrDebug = "Debug";
static constexpr std::string_view StrPrivate = "Private";
static constexpr std::string_view StrPort = "Port";
static constexpr std::string_view StrMaxCars = "MaxCars";
static constexpr std::string_view StrMaxPlayers = "MaxPlayers";
static constexpr std::string_view StrMap = "Map";
static constexpr std::string_view StrName = "Name";
static constexpr std::string_view StrDescription = "Description";
static constexpr std::string_view StrResourceFolder = "ResourceFolder";
static constexpr std::string_view StrAuthKey = "AuthKey";
TConfig::TConfig() {
if (!fs::exists(ConfigFileName) || !fs::is_regular_file(ConfigFileName)) {
info("No config file found! Generating one...");
CreateConfigFile(ConfigFileName);
}
if(!fs::exists("Server.cfg")){
if (!mFailed) {
if (fs::exists("Server.cfg")) {
warn("An old \"Server.cfg\" file still exists. Please note that this is no longer used. Instead, \"" + std::string(ConfigFileName) + "\" is used. You can safely delete the \"Server.cfg\".");
}
ParseFromFile(ConfigFileName);
}
/*if (!fs::exists("Server.cfg")) {
info("Config not found generating default");
ManageJson();
error("AuthKey cannot be empty check Config.json!");
@ -48,41 +66,145 @@ TConfig::TConfig(const std::string& ConfigFile) {
FileStream.open(ConfigFile);
// TODO REPLACE THIS SHIT OMG -- replacing
FileStream << "# This is the BeamMP Server Configuration File v0.60\n"
"Debug = false # true or false to enable debug console output\n"
"Private = true # Private?\n"
"Port = 30814 # Port to run the server on UDP and TCP\n"
"Cars = 1 # Max cars for every player\n"
"MaxPlayers = 10 # Maximum Amount of Clients\n"
"Map = \"/levels/gridmap/info.json\" # Default Map\n"
"Name = \"BeamMP New Server\" # Server Name\n"
"Desc = \"BeamMP Default Description\" # Server Description\n"
"use = \"Resources\" # Resource file name\n"
"AuthKey = \"\" # Auth Key";
"Debug = false # true or false to enable debug console output\n"
"Private = true # Private?\n"
"Port = 30814 # Port to run the server on UDP and TCP\n"
"Cars = 1 # Max cars for every player\n"
"MaxPlayers = 10 # Maximum Amount of Clients\n"
"Map = \"/levels/gridmap/info.json\" # Default Map\n"
"Name = \"BeamMP New Server\" # Server Name\n"
"Desc = \"BeamMP Default Description\" # Server Description\n"
"use = \"Resources\" # Resource file name\n"
"AuthKey = \"\" # Auth Key";
FileStream.close();
error("You are required to input the AuthKey");
std::this_thread::sleep_for(std::chrono::seconds(3));
_Exit(0);
}
ManageJson();
PrintDebug();
*/
}
void TConfig::CreateConfigFile(std::string_view name) {
toml::table tbl { {
{ "General",
toml::table { {
{ StrDebug, Application::Settings.DebugModeEnabled },
{ StrPrivate, Application::Settings.Private },
{ StrPort, Application::Settings.Port },
{ StrMaxCars, Application::Settings.MaxCars },
{ StrMaxPlayers, Application::Settings.MaxPlayers },
{ StrMap, Application::Settings.MapName },
{ StrName, Application::Settings.ServerName },
{ StrDescription, Application::Settings.ServerDesc },
{ StrResourceFolder, Application::Settings.Resource },
{ StrAuthKey, Application::Settings.Key },
} } },
} };
std::ofstream ofs { std::string(name) };
if (ofs.good()) {
ofs << "# This is the BeamMP-Server config file.\n"
"# Help & Documentation: `https://wiki.beammp.com/en/home/server-maintenance`\n"
"# IMPORTANT: Fill in the AuthKey with the key you got from `https://beammp.com/k/dashboard` on the left under \"Keys\""
<< '\n';
ofs << tbl << '\n';
error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. Please open it and fill in your AuthKey and other settings, then restart the server. The old Server.cfg file will no longer be used and cause a warning if it exists from now on.");
mFailed = true;
} else {
error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work.");
mFailed = true;
}
}
void TConfig::ParseFromFile(std::string_view name) {
try {
toml::table FullTable = toml::parse_file(name);
toml::table GeneralTable = *FullTable["General"].as_table();
if (auto val = GeneralTable[StrDebug].value<bool>(); val.has_value()) {
Application::Settings.DebugModeEnabled = val.value();
} else {
throw std::runtime_error(std::string(StrDebug));
}
if (auto val = GeneralTable[StrPrivate].value<bool>(); val.has_value()) {
Application::Settings.Private = val.value();
} else {
throw std::runtime_error(std::string(StrPrivate));
}
if (auto val = GeneralTable[StrPort].value<int>(); val.has_value()) {
Application::Settings.Port = val.value();
} else {
throw std::runtime_error(std::string(StrPort));
}
if (auto val = GeneralTable[StrMaxCars].value<int>(); val.has_value()) {
Application::Settings.MaxCars = val.value();
} else {
throw std::runtime_error(std::string(StrMaxCars));
}
if (auto val = GeneralTable[StrMaxPlayers].value<int>(); val.has_value()) {
Application::Settings.MaxPlayers = val.value();
} else {
throw std::runtime_error(std::string(StrMaxPlayers));
}
if (auto val = GeneralTable[StrMap].value<std::string>(); val.has_value()) {
Application::Settings.MapName = val.value();
} else {
throw std::runtime_error(std::string(StrMap));
}
if (auto val = GeneralTable[StrName].value<std::string>(); val.has_value()) {
Application::Settings.ServerName = val.value();
} else {
throw std::runtime_error(std::string(StrName));
}
if (auto val = GeneralTable[StrDescription].value<std::string>(); val.has_value()) {
Application::Settings.ServerDesc = val.value();
} else {
throw std::runtime_error(std::string(StrDescription));
}
if (auto val = GeneralTable[StrResourceFolder].value<std::string>(); val.has_value()) {
Application::Settings.Resource = val.value();
} else {
throw std::runtime_error(std::string(StrResourceFolder));
}
if (auto val = GeneralTable[StrAuthKey].value<std::string>(); val.has_value()) {
Application::Settings.Key = val.value();
} else {
throw std::runtime_error(std::string(StrAuthKey));
}
} catch (const std::exception& err) {
error("Error parsing config file value: " + std::string(err.what()));
mFailed = true;
return;
}
PrintDebug();
// all good so far, let's check if there's a key
if (Application::Settings.Key.empty()) {
error("No AuthKey specified in the \"" + std::string(ConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server.");
mFailed = true;
}
}
/*
void TConfig::ReadJson() {
auto Size = fs::file_size("Config.json");
if(Size < 3)return;
if (Size < 3)
return;
std::ifstream ifs("Config.json");
if(ifs.is_open()) {
if (ifs.is_open()) {
std::string cfg(Size, 0);
ifs.read(&cfg[0], long(Size));
ifs.close();
if(auto pos = cfg.find('{'); pos != std::string::npos) {
if(cfg.at(0) != '{') {
if (auto pos = cfg.find('{'); pos != std::string::npos) {
if (cfg.at(0) != '{') {
cfg = cfg.substr(pos);
}
}else{
} else {
error("Config file is not valid JSON!");
std::this_thread::sleep_for(std::chrono::seconds(3));
Application::GracefullyShutdown();
@ -90,97 +212,97 @@ void TConfig::ReadJson() {
rapidjson::Document d;
d.Parse(cfg.c_str());
if(!d.HasParseError()){
if (!d.HasParseError()) {
auto& Val = d["Debug"];
if(!Val.IsNull() && Val.IsBool()) {
if (!Val.IsNull() && Val.IsBool()) {
Application::Settings.DebugModeEnabled = Val.GetBool();
}else{
} else {
info("'Debug' Missing in config! Setting to 'false' by default");
}
Val = d["Private"];
if(!Val.IsNull() && Val.IsBool()) {
if (!Val.IsNull() && Val.IsBool()) {
Application::Settings.Private = Val.GetBool();
}else{
} else {
info("'Private' Missing in config! Setting to 'true' by default");
}
Val = d["Port"];
if(!Val.IsNull() && Val.IsNumber()) {
if (!Val.IsNull() && Val.IsNumber()) {
Application::Settings.Port = Val.GetInt();
}else{
} else {
info("'Port' Missing in config! Setting to '30814' by default");
}
Val = d["MaxCars"];
if(!Val.IsNull() && Val.IsNumber()) {
if (!Val.IsNull() && Val.IsNumber()) {
Application::Settings.MaxCars = Val.GetInt();
}else{
} else {
info("'MaxCars' Missing in config! Setting to '1' by default");
}
Val = d["MaxPlayers"];
if(!Val.IsNull() && Val.IsNumber()) {
if (!Val.IsNull() && Val.IsNumber()) {
Application::Settings.MaxPlayers = Val.GetInt();
}else{
} else {
info("'MaxPlayers' Missing in config! Setting to '10' by default");
}
Val = d["Map"];
if(!Val.IsNull() && Val.IsString()) {
if (!Val.IsNull() && Val.IsString()) {
Application::Settings.MapName = Val.GetString();
}else{
} else {
info("'Map' Missing in config! Setting to '/levels/gridmap/info.json' by default");
}
Val = d["Name"];
if(!Val.IsNull() && Val.IsString()) {
if (!Val.IsNull() && Val.IsString()) {
Application::Settings.ServerName = Val.GetString();
}else{
} else {
info("'Name' Missing in config! Setting to 'BeamMP Server' by default");
}
Val = d["Desc"];
if(!Val.IsNull() && Val.IsString()) {
if (!Val.IsNull() && Val.IsString()) {
Application::Settings.ServerDesc = Val.GetString();
}else{
} else {
info("'Desc' Missing in config! Setting to 'BeamMP Default Description' by default");
}
Val = d["Resource"];
if(!Val.IsNull() && Val.IsString()) {
if (!Val.IsNull() && Val.IsString()) {
Application::Settings.Resource = Val.GetString();
}else{
} else {
info("'Resource' Missing in config! Setting to 'Resources' by default");
}
Val = d["AuthKey"];
if(!Val.IsNull() && Val.IsString()) {
if (!Val.IsNull() && Val.IsString()) {
Application::Settings.Key = Val.GetString();
if(Application::Settings.Key.empty()) {
if (Application::Settings.Key.empty()) {
error("AuthKey cannot be empty check Config.json!");
std::this_thread::sleep_for(std::chrono::seconds(3));
Application::GracefullyShutdown();
}
}else{
} else {
error("'AuthKey' Missing in config!");
std::this_thread::sleep_for(std::chrono::seconds(3));
Application::GracefullyShutdown();
}
}else{
} else {
error("Failed to parse JSON config! code " + std::to_string(d.GetParseError()));
}
}else{
} else {
error("Failed to read Config.json");
std::this_thread::sleep_for(std::chrono::seconds(3));
Application::GracefullyShutdown();
@ -191,16 +313,16 @@ void TConfig::ReadJson() {
void TConfig::ManageJson() {
rapidjson::Document d;
d.Parse("{}");
d.AddMember("Debug",Application::Settings.DebugModeEnabled,d.GetAllocator());
d.AddMember("Private",Application::Settings.Private,d.GetAllocator());
d.AddMember("Port",Application::Settings.Port,d.GetAllocator());
d.AddMember("MaxCars",Application::Settings.MaxCars,d.GetAllocator());
d.AddMember("MaxPlayers",Application::Settings.MaxPlayers,d.GetAllocator());
d.AddMember("Map", rapidjson::StringRef(Application::Settings.MapName.c_str()),d.GetAllocator());
d.AddMember("Name", rapidjson::StringRef(Application::Settings.ServerName.c_str()),d.GetAllocator());
d.AddMember("Desc", rapidjson::StringRef(Application::Settings.ServerDesc.c_str()),d.GetAllocator());
d.AddMember("Resource", rapidjson::StringRef(Application::Settings.Resource.c_str()),d.GetAllocator());
d.AddMember("AuthKey", rapidjson::StringRef(Application::Settings.Key.c_str()),d.GetAllocator());
d.AddMember("Debug", Application::Settings.DebugModeEnabled, d.GetAllocator());
d.AddMember("Private", Application::Settings.Private, d.GetAllocator());
d.AddMember("Port", Application::Settings.Port, d.GetAllocator());
d.AddMember("MaxCars", Application::Settings.MaxCars, d.GetAllocator());
d.AddMember("MaxPlayers", Application::Settings.MaxPlayers, d.GetAllocator());
d.AddMember("Map", rapidjson::StringRef(Application::Settings.MapName.c_str()), d.GetAllocator());
d.AddMember("Name", rapidjson::StringRef(Application::Settings.ServerName.c_str()), d.GetAllocator());
d.AddMember("Desc", rapidjson::StringRef(Application::Settings.ServerDesc.c_str()), d.GetAllocator());
d.AddMember("Resource", rapidjson::StringRef(Application::Settings.Resource.c_str()), d.GetAllocator());
d.AddMember("AuthKey", rapidjson::StringRef(Application::Settings.Key.c_str()), d.GetAllocator());
rapidjson::StringBuffer buffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
@ -208,11 +330,11 @@ void TConfig::ManageJson() {
std::ofstream cfg;
cfg.open("Config.json");
if(cfg.is_open()){
if (cfg.is_open()) {
cfg << "BeamMP Server Configuration File\n"
<< buffer.GetString();
cfg.close();
}else{
} else {
error("Failed to create Config.json!");
}
}
@ -283,17 +405,17 @@ void TConfig::SetValues(const std::string& Line, int Index) {
break;
}
}
void TConfig::PrintDebug(){
debug("Debug : " + std::string(Application::Settings.DebugModeEnabled ? "true" : "false"));
debug("Private : " + std::string(Application::Settings.Private ? "true" : "false"));
debug("Port : " + std::to_string(Application::Settings.Port));
debug("Max Cars : " + std::to_string(Application::Settings.MaxCars));
debug("MaxPlayers : " + std::to_string(Application::Settings.MaxPlayers));
debug("MapName : \"" + Application::Settings.MapName + "\"");
debug("ServerName : \"" + Application::Settings.ServerName + "\"");
debug("ServerDesc : \"" + Application::Settings.ServerDesc + "\"");
debug("File : \"" + Application::Settings.Resource + "\"");
debug("Key length : " + std::to_string(Application::Settings.Key.length()) + "");
*/
void TConfig::PrintDebug() {
debug(std::string(StrDebug) + ": " + std::string(Application::Settings.DebugModeEnabled ? "true" : "false"));
debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.Private ? "true" : "false"));
debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.Port));
debug(std::string(StrMaxCars) + ": " + std::to_string(Application::Settings.MaxCars));
debug(std::string(StrMaxPlayers) + ": " + std::to_string(Application::Settings.MaxPlayers));
debug(std::string(StrMap) + ": \"" + Application::Settings.MapName + "\"");
debug(std::string(StrName) + ": \"" + Application::Settings.ServerName + "\"");
debug(std::string(StrDescription) + ": \"" + Application::Settings.ServerDesc + "\"");
debug(std::string(StrResourceFolder) + ": \"" + Application::Settings.Resource + "\"");
// special!
debug("Key Length: " + std::to_string(Application::Settings.Key.length()) + "");
}

View File

@ -50,7 +50,14 @@ int main(int argc, char** argv) {
Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; });
TServer Server(argc, argv);
[[maybe_unused]] TConfig Config("Server.cfg");
[[maybe_unused]] TConfig Config;
if (Config.Failed()) {
info("Closing in 10 seconds");
std::this_thread::sleep_for(std::chrono::seconds(10));
return 1;
}
RegisterThread("Main");
TResourceManager ResourceManager;
TPPSMonitor PPSMonitor(Server);