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.
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 */