AuroraRuntime/Include/Aurora/Registry/IRegistry.hpp

184 lines
7.2 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IRegistry.hpp
Date: 2021-6-11
Author: Reece
***/
#pragma once
namespace Aurora::Registry
{
using RegistryType = Data::EDataType;
using RegistryValue = Data::TypedValue;
struct AUKN_SYM IOPath
{
AU_COPY_MOVE(IOPath);
IOPath();
IOPath(const AuString &path);
bool isSpecified {};
// ERegistrySource::eFS
AuString filePath;
// [...]
bool operator ==(const IOPath &other) const;
operator bool() const;
};
/**
* This registry implementation is a fairly reliable, small scale, preference, and app variable database
* Do not consider this as a replacement for a "real" high performance kvp database, it is not, it's a small cache backed document serializer for user profiles
*
* Basic use case:--------------------------------------------------------------
* -> AllocRegistry()
* -> Read("~/Registry/MyApp/DefSettings.dat")
* -> Read("~/Registry/MyApp/UserSettings.dat")
* -> menu.color = GetOrSetKey("theme-color", {.13, .13, .13})
* -> menu.colorChanaged := SetKey("theme-color", color)
* -> app:onExit := SaveAll({})
* -----------------------------------------------------------------------------
*
* Arbitrary write use case:----------------------------------------------------
* -> AllocRegistry()
* -> OpenReadWriteback("~/Registry/MyApp/Settings.dat")
* -> menu.color = GetOrSetKey("theme-color", {.13, .13, .13})
* -> menu.colorChanaged := SetKey("theme-color", color)
* -----------------------------------------------------------------------------
*
* Implementing a protected registry:-------------------------------------------
* -> AllocRegistry()
* -> Read("~/Registry/MyApp/PlayerProfile.dat") will read disk template to the cache, including one "genuine-player-setting"
* -> SetWriteModeCache()
* -> WriteKey("dev-secret-menu-enabled", {0})
* -> LockKey("dev-secret-menu-enabled"), no user write may pass to 'dev-reserved'
* -> SetWriteModeCache()
* -> SetKey("dev-secret-menu-enabled", {1}) originating from an evil script will fail, returning false
* -> SetKey("genuine-ux-setting", {2, 2}) will successfully write to cache
* -> SetKey("genuine-player-setting", {2, 2}) will be assumed to be legitimate, write to cache
* -> GetKey("genuine-ux-setting") will return {2, 2} from the cache
* -> GetKey("genuine-player-setting") will return {2, 2} from the cache
* -> SetKey("some-leftover-magic", {.3, .4, .3}) will successfully write to cache
* -> GetKey("some-leftover-magic") will return {.3, .4, .3} from the cache
* -> OpenSave({})
* -> SetKey("genuine-ux-setting", GetKey("genuine-ux-setting")) will specifically write genuine-ux-setting to disk
* -> var userSetting = GetKey("genuine-player-setting") will return genuine-player-setting from the cache
* -> if (userSetting is inbounds of good constraints) then SetKey("genuine-player-setting", userSetting [=GetKey("genuine-ux-setting")]) will write the cached value back to disk
* -> --
* -> Unload(), some-leftover-magic will be lost
*
*
* -> Prevent malicious usage of development variables while ensuring spurious references work with read only reference values
* -> You may write to the registry the default safe [key:value]s; for instance, zeroing out debug options
* -> You may call `LockKey(...)` to ensure spurious writes, like an unchecked server server command or user request, will not overload the protected variable
*
* -> Some developers may wish to validate the registry dataset before locking the registry,
* -> A general purpose vaildator, schema vaildator, or similar may wish to reset values back to a known good state (`SetWriteModeCache` + `SetKey`) before locking (`SetWriteModeNone`) an otherwise read only database
*
* -----------------------------------------------------------------------------
*
*/
class IRegistry
{
public:
enum class EWriteMode
{
eWriteModeLocked, ///
eWriteModeFileBuffer, /// Write to cache only
eWriteModeFileStream, /// [Default] write database to disk on each set, saving to cache
};
enum class EReadType
{
eClearCacheAndStore,
eStoreNew,
eStoreAll
};
virtual bool Read(const IOPath &path, EReadType read) = 0;
/**
* Puts the registry in read only mode
*/
virtual void SetWriteModeNone() = 0; /// read only, eqiv of ForEach((key) => { LockKey(key) }; SetWriteModeCache();
/**
* Puts the registry in an in memory only mode.
* -> Permit local read/write updates
* -> Never allows SetKeys to write manipulated sates to an IO buffer or stream until sanitized or otherwise explicitly written back
*/
virtual void SetWriteModeCache() = 0;
/**
* Puts the registry in a live write mode
*/
virtual void SetWriteModeStream(const AuOptional<IOPath> &path) = 0;
/**
* Puts the registry in a write-back-like mode
*/
virtual void SetWriteModeBuffered(const AuOptional<IOPath> &path) = 0;
virtual void WriteAllCacheBack() = 0; /// eqiv of ForEach((key) => { WriteKey(key, GetKey(key)); }; writes all updated cache entries back to io buffer or stream
virtual void SaveBuffered() = 0;
/**
* Saves the current state of the registry
*/
virtual void SaveAll(const AuOptional<IOPath> &path) = 0;
/**
* Further calls to SetKeys will; update a database on write, if buffered; or write to a buffer and serialize on flush (`SaveBuffered`)
*/
virtual void OpenSave(const IOPath &path, bool buffered = false) = 0;
/**
* equiv Read(path, EReadType::eClearCacheAndStore)
*/
virtual void OpenRead(const IOPath &path) = 0;
/**
* equiv Read(path, EReadType::eClearCacheAndStore), OpenSave(path, false)
*/
virtual void OpenReadWriteback(const IOPath &path) = 0;
virtual void CloseSave() = 0;
virtual bool KeyExists(const AuString &key, RegistryType &type) = 0;
virtual bool GetOrCreateKey(const AuString &key, const RegistryValue &def, RegistryValue &value) = 0;
/**
* Write a key, to cache or to disk
*/
virtual bool SetKey(const AuString &key, const RegistryValue &value) = 0;
/**
* Read key from cache
*/
virtual bool GetKey(const AuString &key, RegistryValue &value) = 0;
virtual void LockKey(const AuString &str) = 0;
virtual void UnlockKey(const AuString &str) = 0;
/**
* @deprecated
*/
inline void Lock()
{
SetWriteModeCache();
}
/**
* @deprecated
*/
inline void Unlock()
{
OpenSave({}, false);
}
};
}