Skip to content

Commit

Permalink
Implement property invalidation signal
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Haefner committed Dec 15, 2020
1 parent f7c3427 commit ed3eb84
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 9 deletions.
20 changes: 13 additions & 7 deletions include/simppl/clientside.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,12 @@ struct ClientPropertyBase
{
friend struct StubBase;

typedef void (*eval_type)(ClientPropertyBase*, DBusMessageIter&);
typedef void (*eval_type)(ClientPropertyBase*, DBusMessageIter*);


ClientPropertyBase(const char* name, StubBase* iface);

void eval(DBusMessageIter& iter)
void eval(DBusMessageIter* iter)
{
eval_(this, iter);
}
Expand Down Expand Up @@ -232,15 +232,21 @@ struct ClientProperty
private:

static
void __eval(ClientPropertyBase* obj, DBusMessageIter& iter)
void __eval(ClientPropertyBase* obj, DBusMessageIter* iter)
{
ClientProperty* that = (ClientProperty*)obj;

data_type d;
detail::PropertyCodec<data_type>::decode(iter, d);

if (that->f_)
that->f_(CallState(42), d);
{
if (iter)
{
data_type d;
detail::PropertyCodec<data_type>::decode(*iter, d);
that->f_(CallState(42), d);
}
else
that->f_(CallState(new Error("simppl.dbus.Invalid")), data_type());
}
}


Expand Down
13 changes: 13 additions & 0 deletions include/simppl/serverside.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,13 +265,26 @@ struct BaseProperty : ServerPropertyBase
detail::PropertyCodec<DataT>::encode(iter, that->t_.template get<cb_type>() ? (*that->t_.template get<cb_type>())() : *that->t_.template get<DataT>());
}

/**
* Shall be used with properties implementing on_read callback in order
* to send property changes. Not suitable with value holding properties.
*/
void notify(const DataT& data)
{
this->parent_->send_property_change(this->name_, [this, data](DBusMessageIter& iter){
detail::PropertyCodec<DataT>::encode(iter, data);
});
}

/**
* Send an invalidation message, shall only be used in conjunction with the notify message and
* the on_read callback. Currently, value holding properties cannot be invalidated.
*/
void invalidate()
{
this->parent_->send_property_invalidate(this->name_);
}

/// set callback for each read
void on_read(cb_type cb)
{
Expand Down
1 change: 1 addition & 0 deletions include/simppl/skeletonbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ struct SkeletonBase
}

void send_property_change(const char* prop, std::function<void(DBusMessageIter&)>&& f);
void send_property_invalidate(const char* prop);

void send_signal(const char* signame, std::function<void(DBusMessageIter&)>&& f);

Expand Down
25 changes: 25 additions & 0 deletions src/skeletonbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "simppl/interface.h"
#include "simppl/string.h"
#include "simppl/vector.h"
#include "simppl/map.h"

#define SIMPPL_SKELETONBASE_CPP
#include "simppl/serverside.h"
Expand Down Expand Up @@ -411,6 +412,30 @@ void SkeletonBase::send_signal(const char* signame, std::function<void(DBusMessa
}


void SkeletonBase::send_property_invalidate(const char* prop)
{
// dummy map for changed properties, is empty -> type doesn't matter
static std::map<int, int> m;

message_ptr_t msg = make_message(dbus_message_new_signal(objectpath(), "org.freedesktop.DBus.Properties", "PropertiesChanged"));

DBusMessageIter iter;
dbus_message_iter_init_append(msg.get(), &iter);

encode(iter, iface());
encode(iter, m);

// the invalidated property as the only element in a vector
DBusMessageIter inv_iter;
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &inv_iter);
encode(inv_iter, prop);

dbus_message_iter_close_container(&iter, &inv_iter);

dbus_connection_send(disp_->conn_, msg.get(), nullptr);
}


void SkeletonBase::send_property_change(const char* prop, std::function<void(DBusMessageIter&)>&& f)
{
static std::vector<std::string> invalid;
Expand Down
28 changes: 26 additions & 2 deletions src/stubbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,6 @@ PendingCall StubBase::get_property_async(const char* name)
message_ptr_t StubBase::get_property(const char* name)
{
message_ptr_t msg = make_message(dbus_message_new_method_call(busname().c_str(), objectpath(), "org.freedesktop.DBus.Properties", "Get"));
DBusPendingCall* pending = nullptr;

DBusMessageIter iter;
dbus_message_iter_init_append(msg.get(), &iter);
Expand Down Expand Up @@ -435,7 +434,32 @@ void StubBase::try_handle_signal(DBusMessage* msg)
{
if (property_name == p->name_)
{
p->eval(item_iterator);
p->eval(&item_iterator);
break;
}

p = p->next_;
}

// advance to next element
dbus_message_iter_next(&iter);
}

// check for invalidated properties
dbus_message_iter_next(&it);
dbus_message_iter_recurse(&it, &iter);

while(dbus_message_iter_get_arg_type(&iter) != 0)
{
std::string property_name;
decode(iter, property_name);

auto p = properties_;
while(p)
{
if (property_name == p->name_)
{
p->eval(nullptr);
break;
}

Expand Down
65 changes: 65 additions & 0 deletions tests/properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,28 @@ struct InvalidSetterClient : simppl::dbus::Stub<Properties>
};


struct InvalidatedPropertyClient : simppl::dbus::Stub<Properties>
{
InvalidatedPropertyClient(simppl::dbus::Dispatcher& d)
: simppl::dbus::Stub<Properties>(d, "s")
{
connected >> [this](simppl::dbus::ConnectionState s){
EXPECT_EQ(simppl::dbus::ConnectionState::Connected, s);

data.attach() >> [this](simppl::dbus::CallState cs, int) {
++calls_;
EXPECT_FALSE((bool)cs);
EXPECT_STREQ(cs.what(), "simppl.dbus.Invalid");

shutdown();
};
};
}

int calls_ = 0;
};


struct Server : simppl::dbus::Skeleton<Properties>
{
Server(simppl::dbus::Dispatcher& d, const char* rolename)
Expand Down Expand Up @@ -383,6 +405,37 @@ struct ErrorThrowingPropertyServer : simppl::dbus::Skeleton<Properties>
};


struct InvalidatedPropertyServer : simppl::dbus::Skeleton<Properties>
{
InvalidatedPropertyServer(simppl::dbus::Dispatcher& d)
: simppl::dbus::Skeleton<Properties>(d, "s")
, countdown_(3)
{
// initialize attributes callbacks
data.on_read([](){

throw simppl::dbus::Error("simppl.dbus.Invalid");

// complete lambda with return value
return 42;
});

// just send message
shutdown >> [this](){

if(--countdown_ > 0)
{
data.invalidate(); // sending error simppl.dbus.Invalid
}
else
disp().stop();
};
}

int countdown_;
};


} // anonymous namespace


Expand Down Expand Up @@ -554,3 +607,15 @@ TEST(Properties, get_async_error)

d.run();
}


TEST(Properties, invalidate)
{
simppl::dbus::Dispatcher d("bus:session");

InvalidatedPropertyServer s(d);
InvalidatedPropertyClient c(d);

d.run();
EXPECT_EQ(c.calls_, 3);
}

0 comments on commit ed3eb84

Please sign in to comment.