Commit b74756e38f7e92e0f7b5c98be4999e3bddc7cc36

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent f32be872

Add methods to change the refresh duration individually.

include/hueplusplus/APICache.h
... ... @@ -30,6 +30,9 @@
30 30  
31 31 namespace hueplusplus
32 32 {
  33 +//! \brief Maximum duration, used to indicate that the cache should never be refreshed automatically.
  34 +constexpr std::chrono::steady_clock::duration c_refreshNever = std::chrono::steady_clock::duration::max();
  35 +
33 36 //! \brief Caches API GET requests and refreshes regularly.
34 37 class APICache
35 38 {
... ... @@ -49,7 +52,8 @@ public:
49 52 //! \param commands HueCommandAPI for making API requests.
50 53 //! \param refresh Interval between cache refreshing. May be 0 to always refresh.
51 54 //! \param initial Initial value, may be null. If present, assumes the value is up to date.
52   - APICache(const std::string& path, const HueCommandAPI& commands, std::chrono::steady_clock::duration refresh, const nlohmann::json& initial);
  55 + APICache(const std::string& path, const HueCommandAPI& commands, std::chrono::steady_clock::duration refresh,
  56 + const nlohmann::json& initial);
53 57  
54 58 //! \brief Refresh cache now.
55 59 //! \throws std::system_error when system or socket operations fail
... ... @@ -70,6 +74,15 @@ public:
70 74 //! \throws HueException when no previous request was cached
71 75 const nlohmann::json& getValue() const;
72 76  
  77 + //! \brief Set duration after which the cache is refreshed.
  78 + //! \param refreshDuration Interval between cache refreshing.
  79 + //! May be 0 to always refresh, or \ref c_refreshNever to never refresh.
  80 + //!
  81 + //! If the new refresh duration is exceeded, does not refresh immediately.
  82 + //! Instead, the next non-const getValue() call will refresh the value.
  83 + //! This is to reduce the number of unneccessary requests.
  84 + void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
  85 +
73 86 //! \brief Get duration between refreshes.
74 87 std::chrono::steady_clock::duration getRefreshDuration() const;
75 88  
... ...
include/hueplusplus/BaseDevice.h
... ... @@ -119,6 +119,9 @@ public:
119 119 //! \throws nlohmann::json::parse_error when response could not be parsed
120 120 virtual void refresh(bool force = false);
121 121  
  122 + //! \brief Sets custom refresh interval for this device.
  123 + virtual void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
  124 +
122 125 protected:
123 126 BaseDevice(int id, const std::shared_ptr<APICache>& baseCache);
124 127 //! \brief Protected ctor that is used by subclasses.
... ...
include/hueplusplus/Bridge.h
... ... @@ -163,6 +163,9 @@ public:
163 163 //! \throws nlohmann::json::parse_error when response could not be parsed
164 164 void refresh();
165 165  
  166 + //! \brief Sets refresh interval for the whole bridge state.
  167 + void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
  168 +
166 169 //! \brief Function to get the ip address of the hue bridge
167 170 //!
168 171 //! \return string containing ip
... ...
include/hueplusplus/BridgeConfig.h
... ... @@ -67,6 +67,9 @@ public:
67 67 //! \throws nlohmann::json::parse_error when response could not be parsed
68 68 void refresh(bool force = false);
69 69  
  70 + //! \brief Sets custom refresh interval for the config.
  71 + void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
  72 +
70 73 //! \brief Get the list of whitelisted users
71 74 //! \returns All users authorized for API access
72 75 std::vector<WhitelistedUser> getWhitelistedUsers() const;
... ...
include/hueplusplus/Group.h
... ... @@ -58,6 +58,9 @@ public:
58 58 //! \throws nlohmann::json::parse_error when response could not be parsed
59 59 void refresh(bool force = false);
60 60  
  61 + //! \brief Sets custom refresh interval for this group.
  62 + void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
  63 +
61 64 //! \name General information
62 65 ///@{
63 66  
... ...
include/hueplusplus/ResourceList.h
... ... @@ -40,7 +40,8 @@ namespace hueplusplus
40 40 //!
41 41 //! The resources are assumed to be in an object with ids as keys.
42 42 //! The Resource class needs a constructor that accepts \c id, HueCommandAPI, \c refreshDuration and \c state;
43   -//! otherwise a factory function needs to be provided that takes \c id and the JSON state.
  43 +//! otherwise a factory function needs to be provided that takes \c id, \c state
  44 +//! and a base cache that is null when shared state is disabled.
44 45 template <typename Resource, typename IdT>
45 46 class ResourceList
46 47 {
... ... @@ -57,6 +58,7 @@ public:
57 58 //! \param baseCache Base cache which holds the parent state, not nullptr
58 59 //! \param cacheEntry Entry name of the list state in the base cache
59 60 //! \param refreshDuration Interval between refreshing the cache
  61 + //! \param sharedState Whether created resources should share the same base cache.
60 62 //! \param factory Optional factory function to create Resources.
61 63 //! Necessary if Resource is not constructible as described above.
62 64 ResourceList(std::shared_ptr<APICache> baseCache, const std::string& cacheEntry,
... ... @@ -92,6 +94,12 @@ public:
92 94 //! \brief Refreshes internal state now
93 95 void refresh() { stateCache->refresh(); }
94 96  
  97 + //! \brief Sets custom refresh interval for this list and all resources created.
  98 + void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
  99 + {
  100 + stateCache->setRefreshDuration(refreshDuration);
  101 + }
  102 +
95 103 //! \brief Get all resources that exist
96 104 //! \returns A vector of references to every Resource
97 105 //! \throws std::system_error when system or socket operations fail
... ... @@ -173,8 +181,9 @@ protected:
173 181 //! \throws HueException when factory is nullptr and Resource cannot be constructed as specified above.
174 182 Resource construct(const IdType& id, const nlohmann::json& state)
175 183 {
176   - return construct(
177   - id, state, std::is_constructible<Resource, IdType, HueCommandAPI, std::chrono::steady_clock::duration, const nlohmann::json&> {});
  184 + return construct(id, state,
  185 + std::is_constructible<Resource, IdType, HueCommandAPI, std::chrono::steady_clock::duration,
  186 + const nlohmann::json&> {});
178 187 }
179 188  
180 189 //! \brief Protected defaulted move constructor
... ... @@ -337,7 +346,7 @@ public:
337 346 {
338 347 throw HueException(FileInfo {__FILE__, __LINE__, __func__}, "Resource id is not valid");
339 348 }
340   - return this->construct(id, id == 0 ? nlohmann::json{ nullptr } : state[key]);
  349 + return this->construct(id, id == 0 ? nlohmann::json {nullptr} : state[key]);
341 350 }
342 351 //! \brief Get group, specially handles group 0
343 352 //! \see ResourceList::exists
... ...
include/hueplusplus/Rule.h
... ... @@ -58,6 +58,9 @@ public:
58 58 //! \throws nlohmann::json::parse_error when response could not be parsed
59 59 void refresh(bool force = false);
60 60  
  61 + //! \brief Sets custom refresh interval for this rule.
  62 + void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
  63 +
61 64 //! \brief Get rule identifier
62 65 int getId() const;
63 66  
... ...
include/hueplusplus/Scene.h
... ... @@ -139,6 +139,9 @@ public:
139 139 //! \throws nlohmann::json::parse_error when response could not be parsed
140 140 void refresh(bool force = false);
141 141  
  142 + //! \brief Sets custom refresh interval for this group.
  143 + void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
  144 +
142 145 //! \brief Get scene identifier
143 146 std::string getId() const;
144 147 //! \brief Get scene name
... ...
include/hueplusplus/Schedule.h
... ... @@ -48,6 +48,9 @@ public:
48 48 //! \throws nlohmann::json::parse_error when response could not be parsed
49 49 void refresh();
50 50  
  51 + //! \brief Sets custom refresh interval for this schedule.
  52 + void setRefreshDuration(std::chrono::steady_clock::duration refreshDuration);
  53 +
51 54 //! \brief Get schedule identifier
52 55 int getId() const;
53 56  
... ...
src/APICache.cpp
... ... @@ -25,6 +25,7 @@
25 25  
26 26 namespace hueplusplus
27 27 {
  28 +
28 29 APICache::APICache(
29 30 std::shared_ptr<APICache> baseCache, const std::string& subEntry, std::chrono::steady_clock::duration refresh)
30 31 : base(baseCache),
... ... @@ -113,6 +114,11 @@ const nlohmann::json&amp; APICache::getValue() const
113 114 }
114 115 }
115 116  
  117 +void APICache::setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
  118 +{
  119 + this->refreshDuration = refreshDuration;
  120 +}
  121 +
116 122 std::chrono::steady_clock::duration APICache::getRefreshDuration() const
117 123 {
118 124 return refreshDuration;
... ...
src/BaseDevice.cpp
... ... @@ -120,4 +120,9 @@ void BaseDevice::refresh(bool force)
120 120 }
121 121 }
122 122  
  123 +void BaseDevice::setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
  124 +{
  125 + state.setRefreshDuration(refreshDuration);
  126 +}
  127 +
123 128 } // namespace hueplusplus
... ...
src/Bridge.cpp
... ... @@ -166,6 +166,12 @@ void Bridge::refresh()
166 166 stateCache->refresh();
167 167 }
168 168  
  169 +void Bridge::setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
  170 +{
  171 + stateCache->setRefreshDuration(refreshDuration);
  172 +}
  173 +
  174 +
169 175 std::string Bridge::getBridgeIP() const
170 176 {
171 177 return ip;
... ...
src/BridgeConfig.cpp
... ... @@ -39,6 +39,12 @@ void BridgeConfig::refresh(bool force)
39 39 cache.getValue();
40 40 }
41 41 }
  42 +
  43 +void BridgeConfig::setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
  44 +{
  45 + cache.setRefreshDuration(refreshDuration);
  46 +}
  47 +
42 48 std::vector<WhitelistedUser> BridgeConfig::getWhitelistedUsers() const
43 49 {
44 50 const nlohmann::json& whitelist = cache.getValue().at("whitelist");
... ...
src/Group.cpp
... ... @@ -27,6 +27,12 @@ void Group::refresh(bool force)
27 27 }
28 28 }
29 29  
  30 +void Group::setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
  31 +{
  32 + state.setRefreshDuration(refreshDuration);
  33 +}
  34 +
  35 +
30 36 int Group::getId() const
31 37 {
32 38 return id;
... ...
src/Rule.cpp
... ... @@ -148,6 +148,11 @@ void Rule::refresh(bool force)
148 148 }
149 149 }
150 150  
  151 +void Rule::setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
  152 +{
  153 + state.setRefreshDuration(refreshDuration);
  154 +}
  155 +
151 156 int Rule::getId() const
152 157 {
153 158 return id;
... ...
src/Scene.cpp
... ... @@ -168,6 +168,11 @@ void Scene::refresh(bool force)
168 168 }
169 169 }
170 170  
  171 +void Scene::setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
  172 +{
  173 + state.setRefreshDuration(refreshDuration);
  174 +}
  175 +
171 176 std::string Scene::getId() const
172 177 {
173 178 return id;
... ...
src/Schedule.cpp
... ... @@ -35,6 +35,12 @@ void Schedule::refresh()
35 35 state.refresh();
36 36 }
37 37  
  38 +void Schedule::setRefreshDuration(std::chrono::steady_clock::duration refreshDuration)
  39 +{
  40 + state.setRefreshDuration(refreshDuration);
  41 +}
  42 +
  43 +
38 44 int Schedule::getId() const
39 45 {
40 46 return id;
... ...
test/test_APICache.cpp
... ... @@ -44,7 +44,7 @@ TEST(APICache, getRefreshDuration)
44 44 EXPECT_EQ(refresh, cache.getRefreshDuration());
45 45 }
46 46 {
47   - std::chrono::steady_clock::duration refresh = std::chrono::steady_clock::duration::max();
  47 + std::chrono::steady_clock::duration refresh = c_refreshNever;
48 48 APICache cache("", commands, refresh, nullptr);
49 49 EXPECT_EQ(refresh, cache.getRefreshDuration());
50 50 }
... ... @@ -95,7 +95,7 @@ TEST(APICache, refreshBase)
95 95 // Base cache with max duration
96 96 {
97 97 auto baseCache
98   - = std::make_shared<APICache>(basePath, commands, std::chrono::steady_clock::duration::max(), nullptr);
  98 + = std::make_shared<APICache>(basePath, commands, c_refreshNever, nullptr);
99 99 APICache cache(baseCache, "abc", std::chrono::seconds(0));
100 100  
101 101 // First call refreshes base, second call only child
... ... @@ -149,7 +149,7 @@ TEST(APICache, getValue)
149 149 // Only refresh once
150 150 {
151 151 std::string path = "/test/abc";
152   - APICache cache(path, commands, std::chrono::steady_clock::duration::max(), nullptr);
  152 + APICache cache(path, commands, c_refreshNever, nullptr);
153 153 nlohmann::json value = {{"a", "b"}};
154 154 EXPECT_CALL(*handler,
155 155 GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
... ... @@ -173,7 +173,7 @@ TEST(APICache, getValue)
173 173 // No refresh with const throws exception
174 174 {
175 175 std::string path = "/test/abc";
176   - const APICache cache(path, commands, std::chrono::steady_clock::duration::max(), nullptr);
  176 + const APICache cache(path, commands, c_refreshNever, nullptr);
177 177 nlohmann::json value = {{"a", "b"}};
178 178 EXPECT_CALL(*handler,
179 179 GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
... ... @@ -185,7 +185,7 @@ TEST(APICache, getValue)
185 185 {
186 186 std::string path = "/test/abc";
187 187 nlohmann::json value = {{"a", "b"}};
188   - APICache cache(path, commands, std::chrono::steady_clock::duration::max(), value);
  188 + APICache cache(path, commands, c_refreshNever, value);
189 189 EXPECT_CALL(*handler,
190 190 GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
191 191 .Times(0);
... ... @@ -197,7 +197,7 @@ TEST(APICache, getValue)
197 197 {
198 198 std::string path = "/test/abc";
199 199 nlohmann::json value = {{"a", "b"}};
200   - const APICache cache(path, commands, std::chrono::steady_clock::duration::max(), value);
  200 + const APICache cache(path, commands, c_refreshNever, value);
201 201 EXPECT_CALL(*handler,
202 202 GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
203 203 .Times(0);
... ... @@ -231,7 +231,7 @@ TEST(APICache, getValueBase)
231 231 // Child duration > base duration
232 232 {
233 233 auto baseCache = std::make_shared<APICache>(basePath, commands, std::chrono::seconds(0), nullptr);
234   - APICache cache(baseCache, "abc", std::chrono::steady_clock::duration::max());
  234 + APICache cache(baseCache, "abc", c_refreshNever);
235 235 EXPECT_CALL(*handler,
236 236 GETJson("/api/" + getBridgeUsername() + basePath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
237 237 .Times(1)
... ... @@ -243,7 +243,7 @@ TEST(APICache, getValueBase)
243 243 // Child duration < base duration
244 244 {
245 245 auto baseCache
246   - = std::make_shared<APICache>(basePath, commands, std::chrono::steady_clock::duration::max(), nullptr);
  246 + = std::make_shared<APICache>(basePath, commands, c_refreshNever, nullptr);
247 247 APICache cache(baseCache, "abc", std::chrono::seconds(0));
248 248 const nlohmann::json updateChildValue = {{"test", "updated"}};
249 249 InSequence s;
... ... @@ -265,8 +265,8 @@ TEST(APICache, getValueBase)
265 265 // Only refresh once
266 266 {
267 267 auto baseCache
268   - = std::make_shared<APICache>(basePath, commands, std::chrono::steady_clock::duration::max(), nullptr);
269   - APICache cache(baseCache, "abc", std::chrono::steady_clock::duration::max());
  268 + = std::make_shared<APICache>(basePath, commands, c_refreshNever, nullptr);
  269 + APICache cache(baseCache, "abc", c_refreshNever);
270 270 EXPECT_CALL(*handler,
271 271 GETJson("/api/" + getBridgeUsername() + basePath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
272 272 .Times(1)
... ... @@ -277,6 +277,31 @@ TEST(APICache, getValueBase)
277 277 }
278 278 }
279 279  
  280 +
  281 +TEST(APICache, setRefreshDuration)
  282 +{
  283 + using namespace ::testing;
  284 + auto handler = std::make_shared<MockHttpHandler>();
  285 + HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
  286 +
  287 + {
  288 + std::string path = "/test/abc";
  289 + APICache cache(path, commands, std::chrono::seconds(0), nullptr);
  290 + nlohmann::json value = { {"a", "b"} };
  291 + EXPECT_CALL(*handler,
  292 + GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
  293 + .Times(1)
  294 + .WillOnce(Return(value));
  295 + EXPECT_EQ(value, cache.getValue());
  296 + cache.setRefreshDuration(c_refreshNever);
  297 + EXPECT_EQ(c_refreshNever, cache.getRefreshDuration());
  298 + // Next getValue does not refresh
  299 + EXPECT_EQ(value, cache.getValue());
  300 + Mock::VerifyAndClearExpectations(handler.get());
  301 + }
  302 +}
  303 +
  304 +
280 305 TEST(APICache, getRequestPath)
281 306 {
282 307 using namespace ::testing;
... ...