blob: 651e9747f4732fb22de377479f7b3064a6a8082e [file] [log] [blame]
#include <boost/asio.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/bus.hpp>
#include <iostream>
namespace xyz
{
namespace demo
{
const std::string path = "/xyz/demo";
const std::string name = "xyz.demo";
} // namespace demo
} // namespace xyz
namespace name
{
const std::string greetings = "Greetings";
const std::string goodbyes = "Goodbyes";
} // namespace name
namespace utils
{
template <class T>
class Property
{
public:
Property(sdbusplus::asio::connection& bus, std::string_view service,
std::string_view path, std::string_view interface,
std::string_view name) :
bus_(bus),
service_(service), path_(path), interface_(interface), name_(name)
{}
template <class F>
void async_get(F&& callback)
{
bus_.async_method_call(
[callback =
std::move(callback)](const boost::system::error_code& error,
const std::variant<T>& valueVariant) {
if (error)
{
callback(std::nullopt);
return;
}
if (auto value = std::get_if<T>(&valueVariant))
{
callback(*value);
return;
}
callback(std::nullopt);
},
service_, path_, "org.freedesktop.DBus.Properties", "Get",
interface_, name_);
}
template <class F>
void async_set(const T& value, F&& callback)
{
bus_.async_method_call(
[callback = std::move(callback)](
const boost::system::error_code& error) { callback(error); },
service_, path_, "org.freedesktop.DBus.Properties", "Set",
interface_, name_, value);
}
private:
sdbusplus::asio::connection& bus_;
std::string service_;
std::string path_;
std::string interface_;
std::string name_;
};
} // namespace utils
class Application
{
public:
Application(boost::asio::io_context& ioc, sdbusplus::asio::connection& bus,
sdbusplus::asio::object_server& objServer) :
ioc_(ioc),
bus_(bus), objServer_(objServer)
{
demo_ = objServer_.add_interface(xyz::demo::path, xyz::demo::name);
demo_->register_property_r(name::greetings, std::string(),
sdbusplus::vtable::property_::const_,
[this](const auto&) { return greetings_; });
demo_->register_property_rw(
name::goodbyes, std::string(),
sdbusplus::vtable::property_::emits_change,
[this](const auto& newPropertyValue, const auto&) {
goodbyes_ = newPropertyValue;
return 1;
},
[this](const auto&) { return goodbyes_; });
demo_->initialize();
}
~Application()
{
objServer_.remove_interface(demo_);
}
void asyncReadProperties()
{
propertyGreetings.async_get([](std::optional<std::string> value) {
std::cout << "Greetings value is: "
<< value.value_or("std::nullopt") << "\n";
});
propertyGoodbyes.async_get([](std::optional<std::string> value) {
std::cout << "Goodbyes value is: " << value.value_or("std::nullopt")
<< "\n";
});
}
void asyncChangeProperty()
{
propertyGreetings.async_set(
"Hi, hey, hello", [](const boost::system::error_code& error) {
if (error)
{
std::cout
<< "As expected, failed to set greetings property\n";
}
});
propertyGoodbyes.async_set(
"Bye bye", [this](const boost::system::error_code& error) {
if (!error)
{
std::cout << "Changed goodbyes property as expected\n";
}
boost::asio::post(ioc_, [this] { asyncReadProperties(); });
});
}
private:
boost::asio::io_context& ioc_;
sdbusplus::asio::connection& bus_;
sdbusplus::asio::object_server& objServer_;
std::shared_ptr<sdbusplus::asio::dbus_interface> demo_;
std::string greetings_ = "Hello";
std::string goodbyes_ = "Bye";
utils::Property<std::string> propertyGreetings{
bus_, xyz::demo::name, xyz::demo::path, xyz::demo::name,
name::greetings};
utils::Property<std::string> propertyGoodbyes{
bus_, xyz::demo::name, xyz::demo::path, xyz::demo::name,
name::goodbyes};
};
int main(int, char**)
{
boost::asio::io_context ioc;
boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);
signals.async_wait(
[&ioc](const boost::system::error_code&, const int&) { ioc.stop(); });
auto bus = std::make_shared<sdbusplus::asio::connection>(ioc);
auto objServer = std::make_unique<sdbusplus::asio::object_server>(bus);
bus->request_name(xyz::demo::name.c_str());
Application app(ioc, *bus, *objServer);
boost::asio::post(ioc, [&app] { app.asyncReadProperties(); });
boost::asio::post(ioc, [&app] { app.asyncChangeProperty(); });
ioc.run();
return 0;
}