Fix #214: Add means to unregister signal handler

This commit is contained in:
Osama Ghanem
2021-11-28 16:30:49 +02:00
committed by Stanislav Angelovič
parent 442670ec18
commit 41d33117cc
7 changed files with 130 additions and 0 deletions

View File

@ -216,6 +216,17 @@ namespace sdbus {
std::string interfaceName_;
};
class SignalUnsubscriber
{
public:
SignalUnsubscriber(IProxy& proxy, const std::string& signalName);
void onInterface(std::string interfaceName);
private:
IProxy& proxy_;
const std::string& signalName_;
};
class PropertyGetter
{
public:

View File

@ -671,6 +671,21 @@ namespace sdbus {
});
}
/*** ------------------ ***/
/*** SignalUnsubscriber ***/
/*** ------------------ ***/
inline SignalUnsubscriber::SignalUnsubscriber(IProxy& proxy, const std::string& signalName)
: proxy_(proxy)
, signalName_(signalName)
{
}
inline void SignalUnsubscriber::onInterface(std::string interfaceName)
{
proxy_.unregisterSignalHandler(interfaceName, signalName_);
}
/*** -------------- ***/
/*** PropertyGetter ***/
/*** -------------- ***/

View File

@ -143,6 +143,17 @@ namespace sdbus {
, const std::string& signalName
, signal_handler signalHandler ) = 0;
/*!
* @brief Unregisters the handler of the desired signal
*
* @param[in] interfaceName Name of an interface that the signal belongs to
* @param[in] signalName Name of the signal
*
* @throws sdbus::Error in case of failure
*/
virtual void unregisterSignalHandler( const std::string& interfaceName
, const std::string& signalName ) = 0;
/*!
* @brief Finishes the registration of signal handlers
*
@ -229,6 +240,23 @@ namespace sdbus {
*/
[[nodiscard]] SignalSubscriber uponSignal(const std::string& signalName);
/*!
* @brief Unregisters signal handler of a given signal of the proxied 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 proxied D-Bus object
*
@ -369,6 +397,11 @@ 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);

View File

@ -167,6 +167,16 @@ void Proxy::registerSignalHandler( const std::string& interfaceName
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register signal handler: handler already exists", EINVAL);
}
void Proxy::unregisterSignalHandler( const std::string& interfaceName
, const std::string& signalName )
{
auto& interface = interfaces_[interfaceName];
auto removeResult = interface.signals_.erase(signalName);
SDBUS_THROW_ERROR_IF(removeResult == 0, "Failed to unregister signal handler: handler not exists", EINVAL);
}
void Proxy::finishRegistration()
{
registerSignalHandlers(*connection_);

View File

@ -58,6 +58,9 @@ namespace sdbus::internal {
void registerSignalHandler( const std::string& interfaceName
, const std::string& signalName
, signal_handler signalHandler ) override;
void unregisterSignalHandler( const std::string& interfaceName
, const std::string& signalName ) override;
void finishRegistration() override;
void unregister() override;

View File

@ -114,3 +114,50 @@ TEST_F(SdbusTestObject, CanAccessAssociatedSignalMessageInSignalHandler)
ASSERT_THAT(m_proxy->m_signalMsg, NotNull());
ASSERT_THAT(m_proxy->m_signalMemberName, Eq("simpleSignal"));
}
TEST_F(SdbusTestObject, UnregisterSignalHandler)
{
ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler());
m_adaptor->emitSimpleSignal();
ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal));
}
TEST_F(SdbusTestObject, UnregisterSignalHandlerForSomeProxies)
{
auto proxy1 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH);
auto proxy2 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH);
ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler());
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(proxy1->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal));
ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal));
}
TEST_F(SdbusTestObject, FailsUnregisterSignalHandlerTwice)
{
ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler());
ASSERT_THROW(m_proxy->unregisterSimpleSignalHandler(), sdbus::Error);
}
TEST_F(SdbusTestObject, ReRegisterSignalHandler)
{
// unregister simple-signal handler
ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler());
m_adaptor->emitSimpleSignal();
ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal));
// re-register simple-signal handler
ASSERT_NO_THROW(m_proxy->reRegisterSimpleSignalHandler());
m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal));
}

View File

@ -169,6 +169,17 @@ public:
proxy_.callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME);
}
void unregisterSimpleSignalHandler()
{
proxy_.muteSignal("simpleSignal").onInterface(INTERFACE_NAME);
}
void reRegisterSimpleSignalHandler()
{
proxy_.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); });
proxy_.finishRegistration();
}
public:
uint32_t action()
{