blob: 81a6a4d484d389c4338c33be828a48b4443bbe84 [file] [log] [blame]
#pragma once
#include <nlohmann/json.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/lg2.hpp>
#include <format>
#include <fstream>
#include <ranges>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
class JsonSerializer
{
public:
JsonSerializer(std::string path, nlohmann::json js = nlohmann::json()) :
mfaConfPath(path), jsonData(std::move(js))
{}
inline auto stringSplitter()
{
return std::views::split('/') | std::views::transform([](auto&& sub) {
return std::string(sub.begin(), sub.end());
});
}
nlohmann::json makeJson(const std::string& key, const std::string& value)
{
auto keys = key | stringSplitter();
std::vector v(keys.begin(), keys.end());
auto rv = v | std::views::reverse;
nlohmann::json init;
init[rv.front()] = value;
auto newJson = std::reduce(rv.begin() + 1, rv.end(), init,
[](auto sofar, auto currentKey) {
nlohmann::json j;
j[currentKey] = sofar;
return j;
});
return newJson;
}
std::optional<nlohmann::json> getLeafNode(const std::string_view keyPath)
{
auto keys = keyPath | stringSplitter();
nlohmann::json current = jsonData;
for (auto key : keys)
{
if (!current.contains(key))
{
return std::nullopt;
}
current = current[key];
}
return current;
}
void serialize(std::string key, const std::string value)
{
jsonData.merge_patch(makeJson(key, value));
}
template <typename T>
void deserialize(std::string key, T& value)
{
auto leaf = getLeafNode(key);
if (leaf)
{
value = *leaf;
}
}
void erase(std::string key)
{
if (jsonData.contains(key))
{
jsonData.erase(key);
}
}
bool store()
{
std::filesystem::path dir =
std::filesystem::path(mfaConfPath).parent_path();
// Check if the directory exists, and create it if it does not
if (!dir.string().empty() && !std::filesystem::exists(dir))
{
std::error_code ec;
if (!std::filesystem::create_directories(dir, ec))
{
lg2::error("Unable to create directory {DIR}", "DIR",
dir.string());
return false;
}
}
std::ofstream file(mfaConfPath.data());
if (file.is_open())
{
file << jsonData.dump(4); // Pretty print with 4 spaces
file.close();
return true;
}
else
{
lg2::error("Unable to open file {FILENAME}", "FILENAME",
mfaConfPath);
return false;
}
}
void load()
{
std::ifstream file(mfaConfPath.data());
if (file.is_open())
{
file >> jsonData;
file.close();
}
else
{
lg2::error("Unable to open file for reading {FILENAME}", "FILENAME",
mfaConfPath);
}
}
private:
const std::string mfaConfPath;
nlohmann::json jsonData;
};