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