avs-device-sdk/Settings/include/Settings/SettingInterface.h

189 lines
5.9 KiB
C++

/*
* Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#ifndef ALEXA_CLIENT_SDK_SETTINGS_INCLUDE_SETTINGS_SETTINGINTERFACE_H_
#define ALEXA_CLIENT_SDK_SETTINGS_INCLUDE_SETTINGS_SETTINGINTERFACE_H_
#include <atomic>
#include <memory>
#include <mutex>
#include <string>
#include <type_traits>
#include <unordered_set>
#include <AVSCommon/Utils/GuardedValue.h>
#include <AVSCommon/Utils/Logger/LogEntry.h>
#include <AVSCommon/Utils/Logger/LoggerUtils.h>
#include "Settings/SetSettingResult.h"
#include "Settings/SettingObserverInterface.h"
namespace alexaClientSDK {
namespace settings {
/**
* Interface for setting objects. Second template argument is used to restrict usage to the types accepted.
*
* The setting implementation only support types that have the following properties:
* - copy assignable.
* - Have operator>> and operator<< defined.
*
* @tparam ValueT The setting value type.
*/
template <typename ValueT>
class SettingInterface {
public:
/// Define the setting value type.
using ValueType = ValueT;
/// Define the observer type for this setting.
using ObserverType = SettingObserverInterface<SettingInterface<ValueType>>;
/**
* Destructor.
*/
virtual ~SettingInterface() = default;
/**
* Request to set the managed setting to the given @c value. Note that this is an asynchronous operation.
*
* @param value The target value.
* @return The result of the enqueue operation.
*/
virtual SetSettingResult setLocalChange(const ValueType& value) = 0;
/**
* Request to set the managed setting to the given @c value. This should be used when the request came from AVS.
*
* @param value The target value.
* @return @c true if it succeeds to enqueue the request; @false otherwise.
*/
virtual bool setAvsChange(const ValueType& value) = 0;
/**
* Clear the data this @c Setting.
*
* @param value The default value for this setting.
* @return @c true if it data is cleared; @false otherwise.
*/
virtual bool clearData(const ValueType& value) = 0;
/**
* Get the current value of this setting. This will not take into consideration pending @c set requests.
*
* @return The setting value.
*/
inline ValueType get() const;
/**
* Get the default value of this setting.
*
* @return The setting default value.
*/
inline ValueType getDefault() const;
/**
* Register a setting observer.
*
* The observer will be executed every time the setting value changes or a request fails.
*
* @param observer The connector to register for calling back whenever the setting notifications.
* @return @c true if the observer was added, @c false otherwise.
*/
inline bool addObserver(std::shared_ptr<ObserverType> observer);
/**
* Remove a setting observer.
*
* @param observer The observer to remove.
*/
inline void removeObserver(std::shared_ptr<ObserverType>& observer);
protected:
/**
* Constructor that initialize @c m_value with the given @c value.
*/
SettingInterface(const ValueType& value);
/**
* Notifies observers of the status of applying a setting and it's current value.
*
* @param notification The type of notification to send to the observers.
*/
void notifyObservers(SettingNotifications notification);
/// Mutex used to guard observers.
std::mutex m_observerMutex;
/// Set of all observers of this setting.
std::unordered_set<std::shared_ptr<ObserverType>> m_observers;
/// Alias for GuardedValue with the templated value @c ValueType.
using GuardedValue = avsCommon::utils::GuardedValue<ValueType>;
/// Alias to make log entries less verbose.
using LogEntry = avsCommon::utils::logger::LogEntry;
/// The setting value. (is_trivially_copyable is not supported on gcc4.8)
typename std::conditional<std::is_scalar<ValueType>::value, std::atomic<ValueType>, GuardedValue>::type m_value;
/// The default setting value.
const ValueType m_defaultValue;
};
template <typename ValueT>
ValueT SettingInterface<ValueT>::get() const {
return m_value;
}
template <typename ValueT>
ValueT SettingInterface<ValueT>::getDefault() const {
return m_defaultValue;
}
template <typename ValueT>
bool SettingInterface<ValueT>::addObserver(std::shared_ptr<ObserverType> observer) {
if (observer) {
std::lock_guard<std::mutex>{m_observerMutex};
m_observers.insert(observer);
return true;
}
avsCommon::utils::logger::acsdkError(LogEntry("SettingInterface", "addObserverFailed").d("reason", "nullObserver"));
return false;
}
template <typename ValueT>
void SettingInterface<ValueT>::notifyObservers(SettingNotifications notification) {
std::lock_guard<std::mutex>{m_observerMutex};
for (auto& observer : m_observers) {
ValueT value = m_value;
observer->onSettingNotification(value, notification);
}
}
template <typename ValueT>
void SettingInterface<ValueT>::removeObserver(std::shared_ptr<ObserverType>& observer) {
std::lock_guard<std::mutex>{m_observerMutex};
m_observers.erase(observer);
}
template <typename ValueT>
SettingInterface<ValueT>::SettingInterface(const ValueT& value) : m_value(value), m_defaultValue{value} {
}
} // namespace settings
} // namespace alexaClientSDK
#endif // ALEXA_CLIENT_SDK_SETTINGS_INCLUDE_SETTINGS_SETTINGINTERFACE_H_