From 84f5f95e54fb99f5ed92c0afdd2956327deff532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucca=20Jim=C3=A9nez=20K=C3=B6nings?= Date: Tue, 21 May 2024 13:38:37 +0200 Subject: [PATCH] Refactor: feedback from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lucca Jiménez Könings --- CMakeLists.txt | 2 + include/Common.h | 29 +--- include/Settings.h | 187 +++++++++++++++++++++++++ include/TConfig.h | 5 +- include/TSettings.h | 332 -------------------------------------------- src/LuaAPI.cpp | 2 +- src/Settings.cpp | 132 ++++++++++++++++++ src/TConfig.cpp | 2 +- src/TConsole.cpp | 6 +- src/main.cpp | 2 +- 10 files changed, 330 insertions(+), 369 deletions(-) create mode 100644 include/Settings.h delete mode 100644 include/TSettings.h create mode 100644 src/Settings.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f4e273..0527453 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ set(PRJ_HEADERS include/TServer.h include/VehicleData.h include/Env.h + include/Settings.h ) # add all source files (.cpp) to this, except the one with main() set(PRJ_SOURCES @@ -72,6 +73,7 @@ set(PRJ_SOURCES src/TServer.cpp src/VehicleData.cpp src/Env.cpp + src/Settings.cpp ) find_package(Lua REQUIRED) diff --git a/include/Common.h b/include/Common.h index 56565e3..259cb1d 100644 --- a/include/Common.h +++ b/include/Common.h @@ -37,7 +37,7 @@ namespace fs = std::filesystem; #include "TConsole.h" -#include "TSettings.h" +#include "Settings.h" struct Version { uint8_t major; @@ -59,32 +59,7 @@ using SparseArray = std::unordered_map; class Application final { public: // types - struct TSettings { - std::string ServerName { "BeamMP Server" }; - std::string ServerDesc { "BeamMP Default Description" }; - std::string ServerTags { "Freeroam" }; - std::string Resource { "Resources" }; - std::string MapName { "/levels/gridmap_v2/info.json" }; - std::string Key {}; - std::string Password {}; - std::string SSLKeyPath { "./.ssl/HttpServer/key.pem" }; - std::string SSLCertPath { "./.ssl/HttpServer/cert.pem" }; - bool HTTPServerEnabled { false }; - int MaxPlayers { 8 }; - bool Private { true }; - int MaxCars { 1 }; - bool DebugModeEnabled { false }; - int Port { 30814 }; - std::string CustomIP {}; - bool LogChat { true }; - bool SendErrors { true }; - bool SendErrorsMessageEnabled { true }; - int HTTPServerPort { 8080 }; - std::string HTTPServerIP { "127.0.0.1" }; - bool HTTPServerUseSSL { false }; - bool HideUpdateMessages { false }; - [[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); } - }; + using TShutdownHandler = std::function; diff --git a/include/Settings.h b/include/Settings.h new file mode 100644 index 0000000..2f9565c --- /dev/null +++ b/include/Settings.h @@ -0,0 +1,187 @@ +// BeamMP, the BeamNG.drive multiplayer mod. +// Copyright (C) 2024 BeamMP Ltd., BeamMP team and contributors. +// +// BeamMP Ltd. can be contacted by electronic mail via contact@beammp.com. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#pragma once +#include "Sync.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ComposedKey { + std::string Category; + std::string Key; + + bool operator==(const ComposedKey& rhs) const { + return (this->Category == rhs.Category && this->Key == rhs.Key); + } +}; + +template <> +struct fmt::formatter : formatter { + auto format(ComposedKey key, format_context& ctx) const; +}; + +inline auto fmt::formatter::format(ComposedKey key, fmt::format_context& ctx) const { + std::string key_metadata = fmt::format("{}::{}", key.Category, key.Key); + return formatter::format(key_metadata, ctx); +} + +namespace std { +template <> +class hash { +public: + std::uint64_t operator()(const ComposedKey& key) const { + std::hash hash_fn; + return hash_fn(key.Category + key.Key); + } +}; +} + +struct Settings { + using SettingsTypeVariant = std::variant; + + enum Key { + // Keys that correspond to the keys set in TOML + // Keys have their TOML section name as prefix + + // [Misc] + Misc_SendErrorsShowMessage, + Misc_SendErrors, + Misc_ImScaredOfUpdates, + + // [General] + General_Description, + General_Tags, + General_MaxPlayers, + General_Name, + General_Map, + General_AuthKey, + General_Private, + General_Port, + General_MaxCars, + General_LogChat, + General_ResourceFolder, + General_Debug + }; + + Sync> SettingsMap = std::unordered_map { + { General_Description, "BeamMP Default Description" }, + { General_Tags, "Freeroam" }, + { General_MaxPlayers, 8 }, + { General_Name, "BeamMP Server" }, + { General_Map, "/levels/gridmap_v2/info.json" }, + { General_AuthKey, "" }, + { General_Private, true }, + { General_Port, 30814 }, + { General_MaxCars, 1 }, + { General_LogChat, true }, + { General_ResourceFolder, "Resources" }, + { General_Debug, false }, + { Misc_SendErrorsShowMessage, true }, + { Misc_SendErrors, true }, + { Misc_ImScaredOfUpdates, true } + }; + + enum SettingsAccessMask { + READ_ONLY, // Value can be read from console + READ_WRITE, // Value can be read and written to from console + NO_ACCESS // Value is inaccessible from console (no read OR write) + }; + + using SettingsAccessControl = std::pair< + Key, // The Key's corresponding enum encoding + SettingsAccessMask // Console read/write permissions + >; + + Sync> InputAccessMapping = std::unordered_map { + { { "General", "Description" }, { General_Description, READ_WRITE } }, + { { "General", "Tags" }, { General_Tags, READ_WRITE } }, + { { "General", "MaxPlayers" }, { General_MaxPlayers, READ_WRITE } }, + { { "General", "Name" }, { General_Name, READ_WRITE } }, + { { "General", "Map" }, { General_Map, READ_WRITE } }, + { { "General", "AuthKey" }, { General_AuthKey, READ_WRITE } }, + { { "General", "Private" }, { General_Private, READ_ONLY } }, + { { "General", "Port" }, { General_Port, READ_ONLY } }, + { { "General", "MaxCars" }, { General_MaxCars, READ_WRITE } }, + { { "General", "LogChat" }, { General_LogChat, READ_ONLY } }, + { { "General", "ResourceFolder" }, { General_ResourceFolder, READ_ONLY } }, + { { "General", "Debug" }, { General_Debug, READ_WRITE } }, + { { "Misc", "SendErrorsShowMessage" }, { Misc_SendErrorsShowMessage, READ_WRITE } }, + { { "Misc", "SendErrors" }, { Misc_SendErrors, READ_WRITE } }, + { { "Misc", "ImScaredOfUpdates" }, { Misc_ImScaredOfUpdates, READ_WRITE } } + }; + + std::string getAsString(Key key); + + int getAsInt(Key key); + + bool getAsBool(Key key); + + SettingsTypeVariant get(Key key); + + void set(Key key, const std::string& value); + + template , bool> = true> + void set(Key key, Integer value) { + auto map = SettingsMap.synchronize(); + if (!map->contains(key)) { + throw std::logic_error { "Undefined setting key accessed in Settings::set(int)" }; + } + if (!std::holds_alternative(map->at(key))) { + throw std::logic_error { fmt::format("Wrong value type in Settings::set(int): index {}", map->at(key).index()) }; + } + map->at(key) = value; + } + template , bool> = true> + void set(Key key, Boolean value) { + auto map = SettingsMap.synchronize(); + if (!map->contains(key)) { + throw std::logic_error { "Undefined setting key accessed in Settings::set(bool)" }; + } + if (!std::holds_alternative(map->at(key))) { + throw std::logic_error { fmt::format("Wrong value type in Settings::set(bool): index {}", map->at(key).index()) }; + } + map->at(key) = value; + } + + const std::unordered_map getAccessControlMap() const; + SettingsAccessControl getConsoleInputAccessMapping(const ComposedKey& keyName); + + void setConsoleInputAccessMapping(const ComposedKey& keyName, const std::string& value); + void setConsoleInputAccessMapping(const ComposedKey& keyName, int value); + void setConsoleInputAccessMapping(const ComposedKey& keyName, bool value); +}; + +TEST_CASE("settings variant functions") { + Settings settings; + settings.set(Settings::General_Name, "hello, world"); + CHECK_EQ(settings.getAsString(Settings::General_Name), "hello, world"); + settings.set(Settings::General_Name, std::string("hello, world")); + CHECK_EQ(settings.getAsString(Settings::General_Name), "hello, world"); + settings.set(Settings::General_MaxPlayers, 12); + CHECK_EQ(settings.getAsInt(Settings::General_MaxPlayers), 12); + + CHECK_THROWS(settings.set(Settings::General_Debug, "hello, world")); + CHECK_NOTHROW(settings.set(Settings::General_Debug, false)); +} diff --git a/include/TConfig.h b/include/TConfig.h index f84a5bc..c510fb5 100644 --- a/include/TConfig.h +++ b/include/TConfig.h @@ -19,7 +19,7 @@ #pragma once #include "Common.h" -#include "TSettings.h" +#include "Settings.h" #include #include @@ -41,9 +41,6 @@ public: private: void CreateConfigFile(); void ParseFromFile(std::string_view name); - void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, std::string& OutValue); - void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, bool& OutValue); - void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, int& OutValue); void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, Settings::Key key); void ParseOldFormat(); diff --git a/include/TSettings.h b/include/TSettings.h deleted file mode 100644 index b9c74c4..0000000 --- a/include/TSettings.h +++ /dev/null @@ -1,332 +0,0 @@ -// BeamMP, the BeamNG.drive multiplayer mod. -// Copyright (C) 2024 BeamMP Ltd., BeamMP team and contributors. -// -// BeamMP Ltd. can be contacted by electronic mail via contact@beammp.com. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#pragma once -#include "Sync.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct ComposedKey { - std::string Category; - std::string Key; - - bool operator==(const ComposedKey& rhs) const { - return (this->Category == rhs.Category && this->Key == rhs.Key); - } -}; - -template <> -struct fmt::formatter : formatter { - auto format(ComposedKey key, format_context& ctx) const; -}; - -inline auto fmt::formatter::format(ComposedKey key, fmt::format_context& ctx) const { - std::string key_metadata = fmt::format("{}::{}", key.Category, key.Key); - return formatter::format(key_metadata, ctx); -} - -namespace std { -template <> -class hash { -public: - std::uint64_t operator()(const ComposedKey& key) const { - std::hash hash_fn; - return hash_fn(key.Category + key.Key); - } -}; -} - -struct Settings { - using SettingsTypeVariant = std::variant; - - enum Key { - // Keys that correspond to the keys set in TOML - // Keys have their TOML section name as prefix - - // [Misc] - Misc_SendErrorsShowMessage, - Misc_SendErrors, - Misc_ImScaredOfUpdates, - - // [General] - General_Description, - General_Tags, - General_MaxPlayers, - General_Name, - General_Map, - General_AuthKey, - General_Private, - General_Port, - General_MaxCars, - General_LogChat, - General_ResourceFolder, - General_Debug - }; - - Sync> SettingsMap = std::unordered_map { - { General_Description, "BeamMP Default Description" }, - { General_Tags, "Freeroam" }, - { General_MaxPlayers, 8 }, - { General_Name, "BeamMP Server" }, - { General_Map, "/levels/gridmap_v2/info.json" }, - { General_AuthKey, "" }, - { General_Private, true }, - { General_Port, 30814 }, - { General_MaxCars, 1 }, - { General_LogChat, true }, - { General_ResourceFolder, "Resources" }, - { General_Debug, false }, - { Misc_SendErrorsShowMessage, true }, - { Misc_SendErrors, true }, - { Misc_ImScaredOfUpdates, true } - }; - - enum SettingsAccessMask { - read, // Value can be read from console - write, // Value can be read and written to from console - noaccess // Value is inaccessible from console (no read OR write) - }; - - using SettingsAccessControl = std::pair< - Key, // The Key's corresponding enum encoding - SettingsAccessMask // Console read/write permissions - >; - - Sync> InputAccessMapping = std::unordered_map { - { { "General", "Description" }, { General_Description, write } }, - { { "General", "Tags" }, { General_Tags, write } }, - { { "General", "MaxPlayers" }, { General_MaxPlayers, write } }, - { { "General", "Name" }, { General_Name, write } }, - { { "General", "Map" }, { General_Map, read } }, - { { "General", "AuthKey" }, { General_AuthKey, noaccess } }, - { { "General", "Private" }, { General_Private, read } }, - { { "General", "Port" }, { General_Port, read } }, - { { "General", "MaxCars" }, { General_MaxCars, write } }, - { { "General", "LogChat" }, { General_LogChat, read } }, - { { "General", "ResourceFolder" }, { General_ResourceFolder, read } }, - { { "General", "Debug" }, { General_Debug, write } }, - { { "Misc", "SendErrorsShowMessage" }, { Misc_SendErrorsShowMessage, noaccess } }, - { { "Misc", "SendErrors" }, { Misc_SendErrors, noaccess } }, - { { "Misc", "ImScaredOfUpdates" }, { Misc_ImScaredOfUpdates, noaccess } } - }; - - /* - std::unordered_map InputKeyMapping{ - {"Description", General_Description}, - {"Tags", General_Tags}, - {"MaxPlayers", General_MaxPlayers}, - {"Name", General_Name}, - {"Map", General_Map}, - {"AuthKey", General_AuthKey}, - {"Private", General_Private}, - {"Port", General_Port}, - {"MaxCars", General_MaxCars}, - {"LogChat", General_LogChat}, - {"Resourcefolder", General_ResourceFolder}, - {"Debug", General_Debug}, - {"SendErrorsShowMessage", Misc_SendErrorsShowMessage}, - {"SendErrors", Misc_SendErrors}, - {"ImScaredOfUpdates", Misc_ImScaredOfUpdates} - } - */ - std::string getAsString(Key key) { - auto map = SettingsMap.synchronize(); - if (!map->contains(key)) { - throw std::logic_error { "Undefined key accessed in Settings::getAsString" }; - } - return std::get(map->at(key)); - } - - int getAsInt(Key key) { - auto map = SettingsMap.synchronize(); - if (!map->contains(key)) { - throw std::logic_error { "Undefined key accessed in Settings::getAsInt" }; - } - return std::get(map->at(key)); - } - - bool getAsBool(Key key) { - auto map = SettingsMap.synchronize(); - if (!map->contains(key)) { - throw std::logic_error { "Undefined key accessed in Settings::getAsBool" }; - } - return std::get(map->at(key)); - } - - SettingsTypeVariant get(Key key) { - auto map = SettingsMap.synchronize(); - if (!map->contains(key)) { - throw std::logic_error { "Undefined setting key accessed in Settings::get" }; - } - return map->at(key); - } - - void set(Key key, const std::string& value) { - auto map = SettingsMap.synchronize(); - if (!map->contains(key)) { - throw std::logic_error { "Undefined setting key accessed in Settings::set(std::string)" }; - } - if (!std::holds_alternative(map->at(key))) { - throw std::logic_error { fmt::format("Wrong value type in Settings::set(std::string): index {}", map->at(key).index()) }; - } - map->at(key) = value; - } - - template, bool> = true> - void set(Key key, Integer value) { - auto map = SettingsMap.synchronize(); - if (!map->contains(key)) { - throw std::logic_error { "Undefined setting key accessed in Settings::set(int)" }; - } - if (!std::holds_alternative(map->at(key))) { - throw std::logic_error { fmt::format("Wrong value type in Settings::set(int): index {}", map->at(key).index()) }; - } - map->at(key) = value; - } - template, bool> = true> - void set(Key key, Boolean value) { - auto map = SettingsMap.synchronize(); - if (!map->contains(key)) { - throw std::logic_error { "Undefined setting key accessed in Settings::set(bool)" }; - } - if (!std::holds_alternative(map->at(key))) { - throw std::logic_error { fmt::format("Wrong value type in Settings::set(bool): index {}", map->at(key).index()) }; - } - map->at(key) = value; - } - - const std::unordered_map getACLMap() const { - return *InputAccessMapping; - } - SettingsAccessControl getConsoleInputAccessMapping(const ComposedKey& keyName) { - auto acl_map = InputAccessMapping.synchronize(); - if (!acl_map->contains(keyName)) { - throw std::logic_error { "Unknown key name accessed in Settings::getConsoleInputAccessMapping" }; - } else if (acl_map->at(keyName).second == SettingsAccessMask::noaccess) { - throw std::logic_error { "Setting '" + keyName.Category + " > " + keyName.Key + "' is not accessible from within the runtime!" }; - } - return acl_map->at(keyName); - } - - void setConsoleInputAccessMapping(const ComposedKey& keyName, std::string value) { - auto [map, acl_map] = boost::synchronize(SettingsMap, InputAccessMapping); - if (!acl_map->contains(keyName)) { - throw std::logic_error { "Unknown key name accessed in Settings::setConsoleInputAccessMapping" }; - } else if (acl_map->at(keyName).second == SettingsAccessMask::noaccess) { - throw std::logic_error { "Setting '" + keyName.Category + " > " + keyName.Key + "' is not accessible from within the runtime!" }; - } else if (acl_map->at(keyName).second == SettingsAccessMask::read) { - throw std::logic_error { "Setting '" + keyName.Category + " > " + keyName.Key + "' is not writeable from within the runtime!" }; - } - - Key key = acl_map->at(keyName).first; - - if (!std::holds_alternative(map->at(key))) { - throw std::logic_error { "Wrong value type in Settings::setConsoleInputAccessMapping: expected std::string" }; - } - - map->at(key) = value; - } - void setConsoleInputAccessMapping(const ComposedKey& keyName, int value) { - auto [map, acl_map] = boost::synchronize(SettingsMap, InputAccessMapping); - if (!acl_map->contains(keyName)) { - throw std::logic_error { "Unknown key name accessed in Settings::setConsoleInputAccessMapping" }; - } else if (acl_map->at(keyName).second == SettingsAccessMask::noaccess) { - throw std::logic_error { "Key '" + keyName.Category + " > " + keyName.Key + "' is not accessible from within the runtime!" }; - } else if (acl_map->at(keyName).second == SettingsAccessMask::read) { - throw std::logic_error { "Key '" + keyName.Category + " > " + keyName.Key + "' is not writeable from within the runtime!" }; - } - - Key key = acl_map->at(keyName).first; - - if (!std::holds_alternative(map->at(key))) { - throw std::logic_error { "Wrong value type in Settings::setConsoleInputAccessMapping: expected int" }; - } - - map->at(key) = value; - } - void setConsoleInputAccessMapping(const ComposedKey& keyName, bool value) { - auto [map, acl_map] = boost::synchronize(SettingsMap, InputAccessMapping); - if (!acl_map->contains(keyName)) { - throw std::logic_error { "Unknown key name accessed in Settings::setConsoleInputAccessMapping" }; - } else if (acl_map->at(keyName).second == SettingsAccessMask::noaccess) { - throw std::logic_error { "Key '" + keyName.Category + " > " + keyName.Key + "' is not accessible from within the runtime!" }; - } else if (acl_map->at(keyName).second == SettingsAccessMask::read) { - throw std::logic_error { "Key '" + keyName.Category + " > " + keyName.Key + "' is not writeable from within the runtime!" }; - } - - Key key = acl_map->at(keyName).first; - - if (!std::holds_alternative(map->at(key))) { - throw std::logic_error { "Wrong value type in Settings::setConsoleInputAccessMapping: expected bool" }; - } - - map->at(key) = value; - } -}; - -/*struct TSettings { - - -std::string ServerName { "BeamMP Server" }; -std::string ServerDesc { "BeamMP Default Description" }; -std::string ServerTags { "Freeroam" }; -std::string Resource { "Resources" }; -std::string MapName { "/levels/gridmap_v2/info.json" }; -std::string Key {}; -std::string Password{}; -std::string SSLKeyPath { "./.ssl/HttpServer/key.pem" }; -std::string SSLCertPath { "./.ssl/HttpServer/cert.pem" }; -bool HTTPServerEnabled { false }; -int MaxPlayers { 8 }; -bool Private { true }; -int MaxCars { 1 }; -bool DebugModeEnabled { false }; -int Port { 30814 }; -std::string CustomIP {}; -bool LogChat { true }; -bool SendErrors { true }; -bool SendErrorsMessageEnabled { true }; -int HTTPServerPort { 8080 }; -std::string HTTPServerIP { "127.0.0.1" }; -bool HTTPServerUseSSL { false }; -bool HideUpdateMessages { false }; -[[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); } - }; - - -}*/ - -TEST_CASE("settings variant functions") { - Settings settings; - settings.set(Settings::General_Name, "hello, world"); - CHECK_EQ(settings.getAsString(Settings::General_Name), "hello, world"); - settings.set(Settings::General_Name, std::string("hello, world")); - CHECK_EQ(settings.getAsString(Settings::General_Name), "hello, world"); - settings.set(Settings::General_MaxPlayers, 12); - CHECK_EQ(settings.getAsInt(Settings::General_MaxPlayers), 12); - - CHECK_THROWS(settings.set(Settings::General_Debug, "hello, world")); - CHECK_NOTHROW(settings.set(Settings::General_Debug, false)); -} diff --git a/src/LuaAPI.cpp b/src/LuaAPI.cpp index 2e99655..2d1906f 100644 --- a/src/LuaAPI.cpp +++ b/src/LuaAPI.cpp @@ -21,7 +21,7 @@ #include "Common.h" #include "CustomAssert.h" #include "TLuaEngine.h" -#include "TSettings.h" +#include "Settings.h" #include diff --git a/src/Settings.cpp b/src/Settings.cpp new file mode 100644 index 0000000..9c6753c --- /dev/null +++ b/src/Settings.cpp @@ -0,0 +1,132 @@ +// BeamMP, the BeamNG.drive multiplayer mod. +// Copyright (C) 2024 BeamMP Ltd., BeamMP team and contributors. +// +// BeamMP Ltd. can be contacted by electronic mail via contact@beammp.com. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "Settings.h" + +std::string Settings::getAsString(Key key) { + auto map = SettingsMap.synchronize(); + if (!map->contains(key)) { + throw std::logic_error { "Undefined key accessed in Settings::getAsString" }; + } + return std::get(map->at(key)); +} +int Settings::getAsInt(Key key) { + auto map = SettingsMap.synchronize(); + if (!map->contains(key)) { + throw std::logic_error { "Undefined key accessed in Settings::getAsInt" }; + } + return std::get(map->at(key)); +} + +bool Settings::getAsBool(Key key) { + auto map = SettingsMap.synchronize(); + if (!map->contains(key)) { + throw std::logic_error { "Undefined key accessed in Settings::getAsBool" }; + } + return std::get(map->at(key)); +} + +Settings::SettingsTypeVariant Settings::get(Key key) { + auto map = SettingsMap.synchronize(); + if (!map->contains(key)) { + throw std::logic_error { "Undefined setting key accessed in Settings::get" }; + } + return map->at(key); +} + +void Settings::set(Key key, const std::string& value) { + auto map = SettingsMap.synchronize(); + if (!map->contains(key)) { + throw std::logic_error { "Undefined setting key accessed in Settings::set(std::string)" }; + } + if (!std::holds_alternative(map->at(key))) { + throw std::logic_error { fmt::format("Wrong value type in Settings::set(std::string): index {}", map->at(key).index()) }; + } + map->at(key) = value; +} + +const std::unordered_map Settings::getAccessControlMap() const { + return *InputAccessMapping; +} + +Settings::SettingsAccessControl Settings::getConsoleInputAccessMapping(const ComposedKey& keyName) { + auto acl_map = InputAccessMapping.synchronize(); + if (!acl_map->contains(keyName)) { + throw std::logic_error { "Unknown key name accessed in Settings::getConsoleInputAccessMapping" }; + } else if (acl_map->at(keyName).second == SettingsAccessMask::NO_ACCESS) { + throw std::logic_error { "Setting '" + keyName.Category + " > " + keyName.Key + "' is not accessible from within the runtime!" }; + } + return acl_map->at(keyName); +} + +void Settings::setConsoleInputAccessMapping(const ComposedKey& keyName, const std::string& value) { + auto [map, acl_map] = boost::synchronize(SettingsMap, InputAccessMapping); + if (!acl_map->contains(keyName)) { + throw std::logic_error { "Unknown key name accessed in Settings::setConsoleInputAccessMapping" }; + } else if (acl_map->at(keyName).second == SettingsAccessMask::NO_ACCESS) { + throw std::logic_error { "Setting '" + keyName.Category + " > " + keyName.Key + "' is not accessible from within the runtime!" }; + } else if (acl_map->at(keyName).second == SettingsAccessMask::READ_ONLY) { + throw std::logic_error { "Setting '" + keyName.Category + " > " + keyName.Key + "' is not writeable from within the runtime!" }; + } + + Key key = acl_map->at(keyName).first; + + if (!std::holds_alternative(map->at(key))) { + throw std::logic_error { "Wrong value type in Settings::setConsoleInputAccessMapping: expected std::string" }; + } + + map->at(key) = value; +} + +void Settings::setConsoleInputAccessMapping(const ComposedKey& keyName, int value) { + auto [map, acl_map] = boost::synchronize(SettingsMap, InputAccessMapping); + if (!acl_map->contains(keyName)) { + throw std::logic_error { "Unknown key name accessed in Settings::setConsoleInputAccessMapping" }; + } else if (acl_map->at(keyName).second == SettingsAccessMask::NO_ACCESS) { + throw std::logic_error { "Key '" + keyName.Category + " > " + keyName.Key + "' is not accessible from within the runtime!" }; + } else if (acl_map->at(keyName).second == SettingsAccessMask::READ_ONLY) { + throw std::logic_error { "Key '" + keyName.Category + " > " + keyName.Key + "' is not writeable from within the runtime!" }; + } + + Key key = acl_map->at(keyName).first; + + if (!std::holds_alternative(map->at(key))) { + throw std::logic_error { "Wrong value type in Settings::setConsoleInputAccessMapping: expected int" }; + } + + map->at(key) = value; +} + +void Settings::setConsoleInputAccessMapping(const ComposedKey& keyName, bool value) { + auto [map, acl_map] = boost::synchronize(SettingsMap, InputAccessMapping); + if (!acl_map->contains(keyName)) { + throw std::logic_error { "Unknown key name accessed in Settings::setConsoleInputAccessMapping" }; + } else if (acl_map->at(keyName).second == SettingsAccessMask::NO_ACCESS) { + throw std::logic_error { "Key '" + keyName.Category + " > " + keyName.Key + "' is not accessible from within the runtime!" }; + } else if (acl_map->at(keyName).second == SettingsAccessMask::READ_ONLY) { + throw std::logic_error { "Key '" + keyName.Category + " > " + keyName.Key + "' is not writeable from within the runtime!" }; + } + + Key key = acl_map->at(keyName).first; + + if (!std::holds_alternative(map->at(key))) { + throw std::logic_error { "Wrong value type in Settings::setConsoleInputAccessMapping: expected bool" }; + } + + map->at(key) = value; +} diff --git a/src/TConfig.cpp b/src/TConfig.cpp index daf8b7e..a41cf18 100644 --- a/src/TConfig.cpp +++ b/src/TConfig.cpp @@ -20,7 +20,7 @@ #include "Env.h" #include "TConfig.h" -#include "TSettings.h" +#include "Settings.h" #include #include #include diff --git a/src/TConsole.cpp b/src/TConsole.cpp index 2079b8d..636ae17 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -385,7 +385,7 @@ void TConsole::Command_Settings(const std::string&, const std::vector sets specified setting to value )"; - if (args.size() == 0) { + if (EnsureArgsCount(args, 0)) { beammp_errorf("No arguments specified for command 'settings'!"); Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); return; @@ -472,11 +472,11 @@ void TConsole::Command_Settings(const std::string&, const std::vector - for (const auto& [composedKey, keyACL] : Application::Settings.getACLMap()) { + for (const auto& [composedKey, keyACL] : Application::Settings.getAccessControlMap()) { // even though we have the value, we want to ignore it in order to make use of access // control checks - if (keyACL.second != Settings::SettingsAccessMask::noaccess) { + if (keyACL.second != Settings::SettingsAccessMask::NO_ACCESS) { try { diff --git a/src/main.cpp b/src/main.cpp index b93ff77..59c1469 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,7 +29,7 @@ #include "TPluginMonitor.h" #include "TResourceManager.h" #include "TServer.h" -#include "TSettings.h" +#include "Settings.h" #include #include