1#include "DesignCache.h"
2#include "ArchiveExtractor.h"
8#include "../FileModel/Design/FileArchive.h"
10#include "../ProductModel/Design.h"
14#include <StringVector.h>
15#include <shared_mutex>
18using namespace std::filesystem;
20namespace Odb::Lib::App
22 DesignCache::DesignCache(std::string directory) :
23 m_directory(std::move(directory))
25 ensureDirectoryExists();
28 DesignCache::~DesignCache()
33 std::shared_ptr<ProductModel::Design> DesignCache::GetDesign(
const std::string& designName)
37 std::shared_lock readLock(m_cacheMutex);
38 auto findIt = m_designsByName.find(designName);
39 if (findIt != m_designsByName.end())
41 return findIt->second;
46 auto pDesign = LoadDesign(designName);
49 if (pDesign !=
nullptr)
51 std::unique_lock writeLock(m_cacheMutex);
52 auto findIt = m_designsByName.find(designName);
53 if (findIt != m_designsByName.end())
55 return findIt->second;
57 m_designsByName[designName] = pDesign;
62 std::shared_ptr<FileModel::Design::FileArchive> DesignCache::GetFileArchive(
const std::string& designName)
65 ss <<
"Retrieving design \"" << designName <<
"\" from cache... ";
70 std::shared_lock readLock(m_cacheMutex);
71 auto findIt = m_fileArchivesByName.find(designName);
72 if (findIt != m_fileArchivesByName.end())
74 logdebug(
"Found. Returning from cache.");
75 return findIt->second;
79 loginfo(
"Not found in cache, attempting to load from file...");
82 auto pFileArchive = LoadFileArchive(designName);
84 if (pFileArchive ==
nullptr)
86 logwarn(
"Failed loading from file");
90 loginfo(
"Loaded from file");
93 std::unique_lock writeLock(m_cacheMutex);
94 auto findIt = m_fileArchivesByName.find(designName);
95 if (findIt != m_fileArchivesByName.end())
97 logdebug(
"Found. Returning from cache (loaded by another thread).");
98 return findIt->second;
100 m_fileArchivesByName[designName] = pFileArchive;
105 void DesignCache::AddFileArchive(
const std::string& designName, std::shared_ptr<FileModel::Design::FileArchive> fileArchive,
bool save)
107 std::unique_lock writeLock(m_cacheMutex);
108 m_fileArchivesByName[designName] = fileArchive;
114 SaveFileArchive(designName);
118 bool DesignCache::SaveFileArchive(
const std::string& designName)
120 auto fileArchive = GetFileArchive(designName);
121 if (fileArchive !=
nullptr)
123 std::string directory;
125 std::shared_lock readLock(m_cacheMutex);
126 directory = m_directory;
128 return fileArchive->SaveFileModel(directory);
133 std::vector<std::string> DesignCache::getLoadedDesignNames(
const std::string& filter)
const
135 std::shared_lock readLock(m_cacheMutex);
136 std::vector<std::string> loadedDesigns;
137 for (
const auto& kv : m_designsByName)
139 loadedDesigns.push_back(kv.first);
141 return loadedDesigns;
144 std::vector<std::string> DesignCache::getLoadedFileArchiveNames(
const std::string& filter)
const
146 std::shared_lock readLock(m_cacheMutex);
147 std::vector<std::string> loadedFileArchives;
148 for (
const auto& kv : m_fileArchivesByName)
150 loadedFileArchives.push_back(kv.first);
152 return loadedFileArchives;
155 std::vector<std::string> DesignCache::getUnloadedDesignNames(
const std::string& filter)
const
157 std::string directory;
159 std::shared_lock readLock(m_cacheMutex);
160 directory = m_directory;
163 std::vector<std::string> unloadedNames;
168 for (
const auto& entry : directory_iterator(dir))
170 if (entry.is_regular_file())
172 unloadedNames.push_back(entry.path().stem().string());
183 return unloadedNames;
186 int DesignCache::loadAllFileArchives(
bool stopOnError)
190 std::string directory;
192 std::shared_lock readLock(m_cacheMutex);
193 directory = m_directory;
196 for (
const auto& entry : directory_iterator(directory))
198 if (entry.is_regular_file())
200 if (ArchiveExtractor::IsArchiveTypeSupported(entry.path().filename()))
204 auto pFileArchive = GetFileArchive(entry.path().stem().string());
205 if (pFileArchive !=
nullptr)
210 catch (std::exception& e)
214 if (stopOnError)
throw e;
223 int DesignCache::loadAllDesigns(
bool stopOnError)
227 std::string directory;
229 std::shared_lock readLock(m_cacheMutex);
230 directory = m_directory;
233 for (
const auto& entry : directory_iterator(directory))
235 if (entry.is_regular_file())
237 if (ArchiveExtractor::IsArchiveTypeSupported(entry.path().filename()))
241 auto pDesign = GetDesign(entry.path().stem().string());
242 if (pDesign !=
nullptr)
247 catch (std::exception& e)
262 int DesignCache::loadFileArchives(
const StringVector& names)
266 for (
const auto& name : names)
270 auto pFileArchive = GetFileArchive(name);
271 if (pFileArchive !=
nullptr)
276 catch (std::exception& e)
286 int DesignCache::loadDesigns(
const StringVector& names)
290 for (
const auto& name : names)
294 auto pDesign = GetDesign(name);
295 if (pDesign !=
nullptr)
300 catch (std::exception& e)
310 void DesignCache::setDirectory(
const std::string& directory)
312 std::unique_lock writeLock(m_cacheMutex);
313 m_directory = directory;
316 std::string DesignCache::getDirectory()
const
318 std::shared_lock readLock(m_cacheMutex);
322 void DesignCache::Clear()
324 std::unique_lock writeLock(m_cacheMutex);
325 m_fileArchivesByName.clear();
326 m_designsByName.clear();
329 std::shared_ptr<ProductModel::Design> DesignCache::LoadDesign(
const std::string& designName)
333 std::string directory;
335 std::shared_lock readLock(m_cacheMutex);
336 directory = m_directory;
339 for (
const auto& entry : directory_iterator(directory))
341 if (entry.is_regular_file())
343 if (entry.path().stem() == designName)
346 auto pFileModel = GetFileArchive(designName);
347 if (pFileModel !=
nullptr)
349 auto pDesign = std::make_shared<ProductModel::Design>();
350 if (pDesign->Build(pFileModel))
370 std::shared_ptr<FileModel::Design::FileArchive> DesignCache::LoadFileArchive(
const std::string& designName)
374 auto fileFound =
false;
376 std::string directory;
378 std::shared_lock readLock(m_cacheMutex);
379 directory = m_directory;
383 const auto options = directory_options::skip_permission_denied;
384 for (
const auto& entry : directory_iterator(directory, options))
386 if (entry.is_regular_file())
388 if (entry.path().stem() == designName)
392 loginfo(
"file found: [" + entry.path().string() +
"], attempting to parse...");
394 auto pFileArchive = std::make_shared<FileModel::Design::FileArchive>(entry.path().string());
395 if (pFileArchive->ParseFileModel())
407 throw std::runtime_error(
408 "Failed to load design \"" + designName +
"\": could not extract or parse archive");
415 logwarn(
"Failed to find file for design \"" + designName +
"\"");
417 logdebug(
"Listing all files in directory: " + directory);
418 for (
const auto& entry : directory_iterator(directory, options))
420 if (entry.is_regular_file())
422 logdebug(
"Found file: " + entry.path().filename().string() +
" (stem: " + entry.path().stem().string() +
")");
430 void DesignCache::ensureDirectoryExists()
const
432 if (!std::filesystem::exists(m_directory))
437 std::filesystem::create_directories(m_directory);
439 catch (
const std::exception& e)
441 std::string msg =
"Failed to create design cache directory: " + m_directory;
442 logexception_msg(e, msg);