diff --git a/src/resource/meson.build b/src/resource/meson.build new file mode 100644 index 0000000..bc32862 --- /dev/null +++ b/src/resource/meson.build @@ -0,0 +1,40 @@ +# Define the library +resourceManager_sources = files( + 'private/resourceManager.cpp', + 'private/resourceManagerTypes.cpp' +) + +resourceManager_headers = files( + 'public/resourceManager.h', + 'public/resourceManagerTypes.h' +) + +dependencies = [ + yaml_cpp_dep, + opatio_dep, + eos_dep, + quill_dep, + config_dep, + probe_dep, + mfem_dep, + macros_dep, + meshio_dep +] + +libResourceHeader_dep = declare_dependency(include_directories: include_directories('public')) +# Define the libresourceManager library so it can be linked against by other parts of the build system +libresourceManager = static_library('resourceManager', + resourceManager_sources, + include_directories: include_directories('public'), + cpp_args: ['-fvisibility=default'], + dependencies: dependencies, + install : true) + +resourceManager_dep = declare_dependency( + include_directories: include_directories('public'), + link_with: libresourceManager, + dependencies: dependencies +) + +# Make headers accessible +install_headers(resourceManager_headers, subdir : '4DSSE/resource') \ No newline at end of file diff --git a/src/resource/private/resourceManager.cpp b/src/resource/private/resourceManager.cpp new file mode 100644 index 0000000..ebbe62d --- /dev/null +++ b/src/resource/private/resourceManager.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +#include "quill/LogMacros.h" + +#include "resourceManager.h" +#include "resourceManagerTypes.h" +#include "debug.h" + +#include "config.h" + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +ResourceManager::ResourceManager() { + std::string defaultDataDir = TOSTRING(DATA_DIR); + m_dataDir = m_config.get("Data:Dir", defaultDataDir); + // -- Get the index file path using filesytem to make it a system safe path + std::string indexFilePath = m_dataDir + "/index.yaml"; + std::filesystem::path indexFile(indexFilePath); + + m_resourceConfig.loadConfig(indexFile.string()); + std::vector assets = m_resourceConfig.keys(); + for (auto key : assets ) { + load(key); + } +} + + +std::vector ResourceManager::getAvaliableResources() { + std::vector resources; + resources = m_resourceConfig.keys(); + return resources; +} + +const Resource& ResourceManager::getResource(const std::string &name) const { + auto it = m_resources.find(name); + if (it != m_resources.end()) { + return it->second; + } + throw std::runtime_error("Resource " + name + " not found"); +} + + +bool ResourceManager::loadResource(std::string& name) { + return load(name); +} + +bool ResourceManager::load(const std::string& name) { + const std::string resourcePath = m_dataDir + "/" + m_resourceConfig.get(name); + std::filesystem::path resourceFile(resourcePath); + if (!std::filesystem::exists(resourceFile)) { + LOG_ERROR(m_logger, "Resource file not found: {}", resourceFile.string()); + return false; + } + LOG_INFO(m_logger, "Loading resource: {}", resourceFile.string()); + if (m_resources.find(name) != m_resources.end()) { + LOG_INFO(m_logger, "Resource already loaded: {}", name); + return true; + } + Resource resource = createResource(name, resourcePath); + m_resources[name] = std::move(resource); + // -- Check if the resource is already in the map + return true; +} + diff --git a/src/resource/private/resourceManagerTypes.cpp b/src/resource/private/resourceManagerTypes.cpp new file mode 100644 index 0000000..98593bf --- /dev/null +++ b/src/resource/private/resourceManagerTypes.cpp @@ -0,0 +1,41 @@ +#include + +#include "resourceManagerTypes.h" +#include "opatIO.h" +#include "meshIO.h" +#include "eosIO.h" + +#include "debug.h" + +std::string getFirstSegment(const std::string& input) { + size_t pos = input.find(':'); + if (pos == std::string::npos) { + // No colon found, return the entire string + return input; + } else { + // Return substring from start to the position of the first colon + return input.substr(0, pos); + } +} + + +Resource createResource(const std::string& type, const std::string& path) { + static const std::unordered_map> factoryMap = { + {"opac", [](const std::string& p) { return Resource( + std::make_unique(p)); + }}, + {"mesh", [](const std::string& p) { return Resource( + std::make_unique(p)); + }}, + {"eos", [](const std::string& p) { return Resource( + std::make_unique(p)); + }} + // Add more mappings as needed + }; + auto it = factoryMap.find(getFirstSegment(type)); + if (it != factoryMap.end()) { + return it->second(path); + } else { + throw std::invalid_argument("Unknown resource type: " + type); + } +} \ No newline at end of file diff --git a/src/resource/public/resourceManager.h b/src/resource/public/resourceManager.h new file mode 100644 index 0000000..b304d4c --- /dev/null +++ b/src/resource/public/resourceManager.h @@ -0,0 +1,47 @@ +#ifndef RESOURCE_MANAGER_H +#define RESOURCE_MANAGER_H + +#include +#include +#include +#include + +#include "resourceManagerTypes.h" +#include "config.h" +#include "probe.h" +#include "quill/LogMacros.h" + +class ResourceManager { +private: + ResourceManager(); + ResourceManager(const ResourceManager&) = delete; + ResourceManager& operator=(const ResourceManager&) = delete; + Config& m_config = Config::getInstance(); + Probe::LogManager& m_logManager = Probe::LogManager::getInstance(); + quill::Logger* m_logger = m_logManager.getLogger("log"); + + Config m_resourceConfig; + std::string m_dataDir; + std::unordered_map m_resources; + + bool load(const std::string& name); + +public: + static ResourceManager& getInstance() { + static ResourceManager instance; + return instance; + } + + std::vector getAvaliableResources(); + + const Resource& getResource(const std::string &name) const; + + bool loadResource(std::string& name); + + std::unordered_map loadAllResources(); + + +}; + + +#endif // RESOURCE_MANAGER_H \ No newline at end of file diff --git a/src/resource/public/resourceManagerTypes.h b/src/resource/public/resourceManagerTypes.h new file mode 100644 index 0000000..e0b343e --- /dev/null +++ b/src/resource/public/resourceManagerTypes.h @@ -0,0 +1,22 @@ +#ifndef RESOURCE_MANAGER_TYPES_H +#define RESOURCE_MANAGER_TYPES_H + +#include +#include + +#include "opatIO.h" +#include "helm.h" +#include "meshIO.h" +#include "eosIO.h" + +// -- Valid resource types +using Resource = std::variant< + std::unique_ptr, + std::unique_ptr, + std::unique_ptr>; + + +std::string getFirstSegment(const std::string& input); +Resource createResource(const std::string& type, const std::string& path); + +#endif // RESOURCE_MANAGER_TYPES_H \ No newline at end of file diff --git a/tests/resource/meson.build b/tests/resource/meson.build new file mode 100644 index 0000000..75571d8 --- /dev/null +++ b/tests/resource/meson.build @@ -0,0 +1,24 @@ +# Test files for const +test_sources = [ + 'resourceManagerTest.cpp', +] + +foreach test_file : test_sources + exe_name = test_file.split('.')[0] + message('Building test: ' + exe_name) + + # Create an executable target for each test + test_exe = executable( + exe_name, + test_file, + dependencies: [gtest_dep, resourceManager_dep, gtest_main, macros_dep], + include_directories: include_directories('../../src/resource/public'), + install_rpath: '@loader_path/../../src' # Ensure runtime library path resolves correctly + ) + + # Add the executable as a test + test( + exe_name, + test_exe, + env: ['MESON_SOURCE_ROOT=' + meson.project_source_root(), 'MESON_BUILD_ROOT=' + meson.project_build_root()]) +endforeach diff --git a/tests/resource/resourceManagerTest.cpp b/tests/resource/resourceManagerTest.cpp new file mode 100644 index 0000000..d0264d7 --- /dev/null +++ b/tests/resource/resourceManagerTest.cpp @@ -0,0 +1,61 @@ +#include +#include "resourceManager.h" +#include "config.h" +#include "eosIO.h" +#include "helm.h" +#include "resourceManagerTypes.h" + +#include +#include +#include +#include + +#include "debug.h" + +/** + * @file configTest.cpp + * @brief Unit tests for the resourceManager class. + */ + + +std::string TEST_CONFIG = std::string(getenv("MESON_SOURCE_ROOT")) + "/tests/testsConfig.yaml"; +/** + * @brief Test suite for the resourceManager class. + */ +class resourceManagerTest : public ::testing::Test {}; + +/** + * @brief Test the constructor of the resourceManager class. + */ +TEST_F(resourceManagerTest, constructor) { + Config::getInstance().loadConfig(TEST_CONFIG); + EXPECT_NO_THROW(ResourceManager::getInstance()); +} + +TEST_F(resourceManagerTest, getAvaliableResources) { + Config::getInstance().loadConfig(TEST_CONFIG); + ResourceManager& rm = ResourceManager::getInstance(); + std::vector resources = rm.getAvaliableResources(); + std::set expected = {"eos:helm", "mesh:sphere"}; + std::set actual(resources.begin(), resources.end()); + EXPECT_EQ(expected, actual); +} + +TEST_F(resourceManagerTest, getResource) { + Config::getInstance().loadConfig(TEST_CONFIG); + ResourceManager& rm = ResourceManager::getInstance(); + std::string name = "eos:helm"; + const Resource &r = rm.getResource(name); + // BREAKPOINT(); + const auto &eos = std::get>(r); + EXPECT_EQ("helm", eos->getFormat()); + EOSTable &table = eos->getTable(); + + // -- Extract the Helm table from the EOSTable + helmholtz::HELMTable &helmTable = *std::get>(table); + EXPECT_DOUBLE_EQ(helmTable.f[0][0], -1692098915534.8142); + + EXPECT_THROW(rm.getResource("opac:GS98:high:doesNotExist"), std::runtime_error); +} + +