AuroraRuntime/Source/Registry/Registry.cpp
2021-09-06 11:58:08 +01:00

380 lines
9.8 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Registry.cpp
Date: 2021-6-13
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "Registry.hpp"
#include <nlohmann/json.hpp>
using json = nlohmann::json;
namespace Aurora::Registry
{
class FSRegistry : public IRegistry
{
public:
bool Init();
void OpenReadWriteback(const AuString &path) override;
void OpenRead(const AuString &path) override;
bool Read(const AuString &path, EReadType read) override;
void SetWriteModeNone() override;
void SetWriteModeCache() override;
void SetWriteModeStream(const AuOptional<AuString> &path) override;
void SetWriteModeBuffered(const AuOptional<AuString> &path) override;
void WriteAllCacheBack() override;
void SaveBuffered() override;
void SaveAll(const AuOptional<AuString> &path) override;
void OpenSave(const AuString &path, bool buffered = false) override;
void CloseSave() override;
bool KeyExists(const AuString &key, RegistryType &type) override;
bool GetOrCreateKey(const AuString &key, const RegistryValue &def, RegistryValue &value) override;
bool SetKey(const AuString &key, const RegistryValue &value) override;
bool GetKey(const AuString &key, RegistryValue &value) override;
void LockKey(const AuString &str) override;
void UnlockKey(const AuString &str) override;
bool SetKeyLocked(const AuString &key, const RegistryValue &value);
bool GetKeyLocked(const AuString &key, RegistryValue &value);
bool Save();
private:
Threading::Primitives::RWLockUnique_t lock_;
EWriteMode writeMode_;
json currentStreamDocument_;
json cacheDocument_;
AuOptional<AuString> lastPath_;
AuList<AuString> restrictedKeys_;
AuList<AuString> changes_;
};
bool FSRegistry::Init()
{
lock_ = Threading::Primitives::RWLockUnique();
return lock_ ? true : false;
}
void FSRegistry::SetWriteModeNone()
{
AU_LOCK_GUARD(lock_->AsWritable());
writeMode_ = EWriteMode::eWriteModeLocked;
changes_.clear();
}
void FSRegistry::SetWriteModeCache()
{
AU_LOCK_GUARD(lock_->AsWritable());
writeMode_ = EWriteMode::eWriteModeFileBuffer;
//lastPath_.reset();
changes_.clear();
}
void FSRegistry::SetWriteModeStream(const AuOptional<AuString> &path)
{
AU_LOCK_GUARD(lock_->AsWritable());
writeMode_ = EWriteMode::eWriteModeFileStream;
if (path) lastPath_ = path;
changes_.clear();
}
void FSRegistry::SetWriteModeBuffered(const AuOptional<AuString> &path)
{
AU_LOCK_GUARD(lock_->AsWritable());
writeMode_ = EWriteMode::eWriteModeFileBuffer;
if (path) lastPath_ = path;
changes_.clear();
}
bool FSRegistry::Read(const AuString &path, EReadType read)
{
AU_LOCK_GUARD(lock_->AsWritable());
this->lastPath_ = path;
try
{
AuString file;
currentStreamDocument_ = {};
if (read == EReadType::eClearCacheAndStore)
{
cacheDocument_ = {};
}
if (!IO::FS::ReadString(path, file))
{
return IO::FS::WriteString(path, "{}");
}
currentStreamDocument_ = json::parse(file);
for (const auto &[key, value] : currentStreamDocument_.items())
{
if (read == EReadType::eStoreNew)
{
if (cacheDocument_.find(key) != cacheDocument_.end())
{
continue;
}
}
cacheDocument_[key] = value;
}
}
catch (...)
{
return false;
}
return true;
}
bool FSRegistry::KeyExists(const AuString &key, RegistryType &type)
{
AU_LOCK_GUARD(lock_->AsReadable());
auto itrObject = cacheDocument_.find(key);
if (itrObject == cacheDocument_.end())
{
return false;
}
auto itrType = itrObject->find("type");
if (itrType == itrObject->end())
{
return false;
}
auto itrValue = itrObject->find("value");
if (itrValue == itrObject->end())
{
return false;
}
return true;
}
bool FSRegistry::GetOrCreateKey(const AuString &key, const RegistryValue &ref, RegistryValue &value)
{
AU_LOCK_GUARD(lock_->AsWritable());
if (GetKeyLocked(key, value))
{
return true;
}
value = ref;
return SetKeyLocked(key, ref);
}
bool FSRegistry::GetKey(const AuString &key, RegistryValue &value)
{
AU_LOCK_GUARD(lock_->AsReadable());
return SetKeyLocked(key, value);
}
bool FSRegistry::GetKeyLocked(const AuString &key, RegistryValue &value)
{
auto itrObject = cacheDocument_.find(key);
if (itrObject == cacheDocument_.end())
{
return false;
}
auto itrType = itrObject->find("type");
auto itrValue = itrObject->find("value");
if ((itrType == itrObject->end()) ||
(itrValue == itrObject->end()))
{
return false;
}
if (!itrValue->is_string())
{
return false;
}
if (!itrType->is_number_integer())
{
return false;
}
Parse::ParsableTag type = *itrType;
AuString strValue = *itrValue;
Parse::ParseValueEx parsedValue;
if (!Parse::ConsumeToken(type, strValue , parsedValue))
{
return false;
}
value.type = static_cast<Data::DataType>(type);
value.value = parsedValue;
return true;
}
bool FSRegistry::SetKey(const AuString &key, const RegistryValue &value)
{
AU_LOCK_GUARD(lock_->AsWritable());
return SetKeyLocked(key, value);
}
bool FSRegistry::SetKeyLocked(const AuString &key, const RegistryValue &value)
{
json object {};
AuString stringified;
if (std::find(restrictedKeys_.begin(), restrictedKeys_.end(), key) != restrictedKeys_.end())
{
return false;
}
if (writeMode_ == EWriteMode::eWriteModeLocked)
{
return false;
}
auto oldValueItr = cacheDocument_.find(key);
bool hasOldValue = oldValueItr == cacheDocument_.end();
json oldValue = hasOldValue ? json{} : *oldValueItr;
object["type"] = value.type;
Parse::SerializeToken(static_cast<Parse::ParsableTag>(value.type), value.value, stringified);
object["value"] = stringified;
AuTryInsert(changes_, key);
switch (writeMode_)
{
case EWriteMode::eWriteModeFileBuffer:
cacheDocument_[key] = object;
break;
case EWriteMode::eWriteModeFileStream:
cacheDocument_[key] = object;
currentStreamDocument_[key] = object;
Save();
break;
}
return true;
}
void FSRegistry::SaveBuffered()
{
AU_LOCK_GUARD(lock_->AsWritable());
{
AU_LOCK_GUARD(lock_->AsWritable());
for (const auto &change : changes_)
{
currentStreamDocument_[change] = cacheDocument_[change];
}
}
Save();
}
void FSRegistry::WriteAllCacheBack()
{
AU_LOCK_GUARD(lock_->AsWritable());
for (const auto &[key, val] : cacheDocument_.items())
{
AuTryInsert(changes_, key);
}
}
void FSRegistry::SaveAll(const AuOptional<AuString>& path)
{
OpenSave(path.value_or(lastPath_.value_or(AuString())), true);
WriteAllCacheBack();
SaveBuffered();
CloseSave();
}
void FSRegistry::OpenRead(const AuString &path)
{
Read(path, EReadType::eClearCacheAndStore);
}
void FSRegistry::OpenReadWriteback(const AuString &path)
{
Read(path, EReadType::eClearCacheAndStore);
OpenSave(path, false);
}
void FSRegistry::OpenSave(const AuString &path, bool buffered)
{
if (buffered)
{
SetWriteModeBuffered(path);
}
else
{
SetWriteModeStream(path);
}
}
void FSRegistry::CloseSave()
{
SetWriteModeNone();
}
void FSRegistry::LockKey(const AuString &str)
{
AU_LOCK_GUARD(lock_->AsWritable());
AuTryInsert(restrictedKeys_, str);
}
void FSRegistry::UnlockKey(const AuString &str)
{
AU_LOCK_GUARD(lock_->AsWritable());
AuTryDeleteList(restrictedKeys_, str);
}
bool FSRegistry::Save()
{
bool ret {};
if (!lastPath_.has_value())
{
return false;
}
if (!IO::FS::WriteString(lastPath_.value(), currentStreamDocument_.dump(4)))
{
SysPushErrorIO("Couldn't write registry to {}", lastPath_.value());
return false;
}
return true;
}
AUKN_SYM IRegistry *RegistryNew(ERegistrySource source)
{
SysAssert(source == ERegistrySource::eFS, "Unknown registry type");
auto registry = _new FSRegistry();
if (!registry)
{
return nullptr;
}
if (!registry->Init())
{
delete registry;
return nullptr;
}
return registry;
}
AUKN_SYM void RegistryRelease(IRegistry *registry)
{
SafeDelete<FSRegistry *>(registry);
}
}