forked from Kistler-Group/sdbus-cpp
refactor: improve Proxy signal subscription (#389)
This makes D-Bus proxy signal registration more flexible, more dynamic, and less error-prone since no `finishRegistration()` call is needed. A proxy can register to a signal at any time during its lifetime, and can unregister freely by simply destroying the associated slot.
This commit is contained in:
committed by
Stanislav Angelovic
parent
e3040c0998
commit
bdd0bc2c27
@@ -129,6 +129,10 @@ namespace sdbus {
|
||||
SignalSubscriber(IProxy& proxy, const std::string& signalName);
|
||||
SignalSubscriber& onInterface(std::string interfaceName);
|
||||
template <typename _Function> void call(_Function&& callback);
|
||||
template <typename _Function> [[nodiscard]] Slot call(_Function&& callback, request_slot_t);
|
||||
|
||||
private:
|
||||
template <typename _Function> signal_handler makeSignalHandler(_Function&& callback);
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
@@ -136,17 +140,6 @@ namespace sdbus {
|
||||
std::string interfaceName_;
|
||||
};
|
||||
|
||||
class SignalUnsubscriber
|
||||
{
|
||||
public:
|
||||
SignalUnsubscriber(IProxy& proxy, const std::string& signalName);
|
||||
void onInterface(const std::string& interfaceName);
|
||||
|
||||
private:
|
||||
IProxy& proxy_;
|
||||
const std::string& signalName_;
|
||||
};
|
||||
|
||||
class PropertyGetter
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -307,7 +307,24 @@ namespace sdbus {
|
||||
|
||||
proxy_.registerSignalHandler( interfaceName_
|
||||
, signalName_
|
||||
, [callback = std::forward<_Function>(callback)](Signal signal)
|
||||
, makeSignalHandler(std::forward<_Function>(callback)) );
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline Slot SignalSubscriber::call(_Function&& callback, request_slot_t)
|
||||
{
|
||||
assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function
|
||||
|
||||
return proxy_.registerSignalHandler( interfaceName_
|
||||
, signalName_
|
||||
, makeSignalHandler(std::forward<_Function>(callback))
|
||||
, request_slot );
|
||||
}
|
||||
|
||||
template <typename _Function>
|
||||
inline signal_handler SignalSubscriber::makeSignalHandler(_Function&& callback)
|
||||
{
|
||||
return [callback = std::forward<_Function>(callback)](Signal signal)
|
||||
{
|
||||
// Create a tuple of callback input arguments' types, which will be used
|
||||
// as a storage for the argument values deserialized from the signal message.
|
||||
@@ -343,22 +360,7 @@ namespace sdbus {
|
||||
// Invoke callback with input arguments from the tuple.
|
||||
sdbus::apply(callback, signalArgs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*** ------------------ ***/
|
||||
/*** SignalUnsubscriber ***/
|
||||
/*** ------------------ ***/
|
||||
|
||||
inline SignalUnsubscriber::SignalUnsubscriber(IProxy& proxy, const std::string& signalName)
|
||||
: proxy_(proxy)
|
||||
, signalName_(signalName)
|
||||
{
|
||||
}
|
||||
|
||||
inline void SignalUnsubscriber::onInterface(const std::string& interfaceName)
|
||||
{
|
||||
proxy_.unregisterSignalHandler(interfaceName, signalName_);
|
||||
};
|
||||
}
|
||||
|
||||
/*** -------------- ***/
|
||||
|
||||
+19
-36
@@ -197,6 +197,9 @@ namespace sdbus {
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signalHandler Callback that implements the body of the signal handler
|
||||
*
|
||||
* A signal can be subscribed to and unsubscribed from at any time during proxy
|
||||
* lifetime. The subscription is active immediately after the call.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void registerSignalHandler( const std::string& interfaceName
|
||||
@@ -204,28 +207,27 @@ namespace sdbus {
|
||||
, signal_handler signalHandler ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Unregisters the handler of the desired signal
|
||||
* @brief Registers a handler for the desired signal emitted by the D-Bus object
|
||||
*
|
||||
* @param[in] interfaceName Name of an interface that the signal belongs to
|
||||
* @param[in] signalName Name of the signal
|
||||
* @param[in] signalHandler Callback that implements the body of the signal handler
|
||||
*
|
||||
* @return RAII-style slot handle representing the ownership of the subscription
|
||||
*
|
||||
* A signal can be subscribed to and unsubscribed from at any time during proxy
|
||||
* lifetime. The subscription is active immediately after the call. The subscription
|
||||
* is unregistered when the client destroys the returned slot object.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void unregisterSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName ) = 0;
|
||||
[[nodiscard]] virtual Slot registerSignalHandler( const std::string& interfaceName
|
||||
, const std::string& signalName
|
||||
, signal_handler signalHandler
|
||||
, request_slot_t ) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Finishes the registration of signal handlers
|
||||
*
|
||||
* The method physically subscribes to the desired signals.
|
||||
* Must be called only once, after all signals have been registered already.
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
virtual void finishRegistration() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Unregisters proxy's signal handlers and stops receving replies to pending async calls
|
||||
* @brief Unregisters proxy's signal handlers and stops receiving replies to pending async calls
|
||||
*
|
||||
* Unregistration is done automatically also in proxy's destructor. This method makes
|
||||
* sense if, in the process of proxy removal, we need to make sure that callbacks
|
||||
@@ -291,6 +293,9 @@ namespace sdbus {
|
||||
* in a message and D-Bus signatures automatically deduced from the parameters
|
||||
* of the provided native signal callback.
|
||||
*
|
||||
* A signal can be subscribed to and unsubscribed from at any time during proxy
|
||||
* lifetime. The subscription is active immediately after the call.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object_.uponSignal("fooSignal").onInterface("com.kistler.foo").call([this](int arg1, double arg2){ this->onFooSignal(arg1, arg2); });
|
||||
@@ -300,23 +305,6 @@ namespace sdbus {
|
||||
*/
|
||||
[[nodiscard]] SignalSubscriber uponSignal(const std::string& signalName);
|
||||
|
||||
/*!
|
||||
* @brief Unregisters signal handler of a given signal of the D-Bus object
|
||||
*
|
||||
* @param[in] signalName Name of the signal
|
||||
* @return A helper object for convenient unregistration of the signal handler
|
||||
*
|
||||
* This is a high-level, convenience way of unregistering a D-Bus signal's handler.
|
||||
*
|
||||
* Example of use:
|
||||
* @code
|
||||
* object_.muteSignal("fooSignal").onInterface("com.kistler.foo");
|
||||
* @endcode
|
||||
*
|
||||
* @throws sdbus::Error in case of failure
|
||||
*/
|
||||
[[nodiscard]] SignalUnsubscriber muteSignal(const std::string& signalName);
|
||||
|
||||
/*!
|
||||
* @brief Gets value of a property of the D-Bus object
|
||||
*
|
||||
@@ -543,11 +531,6 @@ namespace sdbus {
|
||||
return SignalSubscriber(*this, signalName);
|
||||
}
|
||||
|
||||
inline SignalUnsubscriber IProxy::muteSignal(const std::string& signalName)
|
||||
{
|
||||
return SignalUnsubscriber(*this, signalName);
|
||||
}
|
||||
|
||||
inline PropertyGetter IProxy::getProperty(const std::string& propertyName)
|
||||
{
|
||||
return PropertyGetter(*this, propertyName);
|
||||
|
||||
@@ -83,9 +83,10 @@ namespace sdbus {
|
||||
* methods. So the _Interfaces template parameter is a list of sdbus-c++-xml2cpp-generated
|
||||
* proxy-side interface classes representing interfaces of the corresponding remote D-Bus object.
|
||||
*
|
||||
* In the final proxy class inherited from ProxyInterfaces, it is necessary to finish proxy
|
||||
* registration in class constructor (`finishRegistration();`), and, conversely, unregister
|
||||
* the proxy in class destructor (`unregister();`).
|
||||
* In the final adaptor class inherited from ProxyInterfaces, one needs to make sure:
|
||||
* 1. to call `registerProxy();` in the class constructor, and, conversely,
|
||||
* 2. to call `unregisterProxy();` in the class destructor,
|
||||
* so that the signals are subscribed to and unsubscribed from at a proper time.
|
||||
*
|
||||
***********************************************/
|
||||
template <typename... _Interfaces>
|
||||
@@ -173,15 +174,15 @@ namespace sdbus {
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Finishes proxy registration and makes the proxy ready for use
|
||||
* @brief Registers handlers for D-Bus signals of the remote object
|
||||
*
|
||||
* This function must be called in the constructor of the final proxy class that implements ProxyInterfaces.
|
||||
*
|
||||
* For more information, see underlying @ref IProxy::finishRegistration()
|
||||
* See also @ref IProxy::registerSignalHandler()
|
||||
*/
|
||||
void registerProxy()
|
||||
{
|
||||
getProxy().finishRegistration();
|
||||
(_Interfaces::registerProxy(), ...);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -54,6 +54,10 @@ namespace sdbus {
|
||||
|
||||
~Peer_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
void Ping()
|
||||
{
|
||||
@@ -89,6 +93,10 @@ namespace sdbus {
|
||||
|
||||
~Introspectable_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
std::string Introspect()
|
||||
{
|
||||
@@ -109,6 +117,17 @@ namespace sdbus {
|
||||
protected:
|
||||
Properties_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
Properties_proxy(const Properties_proxy&) = delete;
|
||||
Properties_proxy& operator=(const Properties_proxy&) = delete;
|
||||
Properties_proxy(Properties_proxy&&) = default;
|
||||
Properties_proxy& operator=(Properties_proxy&&) = default;
|
||||
|
||||
~Properties_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
proxy_
|
||||
->uponSignal("PropertiesChanged")
|
||||
@@ -121,13 +140,6 @@ namespace sdbus {
|
||||
});
|
||||
}
|
||||
|
||||
Properties_proxy(const Properties_proxy&) = delete;
|
||||
Properties_proxy& operator=(const Properties_proxy&) = delete;
|
||||
Properties_proxy(Properties_proxy&&) = default;
|
||||
Properties_proxy& operator=(Properties_proxy&&) = default;
|
||||
|
||||
~Properties_proxy() = default;
|
||||
|
||||
virtual void onPropertiesChanged( const std::string& interfaceName
|
||||
, const std::map<std::string, sdbus::Variant>& changedProperties
|
||||
, const std::vector<std::string>& invalidatedProperties ) = 0;
|
||||
@@ -198,6 +210,17 @@ namespace sdbus {
|
||||
protected:
|
||||
ObjectManager_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(&proxy)
|
||||
{
|
||||
}
|
||||
|
||||
ObjectManager_proxy(const ObjectManager_proxy&) = delete;
|
||||
ObjectManager_proxy& operator=(const ObjectManager_proxy&) = delete;
|
||||
ObjectManager_proxy(ObjectManager_proxy&&) = default;
|
||||
ObjectManager_proxy& operator=(ObjectManager_proxy&&) = default;
|
||||
|
||||
~ObjectManager_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
proxy_
|
||||
->uponSignal("InterfacesAdded")
|
||||
@@ -217,13 +240,6 @@ namespace sdbus {
|
||||
});
|
||||
}
|
||||
|
||||
ObjectManager_proxy(const ObjectManager_proxy&) = delete;
|
||||
ObjectManager_proxy& operator=(const ObjectManager_proxy&) = delete;
|
||||
ObjectManager_proxy(ObjectManager_proxy&&) = default;
|
||||
ObjectManager_proxy& operator=(ObjectManager_proxy&&) = default;
|
||||
|
||||
~ObjectManager_proxy() = default;
|
||||
|
||||
virtual void onInterfacesAdded( const sdbus::ObjectPath& objectPath
|
||||
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties) = 0;
|
||||
virtual void onInterfacesRemoved( const sdbus::ObjectPath& objectPath
|
||||
|
||||
Reference in New Issue
Block a user