1 #include <boost/asio/io_context.hpp>
2 #include <boost/asio/signal_set.hpp>
3 #include <sdbusplus/asio/connection.hpp>
4 #include <sdbusplus/asio/object_server.hpp>
5 #include <sdbusplus/asio/property.hpp>
6 #include <sdbusplus/bus.hpp>
7 
8 #include <iostream>
9 
10 const std::string demoServiceName = "demo.service";
11 const std::string demoObjectPath = "/xyz/demo";
12 const std::string demoInterfaceName = "xyz.demo";
13 const std::string propertyGrettingName = "Greetings";
14 const std::string propertyGoodbyesName = "Goodbyes";
15 
16 class Application
17 {
18   public:
19     Application(boost::asio::io_context& ioc, sdbusplus::asio::connection& bus,
20                 sdbusplus::asio::object_server& objServer) :
21         ioc_(ioc),
22         bus_(bus), objServer_(objServer)
23     {
24         demo_ = objServer_.add_unique_interface(
25             demoObjectPath, demoInterfaceName,
26             [this](sdbusplus::asio::dbus_interface& demo) {
27                 demo.register_property_r<std::string>(
28                     propertyGrettingName, sdbusplus::vtable::property_::const_,
29                     [this](const auto&) { return greetings_; });
30 
31                 demo.register_property_rw<std::string>(
32                     propertyGoodbyesName,
33                     sdbusplus::vtable::property_::emits_change,
34                     [this](const auto& newPropertyValue, const auto&) {
35                         goodbyes_ = newPropertyValue;
36                         return true;
37                     },
38                     [this](const auto&) { return goodbyes_; });
39             });
40     }
41 
42     uint32_t fatalErrors() const
43     {
44         return fatalErrors_;
45     }
46 
47     auto getFailed()
48     {
49         return [this](boost::system::error_code error) {
50             std::cerr << "Error: getProperty failed " << error << "\n";
51             ++fatalErrors_;
52         };
53     }
54 
55     void asyncReadPropertyWithIncorrectType()
56     {
57         sdbusplus::asio::getProperty<uint32_t>(
58             bus_, demoServiceName, demoObjectPath, demoInterfaceName,
59             propertyGrettingName,
60             [this](boost::system::error_code ec, uint32_t) {
61                 if (ec)
62                 {
63                     std::cout
64                         << "As expected failed to getProperty with wrong type: "
65                         << ec << "\n";
66                     return;
67                 }
68 
69                 std::cerr << "Error: it was expected to fail getProperty due "
70                              "to wrong type\n";
71                 ++fatalErrors_;
72             });
73     }
74 
75     void asyncReadProperties()
76     {
77         sdbusplus::asio::getProperty<std::string>(
78             bus_, demoServiceName, demoObjectPath, demoInterfaceName,
79             propertyGrettingName,
80             [this](boost::system::error_code ec, std::string value) {
81                 if (ec)
82                 {
83                     getFailed();
84                     return;
85                 }
86                 std::cout << "Greetings value is: " << value << "\n";
87             });
88 
89         sdbusplus::asio::getProperty<std::string>(
90             bus_, demoServiceName, demoObjectPath, demoInterfaceName,
91             propertyGoodbyesName,
92             [this](boost::system::error_code ec, std::string value) {
93                 if (ec)
94                 {
95                     getFailed();
96                     return;
97                 }
98                 std::cout << "Goodbyes value is: " << value << "\n";
99             });
100     }
101 
102     void asyncChangeProperty()
103     {
104         sdbusplus::asio::setProperty(
105             bus_, demoServiceName, demoObjectPath, demoInterfaceName,
106             propertyGrettingName, "Hi, hey, hello",
107             [this](const boost::system::error_code& ec) {
108                 if (ec)
109                 {
110                     std::cout
111                         << "As expected, failed to set greetings property: "
112                         << ec << "\n";
113                     return;
114                 }
115 
116                 std::cout
117                     << "Error: it was expected to fail to change greetings\n";
118                 ++fatalErrors_;
119             });
120 
121         sdbusplus::asio::setProperty(
122             bus_, demoServiceName, demoObjectPath, demoInterfaceName,
123             propertyGoodbyesName, "Bye bye",
124             [this](const boost::system::error_code& ec) {
125                 if (ec)
126                 {
127                     std::cout
128                         << "Error: it supposed to be ok to change goodbyes "
129                            "property: "
130                         << ec << "\n";
131                     ++fatalErrors_;
132                     return;
133                 }
134                 std::cout << "Changed goodbyes property as expected\n";
135                 boost::asio::post(ioc_, [this] { asyncReadProperties(); });
136             });
137     }
138 
139     void syncChangeGoodbyes(std::string_view value)
140     {
141         goodbyes_ = value;
142         demo_->signal_property(propertyGoodbyesName);
143     }
144 
145   private:
146     boost::asio::io_context& ioc_;
147     sdbusplus::asio::connection& bus_;
148     sdbusplus::asio::object_server& objServer_;
149 
150     std::unique_ptr<sdbusplus::asio::dbus_interface> demo_;
151     std::string greetings_ = "Hello";
152     std::string goodbyes_ = "Bye";
153 
154     uint32_t fatalErrors_ = 0u;
155 };
156 
157 int main(int, char**)
158 {
159     boost::asio::io_context ioc;
160     boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);
161 
162     signals.async_wait(
163         [&ioc](const boost::system::error_code&, const int&) { ioc.stop(); });
164 
165     auto bus = std::make_shared<sdbusplus::asio::connection>(ioc);
166     auto objServer = std::make_unique<sdbusplus::asio::object_server>(bus);
167 
168     bus->request_name(demoServiceName.c_str());
169 
170     Application app(ioc, *bus, *objServer);
171 
172     app.syncChangeGoodbyes("Good bye");
173 
174     boost::asio::post(ioc,
175                       [&app] { app.asyncReadPropertyWithIncorrectType(); });
176     boost::asio::post(ioc, [&app] { app.asyncReadProperties(); });
177     boost::asio::post(ioc, [&app] { app.asyncChangeProperty(); });
178 
179     ioc.run();
180 
181     std::cout << "Fatal errors count: " << app.fatalErrors() << "\n";
182 
183     return app.fatalErrors();
184 }
185