hueplusplus  1.0.0
ResourceList.h
Go to the documentation of this file.
1 
22 #ifndef INCLUDE_HUEPLUSPLUS_RESOURCE_LIST_H
23 #define INCLUDE_HUEPLUSPLUS_RESOURCE_LIST_H
24 
25 #include <functional>
26 #include <map>
27 #include <string>
28 #include <vector>
29 
30 #include "APICache.h"
31 #include "HueException.h"
32 #include "NewDeviceList.h"
33 #include "Utils.h"
34 
35 namespace hueplusplus
36 {
45 template <typename Resource, typename IdT>
47 {
48 public:
49  using ResourceType = Resource;
50  using IdType = IdT;
51  static_assert(std::is_integral<IdType>::value || std::is_same<std::string, IdType>::value,
52  "IdType must be integral or string");
53 
61  ResourceList(std::shared_ptr<APICache> baseCache, const std::string& cacheEntry,
62  std::chrono::steady_clock::duration refreshDuration, bool sharedState = false,
63  const std::function<Resource(IdType, const nlohmann::json&, const std::shared_ptr<APICache>&)>& factory
64  = nullptr)
65  : stateCache(std::make_shared<APICache>(baseCache, cacheEntry, refreshDuration)),
67  path(stateCache->getRequestPath() + '/'),
69  { }
76  ResourceList(const HueCommandAPI& commands, const std::string& path,
77  std::chrono::steady_clock::duration refreshDuration,
78  const std::function<Resource(IdType, const nlohmann::json&, const std::shared_ptr<APICache>&)>& factory
79  = nullptr)
80  : stateCache(std::make_shared<APICache>(path, commands, refreshDuration, nullptr)),
82  path(path + '/'),
83  sharedState(false)
84  { }
85 
87  ResourceList(const ResourceList&) = delete;
89  ResourceList& operator=(const ResourceList&) = delete;
90 
92  void refresh() { stateCache->refresh(); }
93 
96  void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
97  {
98  stateCache->setRefreshDuration(refreshDuration);
99  }
100 
107  std::vector<Resource> getAll()
108  {
109  nlohmann::json& state = stateCache->getValue();
110  std::vector<Resource> result;
111  result.reserve(state.size());
112  for (auto it = state.begin(); it != state.end(); ++it)
113  {
114  result.emplace_back(construct(maybeStoi(it.key()), it.value()));
115  }
116  return result;
117  }
118 
126  Resource get(const IdType& id)
127  {
128  const nlohmann::json& state = stateCache->getValue();
129  std::string key = maybeToString(id);
130  if (!state.count(key))
131  {
132  throw HueException(FileInfo {__FILE__, __LINE__, __func__}, "Resource id is not valid");
133  }
134  return construct(id, state[key]);
135  }
136 
144  bool exists(const IdType& id) { return stateCache->getValue().count(maybeToString(id)) != 0; }
145 
151  bool exists(const IdType& id) const { return stateCache->getValue().count(maybeToString(id)) != 0; }
152 
162  bool remove(const IdType& id)
163  {
164  std::string requestPath = path + maybeToString(id);
165  nlohmann::json result = stateCache->getCommandAPI().DELETERequest(
166  requestPath, nlohmann::json::object(), FileInfo {__FILE__, __LINE__, __func__});
167  bool success = utils::safeGetMember(result, 0, "success") == requestPath + " deleted";
168  return success;
169  }
170 
171 protected:
173  static IdType maybeStoi(const std::string& key) { return maybeStoi(key, std::is_integral<IdType> {}); }
174 
176  static std::string maybeToString(const IdType& id) { return maybeToString(id, std::is_integral<IdType> {}); }
177 
180  Resource construct(const IdType& id, const nlohmann::json& state)
181  {
182  return construct(id, state,
183  std::is_constructible<Resource, IdType, HueCommandAPI, std::chrono::steady_clock::duration,
184  const nlohmann::json&> {});
185  }
186 
188  ResourceList(ResourceList&&) = default;
190  ResourceList& operator=(ResourceList&&) = default;
191 
192 private:
193  // Resource is constructible
194  Resource construct(const IdType& id, const nlohmann::json& state, std::true_type)
195  {
196  if (factory)
197  {
198  return factory(id, state, sharedState ? stateCache : std::shared_ptr<APICache>());
199  }
200  else
201  {
202  if (sharedState)
203  {
204  return Resource(id, stateCache);
205  }
206  else
207  {
208  return Resource(id, stateCache->getCommandAPI(), stateCache->getRefreshDuration(), state);
209  }
210  }
211  }
212  // Resource is not constructible
213  Resource construct(const IdType& id, const nlohmann::json& state, std::false_type)
214  {
215  if (!factory)
216  {
217  throw HueException(FileInfo {__FILE__, __LINE__, __func__},
218  "Resource is not constructable with default parameters, but no factory given");
219  }
220  return factory(id, state, sharedState ? stateCache : std::shared_ptr<APICache>());
221  }
222 
223 private:
224  static IdType maybeStoi(const std::string& key, std::true_type) { return std::stoi(key); }
225  static IdType maybeStoi(const std::string& key, std::false_type) { return key; }
226  static std::string maybeToString(IdType id, std::true_type) { return std::to_string(id); }
227  static std::string maybeToString(const IdType& id, std::false_type) { return id; }
228 
229 protected:
230  std::shared_ptr<APICache> stateCache;
231  std::function<Resource(IdType, const nlohmann::json&, const std::shared_ptr<APICache>&)> factory;
232  std::string path;
234 };
235 
238 template <typename Resource>
239 class SearchableResourceList : public ResourceList<Resource, int>
240 {
241 public:
243 
248  void search(const std::vector<std::string>& deviceIds = {})
249  {
250  std::string requestPath = this->path;
251  // Remove trailing slash
252  requestPath.pop_back();
253  if (deviceIds.empty())
254  {
255  this->stateCache->getCommandAPI().POSTRequest(
256  requestPath, nlohmann::json::object(), FileInfo {__FILE__, __LINE__, __func__});
257  }
258  else
259  {
260  this->stateCache->getCommandAPI().POSTRequest(
261  requestPath, nlohmann::json {{"deviceid", deviceIds}}, FileInfo {__FILE__, __LINE__, __func__});
262  }
263  }
264 
267  {
268  nlohmann::json response = this->stateCache->getCommandAPI().GETRequest(
269  this->path + "new", nlohmann::json::object(), FileInfo {__FILE__, __LINE__, __func__});
270  return NewDeviceList::parse(response);
271  }
272 
273 protected:
278 };
279 
284 template <typename BaseResourceList, typename CreateType>
285 class CreateableResourceList : public BaseResourceList
286 {
287 public:
288  using BaseResourceList::BaseResourceList;
289 
298  typename BaseResourceList::IdType create(const CreateType& params)
299  {
300  std::string requestPath = this->path;
301  // Remove slash
302  requestPath.pop_back();
303  nlohmann::json response = this->stateCache->getCommandAPI().POSTRequest(
304  requestPath, params.getRequest(), FileInfo {__FILE__, __LINE__, __func__});
305  nlohmann::json id = utils::safeGetMember(response, 0, "success", "id");
306  if (id.is_string())
307  {
308  std::string idStr = id.get<std::string>();
309  if (idStr.find(this->path) == 0)
310  {
311  idStr.erase(0, this->path.size());
312  }
313  this->stateCache->refresh();
314  return this->maybeStoi(idStr);
315  }
316  return typename BaseResourceList::IdType {};
317  }
318 
319 protected:
324 };
325 
330 template <typename Resource, typename CreateType>
331 class GroupResourceList : public CreateableResourceList<ResourceList<Resource, int>, CreateType>
332 {
334 
335 public:
336  using Base::Base;
339  Resource get(const int& id)
340  {
341  const nlohmann::json& state = this->stateCache->getValue();
342  std::string key = this->maybeToString(id);
343  if (!state.count(key) && id != 0)
344  {
345  throw HueException(FileInfo {__FILE__, __LINE__, __func__}, "Resource id is not valid");
346  }
347  return this->construct(id, id == 0 ? nlohmann::json {nullptr} : state[key]);
348  }
351  bool exists(int id) const { return id == 0 || Base::exists(id); }
352 
353 protected:
358 };
359 } // namespace hueplusplus
360 
361 #endif
bool exists(int id) const
Get group, specially handles group 0.
Definition: ResourceList.h:351
void search(const std::vector< std::string > &deviceIds={})
Start search for new devices.
Definition: ResourceList.h:248
void refresh()
Refreshes internal state now.
Definition: ResourceList.h:92
Definition: HueCommandAPI.h:37
Exception class with file information. Base class of all custom exception classes.
Definition: HueException.h:49
Handles a ResourceList where Resources can be added by the user.
Definition: ResourceList.h:285
static NewDeviceList parse(const nlohmann::json &json)
Parse from json response.
Definition: NewDeviceList.cpp:45
std::shared_ptr< APICache > stateCache
Definition: ResourceList.h:230
ResourceList & operator=(const ResourceList &)=delete
Deleted copy assignment.
bool exists(const IdType &id) const
Checks whether resource with id exists.
Definition: ResourceList.h:151
Namespace for the hueplusplus library.
Definition: Action.h:27
ResourceList(std::shared_ptr< APICache > baseCache, const std::string &cacheEntry, std::chrono::steady_clock::duration refreshDuration, bool sharedState=false, const std::function< Resource(IdType, const nlohmann::json &, const std::shared_ptr< APICache > &)> &factory=nullptr)
Construct ResourceList using a base cache and optional factory function.
Definition: ResourceList.h:61
Caches API GET requests and refreshes regularly.
Definition: APICache.h:37
List of new devices found during the last scan.
Definition: NewDeviceList.h:35
std::vector< Resource > getAll()
Get all resources that exist.
Definition: ResourceList.h:107
Handles a group list with the special group 0.
Definition: ResourceList.h:331
Handles a list of a certain API resource.
Definition: ResourceList.h:46
Contains information about error location, use CURRENT_FILE_INFO to create.
Definition: HueException.h:34
std::string path
Definition: ResourceList.h:232
std::function< Resource(IdType, const nlohmann::json &, const std::shared_ptr< APICache > &)> factory
Definition: ResourceList.h:231
NewDeviceList getNewDevices() const
Get devices found in last search.
Definition: ResourceList.h:266
void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
Sets custom refresh interval for this list and all resources created.
Definition: ResourceList.h:96
bool exists(const IdType &id)
Checks whether resource with id exists.
Definition: ResourceList.h:144
BaseResourceList::IdType create(const CreateType &params)
Create a new resource.
Definition: ResourceList.h:298
Resource ResourceType
Definition: ResourceList.h:49
int IdType
Definition: ResourceList.h:50
nlohmann::json safeGetMember(const nlohmann::json &json, Paths &&... paths)
Returns the object/array member or null if it does not exist.
Definition: Utils.h:92
static IdType maybeStoi(const std::string &key)
Calls std::stoi if IdType is int.
Definition: ResourceList.h:173
Resource construct(const IdType &id, const nlohmann::json &state)
Constructs resource using factory or constructor, if available.
Definition: ResourceList.h:180
bool sharedState
Definition: ResourceList.h:233
ResourceList(const HueCommandAPI &commands, const std::string &path, std::chrono::steady_clock::duration refreshDuration, const std::function< Resource(IdType, const nlohmann::json &, const std::shared_ptr< APICache > &)> &factory=nullptr)
Construct ResourceList with a separate cache and optional factory function.
Definition: ResourceList.h:76
static std::string maybeToString(const IdType &id)
Calls std::to_string if IdType is int.
Definition: ResourceList.h:176
Handles a ResourceList of physical devices which can be searched for.
Definition: ResourceList.h:239