Skip to content

Source · fairmq/

PluginServices.hpublic header

Defines class fair::mq::PluginServices, struct fair::mq::PluginServices::DeviceControlError.

Described in Plugins and control, custom-controller: control from code, Control a device from code, Write a plugin, Logging.

fairmq/PluginServices.h285 lines · C++API: PluginServicesAPI: DeviceControlErrorGitHub ↗
1/********************************************************************************2 * Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH  *3 *                                                                              *4 *              This software is distributed under the terms of the             *5 *              GNU Lesser General Public Licence (LGPL) version 3,             *6 *                  copied verbatim in the file "LICENSE"                       *7 ********************************************************************************/8 9#ifndef FAIR_MQ_PLUGINSERVICES_H10#define FAIR_MQ_PLUGINSERVICES_H11 12#include <fairmq/Device.h>13#include <fairmq/States.h>14#include <fairmq/ProgOptions.h>15#include <fairmq/Properties.h>16 17#include <boost/optional.hpp>18#include <boost/optional/optional_io.hpp>19 20#include <condition_variable>21#include <functional>22#include <map>23#include <mutex>24#include <stdexcept>25#include <string>26#include <unordered_map>27#include <vector>28 29namespace fair::mq30{31 32/**33 * @class PluginServices PluginServices.h <fairmq/PluginServices.h>34 * @brief Facilitates communication between devices and plugins35 *36 * - Configuration interface37 * - Control interface38 */39class PluginServices40{41  public:42    PluginServices() = delete;43    PluginServices(ProgOptions& config, Device& device)44        : fConfig(config)45        , fDevice(device)46    {}47 48    ~PluginServices()49    {50        LOG(debug) << "Shutting down Plugin Services";51    }52 53    PluginServices(const PluginServices&) = delete;54    PluginServices(PluginServices&&) = delete;55    PluginServices& operator=(const PluginServices&) = delete;56    PluginServices& operator=(PluginServices&&) = delete;57 58    using DeviceState = fair::mq::State;59    using DeviceStateTransition = fair::mq::Transition;60 61    // Control API62 63    /// @brief Convert string to DeviceState64    /// @param state to convert65    /// @return DeviceState enum entry66    /// @throw std::out_of_range if a string cannot be resolved to a DeviceState67    static auto ToDeviceState(const std::string& state) -> DeviceState { return GetState(state); }68 69    /// @brief Convert string to DeviceStateTransition70    /// @param transition to convert71    /// @return DeviceStateTransition enum entry72    /// @throw std::out_of_range if a string cannot be resolved to a DeviceStateTransition73    static auto ToDeviceStateTransition(const std::string& transition) -> DeviceStateTransition { return GetTransition(transition); }74 75    /// @brief Convert DeviceState to string76    /// @param state to convert77    /// @return string representation of DeviceState enum entry78    static auto ToStr(DeviceState state) -> std::string { return GetStateName(state); }79 80    /// @brief Convert DeviceStateTransition to string81    /// @param transition to convert82    /// @return string representation of DeviceStateTransition enum entry83    static auto ToStr(DeviceStateTransition transition) -> std::string { return GetTransitionName(transition); }84 85    /// @return current device state86    auto GetCurrentDeviceState() const -> DeviceState { return fDevice.GetCurrentState(); }87 88    /// @brief Become device controller89    /// @param controller id90    /// @throws fair::mq::PluginServices::DeviceControlError if there is already a device controller.91    ///92    /// Only one plugin can succeed to take control over device state transitions at a time.93    auto TakeDeviceControl(const std::string& controller) -> void;94    struct DeviceControlError : std::runtime_error { using std::runtime_error::runtime_error; };95 96    /// @brief Become device controller by force97    /// @param controller id98    ///99    /// Take over device controller privileges by force. Does not trigger the ReleaseDeviceControl condition!100    /// This function is intended to implement override/emergency control functionality (e.g. device shutdown on SIGINT).101    auto StealDeviceControl(const std::string& controller) -> void;102 103    /// @brief Release device controller role104    /// @param controller id105    /// @throws fair::mq::PluginServices::DeviceControlError if passed controller id is not the current device controller.106    auto ReleaseDeviceControl(const std::string& controller) -> void;107 108    /// @brief Get current device controller109    auto GetDeviceController() const -> boost::optional<std::string>;110 111    /// @brief Block until control is released112    auto WaitForReleaseDeviceControl() -> void;113 114    /// @brief Request a device state transition115    /// @param controller id116    /// @param next state transition117    /// @throws fair::mq::PluginServices::DeviceControlError if control role is not currently owned by passed controller id.118    ///119    /// The state transition may not happen immediately, but when the current state evaluates the120    /// pending transition event and terminates. In other words, the device states are scheduled cooperatively.121    /// If the device control role has not been taken yet, calling this function will take over control implicitely.122    auto ChangeDeviceState(const std::string& controller, DeviceStateTransition next) -> bool;123 124    /// @brief Subscribe with a callback to device state changes125    /// @param subscriber id126    /// @param callback127    ///128    /// The callback will be called at the beginning of a new state. The callback is called from the thread129    /// the state is running in.130    auto SubscribeToDeviceStateChange(const std::string& subscriber, std::function<void(DeviceState /*newState*/)> callback) -> void131    {132        fDevice.SubscribeToStateChange(subscriber, [&,callback](fair::mq::State newState){133            callback(newState);134        });135    }136 137    /// @brief Unsubscribe from device state changes138    /// @param subscriber id139    auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice.UnsubscribeFromStateChange(subscriber); }140 141    /// DO NOT USE, ONLY FOR TESTING, WILL BE REMOVED (and info made available via property api)142    auto GetNumberOfConnectedPeers(const std::string& channelName, int index = 0) -> unsigned long { return fDevice.GetNumberOfConnectedPeers(channelName, index); }143 144    // Config API145 146    /// @brief Checks a property with the given key exist in the configuration147    /// @param key148    /// @return true if it exists, false otherwise149    auto PropertyExists(const std::string& key) const -> bool { return fConfig.Count(key) > 0; }150 151    /// @brief Set config property152    /// @param key153    /// @param val154    ///155    /// Setting a config property will store the value in the FairMQ internal config store and notify any subscribers about the update.156    /// It is property dependent, if the call to this method will have an immediate, delayed or any effect at all.157    template<typename T>158    auto SetProperty(const std::string& key, T val) -> void { fConfig.SetProperty(key, val); }159    /// @brief Set multiple config properties160    /// @param props fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any161    void SetProperties(const fair::mq::Properties& props) { fConfig.SetProperties(props); }162    /// @brief Updates an existing config property (or fails if it doesn't exist)163    /// @param key164    /// @param val165    template<typename T>166    bool UpdateProperty(const std::string& key, T val) { return fConfig.UpdateProperty(key, val); }167    /// @brief Updates multiple existing config properties (or fails of any of then do not exist, leaving property store unchanged)168    /// @param props (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)169    bool UpdateProperties(const fair::mq::Properties& input) { return fConfig.UpdateProperties(input); }170 171    /// @brief Deletes a property with the given key from the config store172    /// @param key173    void DeleteProperty(const std::string& key) { fConfig.DeleteProperty(key); }174 175    /// @brief Read config property, throw if no property with this key exists176    /// @param key177    /// @return config property178    template<typename T>179    auto GetProperty(const std::string& key) const -> T { return fConfig.GetProperty<T>(key); }180 181    /// @brief Read config property, return provided value if no property with this key exists182    /// @param key183    /// @param ifNotFound value to return if key is not found184    /// @return config property185    template<typename T>186    T GetProperty(const std::string& key, const T& ifNotFound) const { return fConfig.GetProperty(key, ifNotFound); }187 188    /// @brief Read config property as string, throw if no property with this key exists189    /// @param key190    /// @return config property converted to string191    ///192    /// Supports conversion to string for a fixed set of types,193    /// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType<MyType>("optional label")`194    /// the provided type must then be convertible to string via operator<<195    auto GetPropertyAsString(const std::string& key) const -> std::string { return fConfig.GetPropertyAsString(key); }196 197    /// @brief Read config property, return provided value if no property with this key exists198    /// @param key199    /// @param ifNotFound value to return if key is not found200    /// @return config property converted to string201    ///202    /// Supports conversion to string for a fixed set of types,203    /// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType<MyType>("optional label")`204    /// the provided type must then be convertible to string via operator<<205    auto GetPropertyAsString(const std::string& key, const std::string& ifNotFound) const -> std::string { return fConfig.GetPropertyAsString(key, ifNotFound); }206 207    /// @brief Read several config properties whose keys match the provided regular expression208    /// @param q regex string to match for209    /// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)210    fair::mq::Properties GetProperties(const std::string& q) const { return fConfig.GetProperties(q); }211    /// @brief Read several config properties whose keys start with the provided string212    /// @param q string to match for213    /// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)214    ///215    /// Typically more performant than GetProperties with regex216    fair::mq::Properties GetPropertiesStartingWith(const std::string& q) const { return fConfig.GetPropertiesStartingWith(q); }217    /// @brief Read several config properties as string whose keys match the provided regular expression218    /// @param q regex string to match for219    /// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)220    std::map<std::string, std::string> GetPropertiesAsString(const std::string& q) const { return fConfig.GetPropertiesAsString(q); }221    /// @brief Read several config properties as string whose keys start with the provided string222    /// @param q string to match for223    /// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)224    ///225    /// Typically more performant than GetPropertiesAsString with regex226    std::map<std::string, std::string> GetPropertiesAsStringStartingWith(const std::string& q) const { return fConfig.GetPropertiesAsStringStartingWith(q); }227 228    /// @brief Retrieve current channel information229    /// @return a map of <channel name, number of subchannels>230    auto GetChannelInfo() const -> std::unordered_map<std::string, int> { return fConfig.GetChannelInfo(); }231 232    /// @brief Discover the list of property keys233    /// @return list of property keys234    auto GetPropertyKeys() const -> std::vector<std::string> { return fConfig.GetPropertyKeys(); }235 236    /// @brief Subscribe to property updates of type T237    /// @param subscriber238    /// @param callback function239    ///240    /// Subscribe to property changes with a callback to monitor property changes in an event based fashion.241    template<typename T>242    auto SubscribeToPropertyChange(const std::string& subscriber, std::function<void(const std::string& key, T)> callback) const -> void243    {244        fConfig.Subscribe<T>(subscriber, callback);245    }246 247    /// @brief Unsubscribe from property updates of type T248    /// @param subscriber249    template<typename T>250    auto UnsubscribeFromPropertyChange(const std::string& subscriber) -> void { fConfig.Unsubscribe<T>(subscriber); }251 252    /// @brief Subscribe to property updates253    /// @param subscriber254    /// @param callback function255    ///256    /// Subscribe to property changes with a callback to monitor property changes in an event based fashion. Will convert the property to string.257    auto SubscribeToPropertyChangeAsString(const std::string& subscriber, std::function<void(const std::string& key, std::string)> callback) const -> void258    {259        fConfig.SubscribeAsString(subscriber, callback);260    }261 262    /// @brief Unsubscribe from property updates that convert to string263    /// @param subscriber264    auto UnsubscribeFromPropertyChangeAsString(const std::string& subscriber) -> void { fConfig.UnsubscribeAsString(subscriber); }265 266    /// @brief Increases console logging severity, or sets it to lowest if it is already highest267    auto CycleLogConsoleSeverityUp() -> void { Logger::CycleConsoleSeverityUp(); }268    /// @brief Decreases console logging severity, or sets it to highest if it is already lowest269    auto CycleLogConsoleSeverityDown() -> void { Logger::CycleConsoleSeverityDown(); }270    /// @brief Increases logging verbosity, or sets it to lowest if it is already highest271    auto CycleLogVerbosityUp() -> void { Logger::CycleVerbosityUp(); }272    /// @brief Decreases logging verbosity, or sets it to highest if it is already lowest273    auto CycleLogVerbosityDown() -> void { Logger::CycleVerbosityDown(); }274 275  private:276    fair::mq::ProgOptions& fConfig;277    Device& fDevice;278    boost::optional<std::string> fDeviceController;279    mutable std::mutex fDeviceControllerMutex;280    std::condition_variable fReleaseDeviceControlCondition;281}; /* class PluginServices */282 283} // namespace fair::mq284 285#endif /* FAIR_MQ_PLUGINSERVICES_H */