xref: /openbmc/bmcweb/include/dbus_monitor.hpp (revision 4859bdbafbb2b78ae414fb050ad197db2f2cb28b)
1 #pragma once
2 #include <dbus_singleton.hpp>
3 #include <sdbusplus/bus/match.hpp>
4 #include <crow/app.h>
5 #include <boost/container/flat_map.hpp>
6 
7 namespace crow {
8 namespace dbus_monitor {
9 
10 struct DbusWebsocketSession {
11   std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
12 };
13 
14 static boost::container::flat_map<crow::websocket::Connection*,
15                                   DbusWebsocketSession>
16     sessions;
17 
18 int onPropertyUpdate(sd_bus_message* m, void* userdata,
19                      sd_bus_error* ret_error) {
20   if (ret_error == nullptr || sd_bus_error_is_set(ret_error)) {
21     BMCWEB_LOG_ERROR << "Sdbus error in on_property_update";
22     return 0;
23   }
24   sdbusplus::message::message message(m);
25   std::string objectName;
26   std::vector<
27       std::pair<std::string, sdbusplus::message::variant<
28                                  std::string, bool, int64_t, uint64_t, double>>>
29       values;
30   message.read(objectName, values);
31   nlohmann::json j;
32   const std::string& path = message.get_path();
33   for (auto& value : values) {
34     mapbox::util::apply_visitor([&](auto&& val) { j[path] = val; },
35                                 value.second);
36   }
37   std::string dataToSend = j.dump();
38 
39   for (const std::pair<crow::websocket::Connection*, DbusWebsocketSession>&
40            session : sessions) {
41     session.first->sendText(dataToSend);
42   }
43 };
44 
45 template <typename... Middlewares>
46 void requestRoutes(Crow<Middlewares...>& app) {
47   BMCWEB_ROUTE(app, "/dbus_monitor")
48       .websocket()
49       .onopen([&](crow::websocket::Connection& conn) {
50         std::string pathNamespace(conn.req.urlParams.get("path_namespace"));
51         if (pathNamespace.empty()) {
52           conn.sendText(
53               nlohmann::json({"error", "Did not specify path_namespace"})
54                   .dump());
55           conn.close("error");
56         }
57         sessions[&conn] = DbusWebsocketSession();
58         std::string matchString(
59             "type='signal',"
60             "interface='org.freedesktop.DBus.Properties',"
61             "path_namespace='" +
62             pathNamespace + "'");
63         sessions[&conn].matches.emplace_back(
64             std::make_unique<sdbusplus::bus::match::match>(
65                 *crow::connections::systemBus, matchString, onPropertyUpdate));
66       })
67       .onclose([&](crow::websocket::Connection& conn,
68                    const std::string& reason) { sessions.erase(&conn); })
69       .onmessage([&](crow::websocket::Connection& conn, const std::string& data,
70                      bool is_binary) {
71         BMCWEB_LOG_ERROR << "Got unexpected message from client on sensorws";
72       });
73 }
74 }  // namespace dbus_monitor
75 }  // namespace crow
76