OdbDesignLib
OdbDesign ODB++ Parsing Library
DesignCache.cpp
1 #include "DesignCache.h"
2 #include "DesignCache.h"
3 #include "ArchiveExtractor.h"
4 #include "DesignCache.h"
5 #include "Logger.h"
6 #include <exception>
7 #include <filesystem>
8 #include <vector>
9 #include "../FileModel/Design/FileArchive.h"
10 #include <memory>
11 #include "../ProductModel/Design.h"
12 #include <iosfwd>
13 #include <string>
14 #include <type_traits>
15 #include <StringVector.h>
16 
17 using namespace Utils;
18 using namespace std::filesystem;
19 
20 namespace Odb::Lib::App
21 {
22  DesignCache::DesignCache(std::string directory) :
23  m_directory(std::move(directory))
24  {
25  }
26 
27  DesignCache::~DesignCache()
28  {
29  Clear();
30  }
31 
32  std::shared_ptr<ProductModel::Design> DesignCache::GetDesign(const std::string& designName)
33  {
34  auto findIt = m_designsByName.find(designName);
35  if (findIt == m_designsByName.end())
36  {
37  auto pDesign = LoadDesign(designName);
38  return pDesign;
39  }
40 
41  return m_designsByName[designName];
42  }
43 
44  std::shared_ptr<FileModel::Design::FileArchive> DesignCache::GetFileArchive(const std::string& designName)
45  {
46  std::stringstream ss;
47  ss << "Retrieving design \"" << designName << "\" from cache... ";
48  loginfo(ss.str());
49 
50  auto findIt = m_fileArchivesByName.find(designName);
51  if (findIt == m_fileArchivesByName.end())
52  {
53  loginfo("Not found in cache, attempting to load from file...");
54 
55  auto pFileArchive = LoadFileArchive(designName);
56  if (pFileArchive == nullptr)
57  {
58  logwarn("Failed loading from file");
59  }
60  else
61  {
62  loginfo("Loaded from file");
63  }
64  return pFileArchive;
65  }
66  else
67  {
68  loginfo("Found. Returning from cache.");
69  }
70 
71  return m_fileArchivesByName[designName];
72  }
73 
74  void DesignCache::AddFileArchive(const std::string& designName, std::shared_ptr<FileModel::Design::FileArchive> fileArchive, bool save)
75  {
76  m_fileArchivesByName[designName] = fileArchive;
77  if (save)
78  {
79  SaveFileArchive(designName);
80  }
81  }
82 
83  bool DesignCache::SaveFileArchive(const std::string& designName)
84  {
85  auto fileArchive = GetFileArchive(designName);
86  if (fileArchive != nullptr)
87  {
88  return fileArchive->SaveFileModel(m_directory);
89  }
90  return false;
91  }
92 
93  std::vector<std::string> DesignCache::getLoadedDesignNames(const std::string& filter) const
94  {
95  std::vector<std::string> loadedDesigns;
96  for (const auto& kv : m_designsByName)
97  {
98  loadedDesigns.push_back(kv.first);
99  }
100  return loadedDesigns;
101  }
102 
103  std::vector<std::string> DesignCache::getLoadedFileArchiveNames(const std::string& filter) const
104  {
105  std::vector<std::string> loadedFileArchives;
106  for (const auto& kv : m_fileArchivesByName)
107  {
108  loadedFileArchives.push_back(kv.first);
109  }
110  return loadedFileArchives;
111  }
112 
113  std::vector<std::string> DesignCache::getUnloadedDesignNames(const std::string& filter) const
114  {
115  std::vector<std::string> unloadedNames;
116 
117  //try
118  {
119  path dir(m_directory);
120  for (const auto& entry : directory_iterator(dir))
121  {
122  if (entry.is_regular_file())
123  {
124  unloadedNames.push_back(entry.path().stem().string());
125  }
126  }
127  }
128  //catch (std::filesystem::filesystem_error& fe)
129  //{
130  // logexception(fe);
131  // // re-throw it so we get a HTTP 500 response to the client
132  // throw fe;
133  //}
134 
135  return unloadedNames;
136  }
137 
138  int DesignCache::loadAllFileArchives(bool stopOnError)
139  {
140  int loaded = 0;
141 
142  for (const auto& entry : directory_iterator(m_directory))
143  {
144  if (entry.is_regular_file())
145  {
146  if (ArchiveExtractor::IsArchiveTypeSupported(entry.path().filename()))
147  {
148  try
149  {
150  auto pFileArchive = LoadFileArchive(entry.path().stem().string());
151  if (pFileArchive != nullptr)
152  {
153  loaded++;
154  }
155  }
156  catch (std::exception& e)
157  {
158  // continue if we encounter an error loading one
159  logexception(e);
160  if (stopOnError) throw e;
161  }
162  }
163  }
164  }
165 
166  return loaded;
167  }
168 
169  int DesignCache::loadAllDesigns(bool stopOnError)
170  {
171  int loaded = 0;
172 
173  for (const auto& entry : directory_iterator(m_directory))
174  {
175  if (entry.is_regular_file())
176  {
177  if (ArchiveExtractor::IsArchiveTypeSupported(entry.path().filename()))
178  {
179  try
180  {
181  auto pDesign = LoadDesign(entry.path().stem().string());
182  if (pDesign != nullptr)
183  {
184  loaded++;
185  }
186  }
187  catch (std::exception& e)
188  {
189  logexception(e);
190  if (stopOnError)
191  {
192  throw e;
193  }
194  }
195  }
196  }
197  }
198 
199  return loaded;
200  }
201 
202  int DesignCache::loadFileArchives(const StringVector& names)
203  {
204  int loaded = 0;
205 
206  for (const auto& name : names)
207  {
208  try
209  {
210  auto pFileArchive = LoadFileArchive(name);
211  if (pFileArchive != nullptr)
212  {
213  loaded++;
214  }
215  }
216  catch (std::exception& e)
217  {
218  // continue on error
219  logexception(e);
220  }
221  }
222 
223  return loaded;
224  }
225 
226  int DesignCache::loadDesigns(const StringVector& names)
227  {
228  int loaded = 0;
229 
230  for (const auto& name : names)
231  {
232  try
233  {
234  auto pDesign = LoadDesign(name);
235  if (pDesign != nullptr)
236  {
237  loaded++;
238  }
239  }
240  catch (std::exception& e)
241  {
242  // continue on error
243  logexception(e);
244  }
245  }
246 
247  return loaded;
248  }
249 
250  void DesignCache::setDirectory(const std::string& directory)
251  {
252  m_directory = directory;
253  }
254 
255  const std::string& DesignCache::getDirectory() const
256  {
257  return m_directory;
258  }
259 
260  void DesignCache::Clear()
261  {
262  m_fileArchivesByName.clear();
263  m_designsByName.clear();
264  }
265 
266  std::shared_ptr<ProductModel::Design> DesignCache::LoadDesign(const std::string& designName)
267  {
268  for (const auto& entry : directory_iterator(m_directory))
269  {
270  if (entry.is_regular_file())
271  {
272  if (entry.path().stem() == designName)
273  {
274  auto pFileModel = GetFileArchive(designName);
275  if (pFileModel != nullptr)
276  {
277  auto pDesign = std::make_shared<ProductModel::Design>();
278  if (pDesign->Build(pFileModel))
279  {
280  // overwrite any existing design with the same name
281  m_designsByName[designName] = pDesign;
282  return pDesign;
283  }
284  else
285  {
286  break;
287  }
288  }
289  else
290  {
291  break;
292  }
293  }
294  }
295  }
296 
297  return nullptr;
298  }
299 
300  std::shared_ptr<FileModel::Design::FileArchive> DesignCache::LoadFileArchive(const std::string& designName)
301  {
302  auto fileFound = false;
303 
304  // skip inaccessible files and do not follow symlinks
305  const auto options = directory_options::skip_permission_denied;
306  for (const auto& entry : directory_iterator(m_directory, options))
307  {
308  if (entry.is_regular_file())
309  {
310  if (entry.path().stem() == designName)
311  {
312  fileFound = true;
313 
314  loginfo("file found: [" + entry.path().string() + "], attempting to parse...");
315 
316  auto pFileArchive = std::make_shared<FileModel::Design::FileArchive>(entry.path().string());
317  if (pFileArchive->ParseFileModel())
318  {
319  // overwrite any existing file archive with the same name
320  m_fileArchivesByName[designName] = pFileArchive;
321  return pFileArchive;
322  }
323  else
324  {
325  break;
326  }
327  }
328  }
329  }
330 
331  if (!fileFound)
332  {
333  logwarn("Failed to find file for design \"" + designName + "\"");
334  }
335 
336  return nullptr;
337  }
338 }