Ed Tanous | 911ac31 | 2017-08-15 09:37:42 -0700 | [diff] [blame^] | 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 |