Changeset View
Changeset View
Standalone View
Standalone View
source/ps/ConfigDB.cpp
Show All 31 Lines | |||||
namespace | namespace | ||||
{ | { | ||||
void TriggerAllHooks(const std::multimap<CStr, std::function<void()>>& hooks, const CStr& name) | void TriggerAllHooks(const std::multimap<CStr, std::function<void()>>& hooks, const CStr& name) | ||||
{ | { | ||||
std::for_each(hooks.lower_bound(name), hooks.upper_bound(name), [](const std::pair<CStr, std::function<void()>>& hook) { hook.second(); }); | std::for_each(hooks.lower_bound(name), hooks.upper_bound(name), [](const std::pair<CStr, std::function<void()>>& hook) { hook.second(); }); | ||||
} | } | ||||
std::recursive_mutex g_ConfigDBMutex; | |||||
// These entries will not be printed to logfiles, so that logfiles can be shared without leaking personal or sensitive data | // These entries will not be printed to logfiles, so that logfiles can be shared without leaking personal or sensitive data | ||||
const std::unordered_set<std::string> g_UnloggedEntries = { | const std::unordered_set<std::string> g_UnloggedEntries = { | ||||
"lobby.password", | "lobby.password", | ||||
"lobby.buddies", | "lobby.buddies", | ||||
"userreport.id" // authentication token for GDPR personal data requests | "userreport.id" // authentication token for GDPR personal data requests | ||||
}; | }; | ||||
#define CHECK_NS(rval)\ | #define CHECK_NS(rval)\ | ||||
Show All 34 Lines | else | ||||
ret += str[i]; | ret += str[i]; | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
} // anonymous namespace | } // anonymous namespace | ||||
typedef std::map<CStr, CConfigValueSet> TConfigMap; | typedef std::map<CStr, CConfigValueSet> TConfigMap; | ||||
TConfigMap CConfigDB::m_Map[CFG_LAST]; | |||||
VfsPath CConfigDB::m_ConfigFile[CFG_LAST]; | |||||
bool CConfigDB::m_HasChanges[CFG_LAST]; | |||||
std::multimap<CStr, std::function<void()>> CConfigDB::m_Hooks; | |||||
#define GETVAL(type)\ | #define GETVAL(type)\ | ||||
void CConfigDB::GetValue(EConfigNamespace ns, const CStr& name, type& value)\ | void CConfigDB::GetValue(EConfigNamespace ns, const CStr& name, type& value)\ | ||||
{\ | {\ | ||||
CHECK_NS(;);\ | CHECK_NS(;);\ | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex);\ | std::lock_guard<std::recursive_mutex> s(m_Mutex);\ | ||||
TConfigMap::iterator it = m_Map[CFG_COMMAND].find(name);\ | TConfigMap::iterator it = m_Map[CFG_COMMAND].find(name);\ | ||||
if (it != m_Map[CFG_COMMAND].end())\ | if (it != m_Map[CFG_COMMAND].end())\ | ||||
{\ | {\ | ||||
if (!it->second.empty())\ | if (!it->second.empty())\ | ||||
Get(it->second[0], value);\ | Get(it->second[0], value);\ | ||||
return;\ | return;\ | ||||
}\ | }\ | ||||
for (int search_ns = ns; search_ns >= 0; --search_ns)\ | for (int search_ns = ns; search_ns >= 0; --search_ns)\ | ||||
Show All 10 Lines | |||||
GETVAL(bool) | GETVAL(bool) | ||||
GETVAL(int) | GETVAL(int) | ||||
GETVAL(u32) | GETVAL(u32) | ||||
GETVAL(float) | GETVAL(float) | ||||
GETVAL(double) | GETVAL(double) | ||||
GETVAL(std::string) | GETVAL(std::string) | ||||
#undef GETVAL | #undef GETVAL | ||||
std::unique_ptr<CConfigDB> g_ConfigDBPtr; | |||||
void CConfigDB::Initialise() | |||||
{ | |||||
g_ConfigDBPtr = std::make_unique<CConfigDB>(); | |||||
} | |||||
void CConfigDB::Shutdown() | |||||
{ | |||||
g_ConfigDBPtr.reset(); | |||||
} | |||||
bool CConfigDB::IsInitialised() | |||||
{ | |||||
return !!g_ConfigDBPtr; | |||||
} | |||||
CConfigDB* CConfigDB::Instance() | |||||
{ | |||||
return g_ConfigDBPtr.get(); | |||||
} | |||||
CConfigDB::CConfigDB() | |||||
{ | |||||
} | |||||
CConfigDB::~CConfigDB() | |||||
{ | |||||
} | |||||
bool CConfigDB::HasChanges(EConfigNamespace ns) const | bool CConfigDB::HasChanges(EConfigNamespace ns) const | ||||
{ | { | ||||
CHECK_NS(false); | CHECK_NS(false); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
return m_HasChanges[ns]; | return m_HasChanges[ns]; | ||||
} | } | ||||
void CConfigDB::SetChanges(EConfigNamespace ns, bool value) | void CConfigDB::SetChanges(EConfigNamespace ns, bool value) | ||||
{ | { | ||||
CHECK_NS(;); | CHECK_NS(;); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
m_HasChanges[ns] = value; | m_HasChanges[ns] = value; | ||||
} | } | ||||
void CConfigDB::GetValues(EConfigNamespace ns, const CStr& name, CConfigValueSet& values) const | void CConfigDB::GetValues(EConfigNamespace ns, const CStr& name, CConfigValueSet& values) const | ||||
{ | { | ||||
CHECK_NS(;); | CHECK_NS(;); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
TConfigMap::iterator it = m_Map[CFG_COMMAND].find(name); | TConfigMap::const_iterator it = m_Map[CFG_COMMAND].find(name); | ||||
if (it != m_Map[CFG_COMMAND].end()) | if (it != m_Map[CFG_COMMAND].end()) | ||||
{ | { | ||||
values = it->second; | values = it->second; | ||||
return; | return; | ||||
} | } | ||||
for (int search_ns = ns; search_ns >= 0; --search_ns) | for (int search_ns = ns; search_ns >= 0; --search_ns) | ||||
{ | { | ||||
it = m_Map[search_ns].find(name); | it = m_Map[search_ns].find(name); | ||||
if (it != m_Map[search_ns].end()) | if (it != m_Map[search_ns].end()) | ||||
{ | { | ||||
values = it->second; | values = it->second; | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
EConfigNamespace CConfigDB::GetValueNamespace(EConfigNamespace ns, const CStr& name) const | EConfigNamespace CConfigDB::GetValueNamespace(EConfigNamespace ns, const CStr& name) const | ||||
{ | { | ||||
CHECK_NS(CFG_LAST); | CHECK_NS(CFG_LAST); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
TConfigMap::iterator it = m_Map[CFG_COMMAND].find(name); | TConfigMap::const_iterator it = m_Map[CFG_COMMAND].find(name); | ||||
if (it != m_Map[CFG_COMMAND].end()) | if (it != m_Map[CFG_COMMAND].end()) | ||||
return CFG_COMMAND; | return CFG_COMMAND; | ||||
for (int search_ns = ns; search_ns >= 0; --search_ns) | for (int search_ns = ns; search_ns >= 0; --search_ns) | ||||
{ | { | ||||
it = m_Map[search_ns].find(name); | it = m_Map[search_ns].find(name); | ||||
if (it != m_Map[search_ns].end()) | if (it != m_Map[search_ns].end()) | ||||
return (EConfigNamespace)search_ns; | return (EConfigNamespace)search_ns; | ||||
} | } | ||||
return CFG_LAST; | return CFG_LAST; | ||||
} | } | ||||
std::map<CStr, CConfigValueSet> CConfigDB::GetValuesWithPrefix(EConfigNamespace ns, const CStr& prefix) const | std::map<CStr, CConfigValueSet> CConfigDB::GetValuesWithPrefix(EConfigNamespace ns, const CStr& prefix) const | ||||
{ | { | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
std::map<CStr, CConfigValueSet> ret; | std::map<CStr, CConfigValueSet> ret; | ||||
CHECK_NS(ret); | CHECK_NS(ret); | ||||
// Loop upwards so that values in later namespaces can override | // Loop upwards so that values in later namespaces can override | ||||
// values in earlier namespaces | // values in earlier namespaces | ||||
for (int search_ns = 0; search_ns <= ns; ++search_ns) | for (int search_ns = 0; search_ns <= ns; ++search_ns) | ||||
for (const std::pair<const CStr, CConfigValueSet>& p : m_Map[search_ns]) | for (const std::pair<const CStr, CConfigValueSet>& p : m_Map[search_ns]) | ||||
if (boost::algorithm::starts_with(p.first, prefix)) | if (boost::algorithm::starts_with(p.first, prefix)) | ||||
ret[p.first] = p.second; | ret[p.first] = p.second; | ||||
for (const std::pair<const CStr, CConfigValueSet>& p : m_Map[CFG_COMMAND]) | for (const std::pair<const CStr, CConfigValueSet>& p : m_Map[CFG_COMMAND]) | ||||
if (boost::algorithm::starts_with(p.first, prefix)) | if (boost::algorithm::starts_with(p.first, prefix)) | ||||
ret[p.first] = p.second; | ret[p.first] = p.second; | ||||
return ret; | return ret; | ||||
} | } | ||||
void CConfigDB::SetValueString(EConfigNamespace ns, const CStr& name, const CStr& value) | void CConfigDB::SetValueString(EConfigNamespace ns, const CStr& name, const CStr& value) | ||||
{ | { | ||||
CHECK_NS(;); | CHECK_NS(;); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
TConfigMap::iterator it = m_Map[ns].find(name); | TConfigMap::iterator it = m_Map[ns].find(name); | ||||
if (it == m_Map[ns].end()) | if (it == m_Map[ns].end()) | ||||
it = m_Map[ns].insert(m_Map[ns].begin(), make_pair(name, CConfigValueSet(1))); | it = m_Map[ns].insert(m_Map[ns].begin(), make_pair(name, CConfigValueSet(1))); | ||||
if (!it->second.empty()) | if (!it->second.empty()) | ||||
it->second[0] = value; | it->second[0] = value; | ||||
else | else | ||||
it->second.emplace_back(value); | it->second.emplace_back(value); | ||||
TriggerAllHooks(m_Hooks, name); | TriggerAllHooks(m_Hooks, name); | ||||
} | } | ||||
void CConfigDB::SetValueBool(EConfigNamespace ns, const CStr& name, const bool value) | void CConfigDB::SetValueBool(EConfigNamespace ns, const CStr& name, const bool value) | ||||
{ | { | ||||
CStr valueString = value ? "true" : "false"; | CStr valueString = value ? "true" : "false"; | ||||
SetValueString(ns, name, valueString); | SetValueString(ns, name, valueString); | ||||
} | } | ||||
void CConfigDB::SetValueList(EConfigNamespace ns, const CStr& name, std::vector<CStr> values) | void CConfigDB::SetValueList(EConfigNamespace ns, const CStr& name, std::vector<CStr> values) | ||||
{ | { | ||||
CHECK_NS(;); | CHECK_NS(;); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
TConfigMap::iterator it = m_Map[ns].find(name); | TConfigMap::iterator it = m_Map[ns].find(name); | ||||
if (it == m_Map[ns].end()) | if (it == m_Map[ns].end()) | ||||
it = m_Map[ns].insert(m_Map[ns].begin(), make_pair(name, CConfigValueSet(1))); | it = m_Map[ns].insert(m_Map[ns].begin(), make_pair(name, CConfigValueSet(1))); | ||||
it->second = values; | it->second = values; | ||||
} | } | ||||
void CConfigDB::RemoveValue(EConfigNamespace ns, const CStr& name) | void CConfigDB::RemoveValue(EConfigNamespace ns, const CStr& name) | ||||
{ | { | ||||
CHECK_NS(;); | CHECK_NS(;); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
TConfigMap::iterator it = m_Map[ns].find(name); | TConfigMap::iterator it = m_Map[ns].find(name); | ||||
if (it == m_Map[ns].end()) | if (it == m_Map[ns].end()) | ||||
return; | return; | ||||
m_Map[ns].erase(it); | m_Map[ns].erase(it); | ||||
TriggerAllHooks(m_Hooks, name); | TriggerAllHooks(m_Hooks, name); | ||||
} | } | ||||
void CConfigDB::SetConfigFile(EConfigNamespace ns, const VfsPath& path) | void CConfigDB::SetConfigFile(EConfigNamespace ns, const VfsPath& path) | ||||
{ | { | ||||
CHECK_NS(;); | CHECK_NS(;); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
m_ConfigFile[ns] = path; | m_ConfigFile[ns] = path; | ||||
} | } | ||||
bool CConfigDB::Reload(EConfigNamespace ns) | bool CConfigDB::Reload(EConfigNamespace ns) | ||||
{ | { | ||||
CHECK_NS(false); | CHECK_NS(false); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
shared_ptr<u8> buffer; | shared_ptr<u8> buffer; | ||||
size_t buflen; | size_t buflen; | ||||
{ | { | ||||
// Handle missing files quietly | // Handle missing files quietly | ||||
if (g_VFS->GetFileInfo(m_ConfigFile[ns], NULL) < 0) | if (g_VFS->GetFileInfo(m_ConfigFile[ns], NULL) < 0) | ||||
{ | { | ||||
LOGMESSAGE("Cannot find config file \"%s\" - ignoring", m_ConfigFile[ns].string8()); | LOGMESSAGE("Cannot find config file \"%s\" - ignoring", m_ConfigFile[ns].string8()); | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | bool CConfigDB::Reload(EConfigNamespace ns) | ||||
return true; | return true; | ||||
} | } | ||||
bool CConfigDB::WriteFile(EConfigNamespace ns) const | bool CConfigDB::WriteFile(EConfigNamespace ns) const | ||||
{ | { | ||||
CHECK_NS(false); | CHECK_NS(false); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
return WriteFile(ns, m_ConfigFile[ns]); | return WriteFile(ns, m_ConfigFile[ns]); | ||||
} | } | ||||
bool CConfigDB::WriteFile(EConfigNamespace ns, const VfsPath& path) const | bool CConfigDB::WriteFile(EConfigNamespace ns, const VfsPath& path) const | ||||
{ | { | ||||
CHECK_NS(false); | CHECK_NS(false); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
shared_ptr<u8> buf; | shared_ptr<u8> buf; | ||||
AllocateAligned(buf, 1*MiB, maxSectorSize); | AllocateAligned(buf, 1*MiB, maxSectorSize); | ||||
char* pos = (char*)buf.get(); | char* pos = (char*)buf.get(); | ||||
for (const std::pair<const CStr, CConfigValueSet>& p : m_Map[ns]) | for (const std::pair<const CStr, CConfigValueSet>& p : m_Map[ns]) | ||||
{ | { | ||||
size_t i; | size_t i; | ||||
pos += sprintf(pos, "%s = ", p.first.c_str()); | pos += sprintf(pos, "%s = ", p.first.c_str()); | ||||
Show All 15 Lines | bool CConfigDB::WriteFile(EConfigNamespace ns, const VfsPath& path) const | ||||
return true; | return true; | ||||
} | } | ||||
bool CConfigDB::WriteValueToFile(EConfigNamespace ns, const CStr& name, const CStr& value) | bool CConfigDB::WriteValueToFile(EConfigNamespace ns, const CStr& name, const CStr& value) | ||||
{ | { | ||||
CHECK_NS(false); | CHECK_NS(false); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
return WriteValueToFile(ns, name, value, m_ConfigFile[ns]); | return WriteValueToFile(ns, name, value, m_ConfigFile[ns]); | ||||
} | } | ||||
bool CConfigDB::WriteValueToFile(EConfigNamespace ns, const CStr& name, const CStr& value, const VfsPath& path) | bool CConfigDB::WriteValueToFile(EConfigNamespace ns, const CStr& name, const CStr& value, const VfsPath& path) | ||||
{ | { | ||||
CHECK_NS(false); | CHECK_NS(false); | ||||
std::lock_guard<std::recursive_mutex> s(g_ConfigDBMutex); | std::lock_guard<std::recursive_mutex> s(m_Mutex); | ||||
TConfigMap newMap; | TConfigMap newMap; | ||||
m_Map[ns].swap(newMap); | m_Map[ns].swap(newMap); | ||||
Reload(ns); | Reload(ns); | ||||
SetValueString(ns, name, value); | SetValueString(ns, name, value); | ||||
bool ret = WriteFile(ns, path); | bool ret = WriteFile(ns, path); | ||||
m_Map[ns].swap(newMap); | m_Map[ns].swap(newMap); | ||||
return ret; | return ret; | ||||
} | } | ||||
CConfigDBHook CConfigDB::RegisterHookAndCall(const CStr& name, std::function<void()> hook) | CConfigDBHook CConfigDB::RegisterHookAndCall(const CStr& name, std::function<void()> hook) | ||||
{ | { | ||||
hook(); | hook(); | ||||
std::lock_guard<std::recursive_mutex> s(m_Mutex); | |||||
return CConfigDBHook(*this, m_Hooks.emplace(name, hook)); | return CConfigDBHook(*this, m_Hooks.emplace(name, hook)); | ||||
} | } | ||||
void CConfigDB::UnregisterHook(CConfigDBHook&& hook) | void CConfigDB::UnregisterHook(CConfigDBHook&& hook) | ||||
{ | { | ||||
if (hook.m_Ptr != m_Hooks.end()) | if (hook.m_Ptr != m_Hooks.end()) | ||||
{ | |||||
std::lock_guard<std::recursive_mutex> s(m_Mutex); | |||||
m_Hooks.erase(hook.m_Ptr); | m_Hooks.erase(hook.m_Ptr); | ||||
hook.m_Ptr = m_Hooks.end(); | |||||
} | |||||
} | } | ||||
void CConfigDB::UnregisterHook(std::unique_ptr<CConfigDBHook> hook) | void CConfigDB::UnregisterHook(std::unique_ptr<CConfigDBHook> hook) | ||||
{ | { | ||||
UnregisterHook(std::move(*hook.get())); | UnregisterHook(std::move(*hook.get())); | ||||
} | } | ||||
#undef CHECK_NS | #undef CHECK_NS |
Wildfire Games · Phabricator