DeviceAtlas C++ interface Api
devatlas.h
1 #ifndef DEVATLAS_CPP_H
2 #define DEVATLAS_CPP_H
3 #if !defined(APINOCACHE) && !defined(XXH_DATLAS)
4 #include "import/cache.hpp"
5 #include "import/lru_cache_policy.hpp"
6 #define XXH_NAMESPACE DATLAS
7 #define XXH_IMPLEMENTATION
8 #define XXH_INLINE_ALL
9 #if defined(__x86_64__)
10 #define XXH_VECTOR XXH_SSE2
11 #elif defined(__aarch64__)
12 #define XXH_VECTOR XXH_NEON
13 #endif
14 #include "import/xxhash.h"
15 #define XXH_DATLAS
16 #endif
17 #include "dac.h"
18 #include "dadwcurl.h"
19 #include "dadwarc.h"
20 #include "ci.h"
21 #include "util.h"
22 
23 
24 /*
25  * Copyright (c) DeviceAtlas Limited 2024. All Rights Reserved.
26  */
27 
28 namespace com {
32 namespace deviceatlas {
36 namespace da {
37  inline size_t
38  p_read_fn(void *a, size_t max, char *buf) {
39  std::ifstream *s = static_cast<std::ifstream *>(a);
40  s->read(buf, max);
41  return s->gcount();
42  }
43 
44  inline da_status_t
45  p_setpos_fn(void *a, off_t pos) {
46  std::ifstream *s = static_cast<std::ifstream *>(a);
47  s->seekg(pos, s->beg);
48  return (s->tellg() == -1 ? DA_SYS : DA_OK);
49  }
50 
51  class DeliveryContext;
52  class HttpHeaders;
53 #if !defined(APINOCACHE)
54  using DaCachePair = std::pair<std::map<size_t, PVPair>, std::map<std::string, size_t>>;
55  using DaCache = caches::fixed_sized_cache<XXH64_hash_t, DaCachePair, caches::LRUCachePolicy>;
56 #endif
57 
58  constexpr const char *const defaultCl = "DAPROPS";
59  static da_property_decl_t defaultep[1] = {{nullptr, da_type_t(0)}};
60 
66  struct DeviceDwConfig {
67  std::string path;
68  std::string url;
69  DwProcFn dwproc;
70  DwExtractFn dwextract;
71  DwNotifyFn dwnotify;
72  DwLogFn dwlog;
73  DwMode mode;
74  dw_config inst;
75  DeviceDwConfig(std::string _path = std::string(), std::string _url = std::string(),
76  std::chrono::time_point<std::chrono::system_clock> *_sc = nullptr,
77  da_property_decl_t *_ep = defaultep, DwProcFn _dwproc = nullptr,
78  DwExtractFn _dwextract = nullptr, DwNotifyFn _dwnotify = nullptr,
79  DwLogFn _dwlog = nullptr) :
80  path(_path)
81  , url(_url)
82  , dwproc(_dwproc)
83  , dwextract(_dwextract)
84  , dwnotify(_dwnotify)
85  , dwlog(_dwlog)
86  , mode(DwNone) {
87  if (path != "" && url != "") {
88  mode = DwSgl;
89  if (_sc) {
90  auto time = std::chrono::system_clock::to_time_t(*_sc);
91  gmtime_r(&time, &inst.info.rtm);
92  inst.info.chksum = 1;
93  inst.info.reload = 1;
94  inst.info.datatm = 1;
95  mode = DwSch;
96  }
97 
98  inst.info.url = strdup(url.c_str());
99  inst.info.path = strdup(path.c_str());
100  inst.ep = _ep;
101 
102  if (dwproc)
103  inst.dwproc = *dwproc.target<dw_proc_fn>();
104  else
105  inst.dwproc = curldwproc;
106  if (dwextract)
107  inst.dwextract = *dwextract.target<dw_extract_fn>();
108  else
109  inst.dwextract = dadwextract;
110  if (dwnotify)
111  inst.dwnotify_n = *dwnotify.target<dw_notify_n_fn>();
112  if (dwlog)
113  inst.dwlog = *dwlog.target<dw_log_fn>();
114  }
115  }
116  };
117 
122  struct DeviceConfig {
123  const char *clname;
124  DeviceDwConfig dwcfg;
125  da_config inst;
126  size_t cache_size;
127  DeviceConfig(const char *_clname = defaultCl, size_t _cache_size = 0) :
128  clname(_clname), cache_size(_cache_size) {
129  memset(&inst, 0, sizeof(inst));
130  }
131  };
132 
139  friend class DeliveryContext;
140  friend class HttpHeaders;
141  size_t len;
142  da_dwatlas_t inst;
143  DeviceConfig cfg;
144 #if !defined(APINOCACHE)
145  std::shared_ptr<DaCache> ccache;
146 #endif
147  public:
148  DeviceAtlas(const DeviceConfig &_cfg = DeviceConfig(), da_read_fn _rfn = &p_read_fn, da_setpos_fn _sfn = &p_setpos_fn) :
150  , cfg(_cfg) {
151  da_init();
152  inst.dcfg = cfg.dwcfg.inst;
153  inst.rfn = _rfn;
154  inst.posfn = _sfn;
155 #if !defined(APINOCACHE)
156  if (cfg.cache_size > 0) {
157  if (cfg.cache_size > DA_CACHE_MAX)
158  cfg.cache_size = DA_CACHE_MAX;
159  ccache = std::shared_ptr<DaCache>(new DaCache(cfg.cache_size, caches::LRUCachePolicy<XXH64_hash_t>()));
160  } else {
161  ccache = nullptr;
162  }
163 #endif
164  }
165  ~DeviceAtlas();
166  void loadDataFromFile(const char *) override;
167  void loadDataFromMem(const char *) noexcept(false);
168  void download() noexcept(false);
169  time_t getDataGeneration() const noexcept;
170  std::string getDataGenerationIso8601() const noexcept;
171  bool dump(const char *);
172  const da_dwatlas_t atlas() { return inst; }
173  };
174 
179  class HttpHeaders {
180  friend class DeviceAtlas;
181  friend class DeliveryContext;
182  const HeaderMap &map;
183  size_t evl;
184  bool set;
185 #if !defined(APINOCACHE)
186  uint64_t h;
187 #endif
188  std::array<da_evidence_t, 64> ev;
189  public:
190  HttpHeaders(const HttpHeaders &);
191  HttpHeaders(const HeaderMap &);
192  HttpHeaders(const DeviceAtlas &, const HeaderMap &);
193  };
194 
202  friend class DeviceAtlas;
203  friend class HttpHeaders;
204  da_deviceinfo_t dv;
205  bool lkp;
206 #if !defined(APINOCACHE)
207  std::shared_ptr<DaCache> ccache;
208  size_t cache_size;
209  uint64_t h;
210  std::mutex mtx;
211 #endif
212  std::map<size_t, PVPair> ires;
213  void pvpfill() const {
214  if (!empty() && vres.size() == 0) {
215  size_t i = 0;
216  for (auto e = begin(); e != end(); ++e, ++i) {
217  auto it = *e;
218  if (!it.first) {
219  Exception e;
220  e << "invalid property at ";
221  e << i;
222  __throw(e);
223  }
224  }
225  }
226  }
227  public:
228  DeliveryContext(const DeviceAtlas &, const HttpHeaders &);
233  DeliveryContext(const DeviceAtlas &, std::string &id, std::string &cs = emptys);
234 #if __cplusplus >= 201703L
235 
239  DeliveryContext(const DeviceAtlas &, std::string_view id, std::optional<std::string_view> cs);
240 #endif
241  ~DeliveryContext();
242  class const_iterator;
243  friend class const_iterator;
244  size_t sz;
245 
247  private:
248  DeliveryContext &props;
249  size_t idx;
250  size_t propcount;
251  friend class DeliveryContext;
252  PVPair builtin;
253  const PVPair propdict() const;
254  public:
255  const_iterator(DeliveryContext &props_, size_t idx_);
256  const PVPair operator * () const;
257  const PVPair *operator -> ();
258  const_iterator &operator++();
259  bool operator==(const const_iterator &rhs) const;
260  bool operator!=(const const_iterator &rhs) const;
261  };
262 
263  const_iterator begin() const;
264  const_iterator end() const;
265  const_iterator find(const Property &) const;
266  const_iterator find(const char *) const;
267  size_t size() const { return sz; }
268  bool empty() const { return size() == 0; }
269  bool contains(const char *propname) {
270  return find(propname) != this->end();
271  }
275  template<typename T>
276  bool contains(const char *propname, const T value) {
277  static_assert(std::is_integral<T>::value, "invalid type");
278  auto p = find(propname);
279  if (p == this->end())
280  return false;
281  return p->second->u.longval == value;
282  }
286  const Value *operator[](const Property &) const noexcept;
290  const Value *operator[](const char *) const noexcept;
291 #if __cplusplus >= 201703L
292 
295  std::optional<const Value *> operator[](std::string_view) const noexcept;
296 #endif
297  };
298  template<>
299  inline bool DeliveryContext::contains<const char *>(const char *propname, const char *value) {
300  auto p = find(propname);
301  if (p == this->end())
302  return false;
303  return strcmp(p->second->u.strval, value) == 0;
304  }
305 }
306 
310 namespace ci {
311  class DeliveryContext;
312  class HttpHeaders;
313  struct dropreq {
314  void operator()(ci_searchrequest_t *o) const {
315  delete []o;
316  }
317  };
318 
319  struct dropres {
320  void operator()(ci_searchresult_t *o) const {
321  delete []o;
322  }
323  };
324 
329  class Carrier : public CommonDeviceAtlas {
330  friend class DeliveryContext;
331  friend class HttpHeaders;
332  std::shared_ptr<ci_atlas_t> inst;
333  public:
334  Carrier() : CommonDeviceAtlas() {
335  ci_init();
336  auto ptr = new char[ci_atlas_size()];
337  inst = std::shared_ptr<ci_atlas_t>(new (ptr) ci_atlas_t, [](ci_atlas_t *o) { delete [] o; });
338  }
339  ~Carrier();
340  void loadDataFromFile(const char *) override;
341  };
342 
347  class HttpHeaders {
348  friend class Carrier;
349  friend class DeliveryContext;
350  const HeaderMap &map;
351  std::unique_ptr<ci_searchrequest_t, dropreq> ev;
352  public:
353  HttpHeaders(const Carrier &, const HeaderMap &);
354  ~HttpHeaders();
355  };
356 
364  friend class Carrier;
365  friend class HttpHeaders;
366  const Carrier &ci;
367  std::unique_ptr<ci_searchresult_t, dropres> dv;
368  std::map<size_t, PVPairSet> ires;
369  void pvpfill() const {
370  if (!empty() && vres.size() == 0) {
371  size_t i = 0;
372  for (auto e = begin(); e != end(); ++e, ++i) {
373  auto it = *e;
374  if (!it.first) {
375  Exception e;
376  e << "invalid property at";
377  e << i;
378  __throw(e);
379  }
380  }
381  }
382  }
383  public:
384  DeliveryContext(const Carrier &, const HttpHeaders &);
385  class const_iterator;
386  friend class const_iterator;
387 
389  private:
390  DeliveryContext &props;
391  size_t idx;
392  size_t propcount;
393  friend class DeliveryContext;
394  PVPairSet builtin;
395  const PVPairSet propdict() const;
396  public:
397  const_iterator(DeliveryContext &props_, size_t idx_);
398  const PVPairSet operator * () const;
399  const PVPairSet *operator -> ();
400  const_iterator &operator++();
401  bool operator==(const const_iterator &rhs) const;
402  bool operator!=(const const_iterator &rhs) const;
403  };
404 
405  const_iterator begin() const;
406  const_iterator end() const;
407  const_iterator find(const Property &) const;
408  const_iterator find(const char *) const;
409  size_t size() const { return set ? ci.inst.get()->property_count : 0; }
410  bool empty() const { return size() == 0; }
411  bool contains(const char *propname) {
412  return find(propname) != this->end();
413  }
414  const std::string realip() const { return dv->u.ei; }
418  const valueset operator[](const Property &) const noexcept;
422  const valueset operator[](const char *) const noexcept;
423 #if __cplusplus >= 201703L
424 
427  std::optional<const valueset> operator[](std::string_view) const noexcept;
428 #endif
429  };
430 }
431 }
432 }
433 #endif
Definition: devatlas.h:313
Definition: devatlas.h:319
DeliveryContext class for triggering the API lookup and acts as a container map itself to hold the pr...
Definition: devatlas.h:363
HttpHeaders class is the place holder of the HTTP headers user data to be used for the lookup...
Definition: devatlas.h:347
HttpHeaders class is the place holder of the HTTP headers user data to be used for the lookup...
Definition: devatlas.h:179
Abstract type to map a property.
Definition: common_priv.h:43
Definition: common_priv.h:33
DeviceConfig class to hold the API configuration regarding cache size and the client cookie name...
Definition: devatlas.h:122
Definition: common_priv.h:173
Definition: common_priv.h:152
DeviceAtlas class represents the API data mapped to memory through reading a JSON file or a memory ma...
Definition: devatlas.h:138
DeliveryContext class for triggering the API lookup and acts as a container map itself to hold the pr...
Definition: devatlas.h:201
const Value * operator[](const Property &) const noexcept
[] operator overrides return nullptr if property index is non-existent
Carrier class represents the API data mapped to memory through reading a binary file.
Definition: devatlas.h:329
Definition: common_priv.h:139
const valueset operator[](const Property &) const noexcept
[] operator overrides return nullptr if property index is non-existent
Optional download data config offers single and scheduled download modes using standard C++ type to d...
Definition: devatlas.h:66
bool contains(const char *propname, const T value)
checks if propname equals to value
Definition: devatlas.h:276
Abstract type representing a property&#39;s value.
Definition: common_priv.h:59