1 #pragma once 2 #include <dbus/filter.hpp> 3 #include <dbus/match.hpp> 4 #include <dbus_singleton.hpp> 5 #include <crow/app.h> 6 #include <boost/container/flat_map.hpp> 7 8 namespace crow { 9 namespace dbus_monitor { 10 11 struct DbusWebsocketSession { 12 std::vector<std::unique_ptr<dbus::match>> matches; 13 std::vector<dbus::filter> filters; 14 }; 15 16 static boost::container::flat_map<crow::websocket::connection*, 17 DbusWebsocketSession> 18 sessions; 19 20 void on_property_update(dbus::filter& filter, boost::system::error_code ec, 21 dbus::message s) { 22 if (!ec) { 23 std::string object_name; 24 std::vector<std::pair<std::string, dbus::dbus_variant>> values; 25 s.unpack(object_name, values); 26 nlohmann::json j; 27 for (auto& value : values) { 28 boost::apply_visitor([&](auto val) { j[s.get_path()] = val; }, 29 value.second); 30 } 31 auto data_to_send = j.dump(); 32 33 for (auto& session : sessions) { 34 session.first->send_text(data_to_send); 35 } 36 } 37 filter.async_dispatch([&](boost::system::error_code ec, dbus::message s) { 38 on_property_update(filter, ec, s); 39 }); 40 }; 41 42 template <typename... Middlewares> 43 void request_routes(Crow<Middlewares...>& app) { 44 CROW_ROUTE(app, "/dbus_monitor") 45 .websocket() 46 .onopen([&](crow::websocket::connection& conn) { 47 std::string path_namespace(conn.req.url_params.get("path_namespace")); 48 if (path_namespace.empty()) { 49 conn.send_text( 50 nlohmann::json({"error", "Did not specify path_namespace"})); 51 conn.close("error"); 52 } 53 sessions[&conn] = DbusWebsocketSession(); 54 std::string match_string( 55 "type='signal'," 56 "interface='org.freedesktop.DBus.Properties'," 57 "path_namespace='" + 58 path_namespace + "'"); 59 sessions[&conn].matches.push_back(std::make_unique<dbus::match>( 60 crow::connections::system_bus, std::move(match_string))); 61 62 sessions[&conn].filters.emplace_back( 63 crow::connections::system_bus, [path_namespace](dbus::message m) { 64 return m.get_member() == "PropertiesChanged" && 65 boost::starts_with(m.get_path(), path_namespace); 66 }); 67 auto& this_filter = sessions[&conn].filters.back(); 68 this_filter.async_dispatch( 69 [&](boost::system::error_code ec, dbus::message s) { 70 on_property_update(this_filter, ec, s); 71 }); 72 73 }) 74 .onclose([&](crow::websocket::connection& conn, 75 const std::string& reason) { sessions.erase(&conn); }) 76 .onmessage([&](crow::websocket::connection& conn, const std::string& data, 77 bool is_binary) { 78 CROW_LOG_ERROR << "Got unexpected message from client on sensorws"; 79 }); 80 } 81 } // namespace redfish 82 } // namespace crow 83