AlexaClientSDK  3.0.0
A cross-platform, modular SDK for interacting with the Alexa Voice Service
Setting.h
Go to the documentation of this file.
1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  * http://aws.amazon.com/apache2.0/
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 #ifndef ALEXA_CLIENT_SDK_SETTINGS_INCLUDE_SETTINGS_SETTING_H_
16 #define ALEXA_CLIENT_SDK_SETTINGS_INCLUDE_SETTINGS_SETTING_H_
17 
18 #include <functional>
19 #include <memory>
20 #include <mutex>
21 #include <string>
22 #include <utility>
23 
26 
30 #include "Settings/SettingStatus.h"
32 
33 namespace alexaClientSDK {
34 namespace settings {
35 
47 template <typename ValueT>
48 class Setting : public SettingInterface<ValueT> {
49 public:
51  using ValueType = ValueT;
52 
62  static std::shared_ptr<Setting<ValueT>> create(
63  const ValueType& defaultValue,
64  std::unique_ptr<SettingProtocolInterface> settingProtocol,
65  std::function<bool(const ValueType&)> applyValueFn = std::function<bool(const ValueType&)>());
66 
69  SetSettingResult setLocalChange(const ValueType& value) override;
70  bool setAvsChange(const ValueType& value) override;
71  bool clearData(const ValueType& value) override;
73 
74 private:
82  Setting(
83  const ValueType& value,
84  std::function<bool(const ValueType&)> applyValueFn,
85  std::unique_ptr<SettingProtocolInterface> settingProtocol);
86 
94  std::pair<bool, std::string> handleSetValue(const ValueType& value);
95 
101  bool restore();
102 
105  std::function<bool(const ValueType&)> m_applyFunction;
106 
108  std::unique_ptr<SettingProtocolInterface> m_protocol;
109 
111  ValueType m_oldValue;
112 
114  std::mutex m_mutex;
115 
118 };
119 
120 template <typename ValueT>
121 std::shared_ptr<Setting<ValueT>> Setting<ValueT>::create(
122  const ValueType& defaultValue,
123  std::unique_ptr<SettingProtocolInterface> settingProtocol,
124  std::function<bool(const ValueType&)> applyValueFn) {
125  if (!settingProtocol) {
126  avsCommon::utils::logger::acsdkError(LogEntry("Setting", "createFailed").d("reason", "nullSettingProtocol"));
127  return nullptr;
128  }
129 
130  auto setting =
131  std::shared_ptr<Setting<ValueT>>(new Setting(defaultValue, applyValueFn, std::move(settingProtocol)));
132 
133  if (!setting->restore()) {
134  avsCommon::utils::logger::acsdkError(LogEntry("Setting", "createFailed").d("reason", "restoreValueFailed"));
135  return nullptr;
136  }
137 
138  return setting;
139 }
140 
141 template <typename ValueT>
142 std::pair<bool, std::string> Setting<ValueT>::handleSetValue(const ValueType& value) {
143  bool ok;
144  std::string valueStr;
145  std::tie(ok, valueStr) = toSettingString<ValueT>(value);
146  if (ok && (!this->m_applyFunction || this->m_applyFunction(value))) {
147  avsCommon::utils::logger::acsdkInfo(LogEntry("Setting", __func__).obfuscatePrivateData("value", valueStr));
148  m_oldValue = this->m_value;
149  this->m_value = value;
150  return {true, valueStr};
151  }
152  avsCommon::utils::logger::acsdkError(LogEntry("Setting", "setValueFailed").d("reason", "applyFailed"));
153  return {false, toSettingString<ValueType>(this->m_value).second};
154 }
155 
156 template <typename ValueT>
158  auto executeSet = [this, value] {
159  std::lock_guard<std::mutex> lock{m_mutex};
160  return this->handleSetValue(value);
161  };
162  auto revertChange = [this] {
163  std::lock_guard<std::mutex> lock{m_mutex};
164  auto oldValue = m_oldValue;
165  return this->handleSetValue(oldValue).second;
166  };
167  auto notifyObservers = [this](SettingNotifications notification) { this->notifyObservers(notification); };
168  return m_protocol->avsChange(executeSet, revertChange, notifyObservers);
169 }
170 
171 template <typename ValueT>
173  auto executeSet = [this, value] {
174  std::lock_guard<std::mutex> lock{m_mutex};
175  return this->handleSetValue(value);
176  };
177  auto revertChange = [this] {
178  std::lock_guard<std::mutex> lock{m_mutex};
179  auto oldValue = m_oldValue;
180  return this->handleSetValue(oldValue).second;
181  };
182  auto notifyObservers = [this](SettingNotifications notification) { this->notifyObservers(notification); };
183  return m_protocol->localChange(executeSet, revertChange, notifyObservers);
184 }
185 
186 template <typename ValueT>
188  std::unique_lock<std::mutex> lock{m_mutex};
189  this->m_value = value;
190  // Clear customer's data before restoring the initial value
191  auto result = m_protocol->clearData();
192  lock.unlock();
193  if (result) {
194  // this->m_value (initial value) is restored
195  // as databaseValue.empty() == true
196  restore();
197  }
198  return result;
199 }
200 
201 template <typename ValueT>
203  auto applyChange = [this](const std::string& databaseValue) -> std::pair<bool, std::string> {
204  bool convertOk, setOk;
205  ValueT value;
206  std::string valueStr;
207  if (databaseValue.empty()) {
208  convertOk = true;
209  value = this->m_value;
210  } else {
211  std::tie(convertOk, value) = fromSettingString<ValueT>(databaseValue, this->m_value);
212  }
213  std::lock_guard<std::mutex> lock{m_mutex};
214  std::tie(setOk, valueStr) = handleSetValue(value);
215  return {convertOk && setOk, valueStr};
216  };
217  auto notifyObservers = [this](SettingNotifications notification) { this->notifyObservers(notification); };
218  return m_protocol->restoreValue(applyChange, notifyObservers);
219 }
220 
221 template <typename ValueT>
223  const ValueType& value,
224  std::function<bool(const ValueType&)> applyValueFn,
225  std::unique_ptr<SettingProtocolInterface> settingProtocol) :
227  m_applyFunction{applyValueFn},
228  m_protocol{std::move(settingProtocol)},
229  m_oldValue{value} {
230 }
231 
232 } // namespace settings
233 } // namespace alexaClientSDK
234 
235 #endif // ALEXA_CLIENT_SDK_SETTINGS_INCLUDE_SETTINGS_SETTING_H_
ValueT ValueType
Define an alias for setting value type.
Definition: Setting.h:51
static std::shared_ptr< Setting< ValueT > > create(const ValueType &defaultValue, std::unique_ptr< SettingProtocolInterface > settingProtocol, std::function< bool(const ValueType &)> applyValueFn=std::function< bool(const ValueType &)>())
Definition: Setting.h:121
::std::string string
Definition: gtest-port.h:1097
Definition: SettingInterface.h:45
bool setAvsChange(const ValueType &value) override
Definition: Setting.h:157
std::conditional< std::is_scalar< ValueType >::value, std::atomic< ValueType >, GuardedValue >::type m_value
The setting value. (is_trivially_copyable is not supported on gcc4.8)
Definition: SettingInterface.h:139
Definition: Setting.h:48
void notifyObservers(SettingNotifications notification)
Definition: SettingInterface.h:167
bool clearData(const ValueType &value) override
Definition: Setting.h:187
void acsdkInfo(const LogEntry &entry)
SetSettingResult
Definition: SetSettingResult.h:23
Whether or not curl logs should be emitted.
Definition: AVSConnectionManager.h:36
SettingNotifications
Definition: SettingObserverInterface.h:28
void acsdkError(const LogEntry &entry)
SetSettingResult setLocalChange(const ValueType &value) override
Definition: Setting.h:172
const T & move(const T &t)
Definition: gtest-port.h:1317
LogEntry is used to compile the log entry text to log via Logger.
Definition: LogEntry.h:33

AlexaClientSDK 3.0.0 - Copyright 2016-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. Licensed under the Apache License, Version 2.0