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