mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-20 19:21:00 -06:00
Feature/configuration (#605)
* Switch openspace.cfg file from a Dictionary-based loading to a variable based loading * Change ConfigurationManager to not use Dictionary anymore, but a struct with explicit configuration values instead
This commit is contained in:
350
src/engine/configuration.cpp
Normal file
350
src/engine/configuration.cpp
Normal file
@@ -0,0 +1,350 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/engine/configuration.h>
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <ghoul/filesystem/file.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/lua/ghoul_lua.h>
|
||||
#include <ghoul/lua/lua_helper.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* BasePathToken = "${BASE}";
|
||||
// We can't use ${SCRIPTS} here as that hasn't been defined by this point
|
||||
constexpr const char* InitialConfigHelper =
|
||||
"${BASE}/scripts/configuration_helper.lua";
|
||||
|
||||
// Variable names for the openspace.cfg file
|
||||
// These are also used in the _doc include file
|
||||
constexpr const char* KeySGCTConfig = "SGCTConfig";
|
||||
constexpr const char* KeyAsset = "Asset";
|
||||
constexpr const char* KeyGlobalCustomizationScripts = "GlobalCustomizationScripts";
|
||||
constexpr const char* KeyPaths = "Paths";
|
||||
constexpr const char* KeyPathsCACHE = "Paths.CACHE";
|
||||
constexpr const char* KeyFonts = "Fonts";
|
||||
constexpr const char* KeyLogging = "Logging";
|
||||
constexpr const char* KeyLogDir = "LogDir";
|
||||
constexpr const char* KeyPerformancePrefix = "PerformancePrefix";
|
||||
constexpr const char* KeyLogLevel = "LogLevel";
|
||||
constexpr const char* KeyImmediateFlush = "ImmediateFlush";
|
||||
constexpr const char* KeyLogs = "Logs";
|
||||
constexpr const char* KeyCapabilitiesVerbosity = "CapabilitiesVerbosity";
|
||||
constexpr const char* KeyLuaDocumentation = "LuaDocumentation";
|
||||
constexpr const char* KeyPropertyDocumentation = "PropertyDocumentation";
|
||||
constexpr const char* KeyScriptLog = "ScriptLog";
|
||||
constexpr const char* KeyKeyboardShortcuts = "KeyboardShortcuts";
|
||||
constexpr const char* KeyDocumentation = "Documentation";
|
||||
constexpr const char* KeyFactoryDocumentation = "FactoryDocumentation";
|
||||
constexpr const char* KeyRequireSocketAuthentication = "RequireSocketAuthentication";
|
||||
constexpr const char* KeyServerPasskey = "ServerPasskey";
|
||||
constexpr const char* KeyClientAddressWhitelist = "ClientAddressWhitelist";
|
||||
constexpr const char* KeyLicenseDocumentation = "LicenseDocumentation";
|
||||
constexpr const char* KeyShutdownCountdown = "ShutdownCountdown";
|
||||
constexpr const char* KeyPerSceneCache = "PerSceneCache";
|
||||
constexpr const char* KeyOnScreenTextScaling = "OnScreenTextScaling";
|
||||
constexpr const char* KeyRenderingMethod = "RenderingMethod";
|
||||
constexpr const char* KeyDisableRenderingOnMaster = "DisableRenderingOnMaster";
|
||||
constexpr const char* KeyDisableSceneOnMaster = "DisableSceneOnMaster";
|
||||
constexpr const char* KeyScreenshotUseDate = "ScreenshotUseDate";
|
||||
constexpr const char* KeyHttpProxy = "HttpProxy";
|
||||
constexpr const char* KeyAddress = "Address";
|
||||
constexpr const char* KeyPort = "Port";
|
||||
constexpr const char* KeyAuthentication = "Authentication";
|
||||
constexpr const char* KeyUser = "User";
|
||||
constexpr const char* KeyPassword = "Password";
|
||||
constexpr const char* KeyOpenGLDebugContext = "OpenGLDebugContext";
|
||||
constexpr const char* KeyActivate = "Activate";
|
||||
constexpr const char* KeySynchronous = "Synchronous";
|
||||
constexpr const char* KeyFilterIdentifier = "FilterIdentifier";
|
||||
constexpr const char* KeyIdentifier = "Identifier";
|
||||
constexpr const char* KeySource = "Source";
|
||||
constexpr const char* KeyType = "Type";
|
||||
constexpr const char* KeyFilterSeverity = "FilterSeverity";
|
||||
constexpr const char* KeyCheckOpenGLState = "CheckOpenGLState";
|
||||
constexpr const char* KeyLogEachOpenGLCall = "LogEachOpenGLCall";
|
||||
constexpr const char* KeyUseMultithreadedInitialization =
|
||||
"UseMultithreadedInitialization";
|
||||
constexpr const char* KeyLoadingScreen = "LoadingScreen";
|
||||
constexpr const char* KeyShowMessage = "ShowMessage";
|
||||
constexpr const char* KeyShowNodeNames = "ShowNodeNames";
|
||||
constexpr const char* KeyShowProgressbar = "ShowProgressbar";
|
||||
constexpr const char* KeyModuleConfigurations = "ModuleConfigurations";
|
||||
} // namespace
|
||||
|
||||
#include "configuration_doc.inl"
|
||||
|
||||
namespace openspace {
|
||||
|
||||
template <typename T>
|
||||
void getValue(ghoul::lua::LuaState& L, const char* name, T& value) {
|
||||
auto it = std::find_if(
|
||||
Configuration::Documentation.entries.begin(),
|
||||
Configuration::Documentation.entries.end(),
|
||||
[name](const documentation::DocumentationEntry& e) {
|
||||
return e.key == name;
|
||||
}
|
||||
);
|
||||
|
||||
bool isOptional =
|
||||
it != Configuration::Documentation.entries.end()
|
||||
? it->optional :
|
||||
true;
|
||||
|
||||
lua_getglobal(L, name);
|
||||
if (isOptional && lua_isnil(L, -1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isOptional && lua_isnil(L, -1)) {
|
||||
documentation::TestResult testResult = {
|
||||
false,
|
||||
{ { name, documentation::TestResult::Offense::Reason::MissingKey} },
|
||||
{}
|
||||
};
|
||||
throw documentation::SpecificationError(std::move(testResult), "Configuration");
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, std::vector<std::string>>) {
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
std::vector<std::string> res;
|
||||
for (size_t i = 1; i <= d.size(); ++i) {
|
||||
res.push_back(d.value<std::string>(std::to_string(i)));
|
||||
}
|
||||
value = res;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::map<std::string, std::string>>) {
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
std::map<std::string, std::string> res;
|
||||
for (size_t i = 0; i < d.size(); ++i) {
|
||||
std::string key = d.keys()[i];
|
||||
std::string v = d.value<std::string>(key);
|
||||
res[std::move(key)] = std::move(v);
|
||||
}
|
||||
value = res;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::map<std::string, ghoul::Dictionary>>) {
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
std::map<std::string, ghoul::Dictionary> res;
|
||||
for (size_t i = 0; i < d.size(); ++i) {
|
||||
std::string key = d.keys()[i];
|
||||
ghoul::Dictionary v = d.value<ghoul::Dictionary>(key);
|
||||
res[std::move(key)] = std::move(v);
|
||||
}
|
||||
value = res;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Configuration::Logging>) {
|
||||
Configuration::Logging& v = static_cast<Configuration::Logging&>(value);
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
d.getValue(KeyLogLevel, v.level);
|
||||
d.getValue(KeyLogDir, v.directory);
|
||||
d.getValue(KeyPerformancePrefix, v.performancePrefix);
|
||||
d.getValue(KeyImmediateFlush, v.forceImmediateFlush);
|
||||
d.getValue(KeyCapabilitiesVerbosity, v.capabilitiesVerbosity);
|
||||
|
||||
if (d.hasKeyAndValue<ghoul::Dictionary>(KeyLogs)) {
|
||||
ghoul::Dictionary l = d.value<ghoul::Dictionary>(KeyLogs);
|
||||
std::vector<ghoul::Dictionary> res;
|
||||
for (size_t i = 1; i <= l.size(); ++i) {
|
||||
res.push_back(l.value<ghoul::Dictionary>(std::to_string(i)));
|
||||
}
|
||||
v.logs = res;
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Configuration::DocumentationInfo>) {
|
||||
Configuration::DocumentationInfo& v =
|
||||
static_cast<Configuration::DocumentationInfo&>(value);
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
d.getValue(KeyLuaDocumentation, v.lua);
|
||||
d.getValue(KeyPropertyDocumentation, v.property);
|
||||
d.getValue("ScenePropertyDocumentation", v.sceneProperty);
|
||||
d.getValue(KeyKeyboardShortcuts, v.keyboard);
|
||||
d.getValue(KeyDocumentation, v.documentation);
|
||||
d.getValue(KeyFactoryDocumentation, v.factory);
|
||||
d.getValue(KeyLicenseDocumentation, v.license);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Configuration::LoadingScreen>) {
|
||||
Configuration::LoadingScreen& v =
|
||||
static_cast<Configuration::LoadingScreen&>(value);
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
d.getValue(KeyShowMessage, v.isShowingMessages);
|
||||
d.getValue(KeyShowNodeNames, v.isShowingNodeNames);
|
||||
d.getValue(KeyShowProgressbar, v.isShowingProgressbar);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Configuration::OpenGLDebugContext>) {
|
||||
Configuration::OpenGLDebugContext& v =
|
||||
static_cast<Configuration::OpenGLDebugContext&>(value);
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
d.getValue(KeyActivate, v.isActive);
|
||||
d.getValue(KeySynchronous, v.isSynchronous);
|
||||
|
||||
if (d.hasKeyAndValue<ghoul::Dictionary>(KeyFilterIdentifier)) {
|
||||
ghoul::Dictionary f = d.value<ghoul::Dictionary>(KeyFilterIdentifier);
|
||||
|
||||
std::vector<Configuration::OpenGLDebugContext::IdentifierFilter> res;
|
||||
for (size_t i = 1; i <= f.size(); ++i) {
|
||||
Configuration::OpenGLDebugContext::IdentifierFilter filter;
|
||||
ghoul::Dictionary fi = f.value<ghoul::Dictionary>(std::to_string(i));
|
||||
|
||||
double id = static_cast<double>(filter.identifier);
|
||||
fi.getValue(KeyIdentifier, id);
|
||||
filter.identifier = static_cast<unsigned int>(id);
|
||||
fi.getValue(KeySource, filter.source);
|
||||
fi.getValue(KeyType, filter.type);
|
||||
|
||||
res.push_back(filter);
|
||||
}
|
||||
|
||||
v.identifierFilters = res;
|
||||
}
|
||||
|
||||
if (d.hasKeyAndValue<ghoul::Dictionary>(KeyFilterSeverity)) {
|
||||
ghoul::Dictionary f = d.value<ghoul::Dictionary>(KeyFilterSeverity);
|
||||
|
||||
std::vector<std::string> res;
|
||||
for (size_t i = 1; i <= f.size(); ++i) {
|
||||
res.push_back(f.value<std::string>(std::to_string(i)));
|
||||
}
|
||||
v.severityFilters = res;
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Configuration::HTTPProxy>) {
|
||||
Configuration::HTTPProxy& v = static_cast<Configuration::HTTPProxy&>(value);
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
|
||||
|
||||
d.getValue(KeyActivate, v.usingHttpProxy);
|
||||
d.getValue(KeyAddress, v.address);
|
||||
double p = static_cast<double>(v.port);
|
||||
d.getValue(KeyPort, p);
|
||||
v.port = static_cast<unsigned int>(p);
|
||||
d.getValue(KeyAuthentication, v.authentication);
|
||||
d.getValue(KeyUser, v.user);
|
||||
d.getValue(KeyPassword, v.password);
|
||||
}
|
||||
else {
|
||||
value = ghoul::lua::value<T>(L);
|
||||
}
|
||||
}
|
||||
|
||||
void parseLuaState(Configuration& configuration) {
|
||||
using namespace ghoul::lua;
|
||||
|
||||
// Shorten the rest of this function
|
||||
Configuration& c = configuration;
|
||||
LuaState& s = c.state;
|
||||
|
||||
getValue(s, KeySGCTConfig, c.windowConfiguration);
|
||||
getValue(s, KeyAsset, c.asset);
|
||||
getValue(s, KeyGlobalCustomizationScripts, c.globalCustomizationScripts);
|
||||
getValue(s, KeyPaths, c.pathTokens);
|
||||
getValue(s, KeyFonts, c.fonts);
|
||||
getValue(s, KeyScriptLog, c.scriptLog);
|
||||
getValue(s, KeyUseMultithreadedInitialization, c.useMultithreadedInitialization);
|
||||
getValue(s, KeyCheckOpenGLState, c.isCheckingOpenGLState);
|
||||
getValue(s, KeyLogEachOpenGLCall, c.isLoggingOpenGLCalls);
|
||||
getValue(s, KeyShutdownCountdown, c.shutdownCountdown);
|
||||
getValue(s, KeyScreenshotUseDate, c.shouldUseScreenshotDate);
|
||||
getValue(s, KeyOnScreenTextScaling, c.onScreenTextScaling);
|
||||
getValue(s, KeyPerSceneCache, c.usePerSceneCache);
|
||||
getValue(s, KeyDisableRenderingOnMaster, c.isRenderingOnMasterDisabled);
|
||||
getValue(s, KeyDisableSceneOnMaster, c.isSceneTranslationOnMasterDisabled);
|
||||
getValue(s, KeyRenderingMethod, c.renderingMethod);
|
||||
getValue(s, KeyServerPasskey, c.serverPasskey);
|
||||
getValue(s, KeyRequireSocketAuthentication, c.doesRequireSocketAuthentication);
|
||||
getValue(s, KeyClientAddressWhitelist, c.clientAddressWhitelist);
|
||||
getValue(s, "WebHelperLocation", c.webHelperLocation);
|
||||
getValue(s, "CefWebGuiUrl", c.cefWebGuiUrl);
|
||||
|
||||
getValue(s, KeyLogging, c.logging);
|
||||
getValue(s, KeyDocumentation, c.documentation);
|
||||
getValue(s, KeyLoadingScreen, c.loadingScreen);
|
||||
getValue(s, KeyModuleConfigurations, c.moduleConfigurations);
|
||||
getValue(s, KeyOpenGLDebugContext, c.openGLDebugContext);
|
||||
getValue(s, KeyHttpProxy, c.httpProxy);
|
||||
}
|
||||
|
||||
std::string findConfiguration(const std::string& filename) {
|
||||
using ghoul::filesystem::Directory;
|
||||
|
||||
Directory directory = FileSys.currentDirectory();
|
||||
|
||||
while (true) {
|
||||
std::string fullPath = FileSys.pathByAppendingComponent(
|
||||
directory,
|
||||
filename
|
||||
);
|
||||
|
||||
if (FileSys.fileExists(fullPath)) {
|
||||
// We have found the configuration file and can bail out
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
// Otherwise, we traverse the directory tree up
|
||||
Directory nextDirectory = directory.parentDirectory(
|
||||
ghoul::filesystem::Directory::AbsolutePath::Yes
|
||||
);
|
||||
|
||||
if (directory.path() == nextDirectory.path()) {
|
||||
// We have reached the root of the file system and did not find the file
|
||||
throw ghoul::RuntimeError(
|
||||
"Could not find configuration file '" + filename + "'",
|
||||
"ConfigurationManager"
|
||||
);
|
||||
}
|
||||
directory = nextDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
Configuration loadConfigurationFromFile(const std::string& filename) {
|
||||
ghoul_assert(!filename.empty(), "Filename must not be empty");
|
||||
ghoul_assert(FileSys.fileExists(filename), "File must exist");
|
||||
|
||||
Configuration result;
|
||||
|
||||
// Register the base path as the directory where 'filename' lives
|
||||
std::string basePath = ghoul::filesystem::File(filename).directoryName();
|
||||
FileSys.registerPathToken(BasePathToken, basePath);
|
||||
|
||||
// If there is an initial config helper file, load it into the state
|
||||
if (FileSys.fileExists(absPath(InitialConfigHelper))) {
|
||||
ghoul::lua::runScriptFile(result.state, absPath(InitialConfigHelper));
|
||||
}
|
||||
|
||||
// Load the configuration file into the state
|
||||
ghoul::lua::runScriptFile(result.state, filename);
|
||||
|
||||
parseLuaState(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
Reference in New Issue
Block a user