1 #pragma once 2 3 #include "async_resp.hpp" 4 #include "dbus_utility.hpp" 5 #include "error_messages.hpp" 6 #include "http/utility.hpp" 7 #include "human_sort.hpp" 8 9 #include <boost/url/url.hpp> 10 #include <nlohmann/json.hpp> 11 12 #include <ranges> 13 #include <span> 14 #include <string> 15 #include <string_view> 16 #include <vector> 17 18 namespace redfish 19 { 20 namespace collection_util 21 { 22 23 inline void handleCollectionMembers( 24 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 25 const boost::urls::url& collectionPath, 26 const nlohmann::json::json_pointer& jsonKeyName, 27 const boost::system::error_code& ec, 28 const dbus::utility::MapperGetSubTreePathsResponse& objects) 29 { 30 if (jsonKeyName.empty()) 31 { 32 messages::internalError(asyncResp->res); 33 BMCWEB_LOG_ERROR("Json Key called empty. Did you mean /Members?"); 34 return; 35 } 36 nlohmann::json::json_pointer jsonCountKeyName = jsonKeyName; 37 std::string back = jsonCountKeyName.back(); 38 jsonCountKeyName.pop_back(); 39 jsonCountKeyName /= back + "@odata.count"; 40 41 if (ec == boost::system::errc::io_error) 42 { 43 asyncResp->res.jsonValue[jsonKeyName] = nlohmann::json::array(); 44 asyncResp->res.jsonValue[jsonCountKeyName] = 0; 45 return; 46 } 47 48 if (ec) 49 { 50 BMCWEB_LOG_DEBUG("DBUS response error {}", ec.value()); 51 messages::internalError(asyncResp->res); 52 return; 53 } 54 55 std::vector<std::string> pathNames; 56 for (const auto& object : objects) 57 { 58 sdbusplus::message::object_path path(object); 59 std::string leaf = path.filename(); 60 if (leaf.empty()) 61 { 62 continue; 63 } 64 pathNames.push_back(leaf); 65 } 66 std::ranges::sort(pathNames, AlphanumLess<std::string>()); 67 68 nlohmann::json& members = asyncResp->res.jsonValue[jsonKeyName]; 69 members = nlohmann::json::array(); 70 for (const std::string& leaf : pathNames) 71 { 72 boost::urls::url url = collectionPath; 73 crow::utility::appendUrlPieces(url, leaf); 74 nlohmann::json::object_t member; 75 member["@odata.id"] = std::move(url); 76 members.emplace_back(std::move(member)); 77 } 78 asyncResp->res.jsonValue[jsonCountKeyName] = members.size(); 79 } 80 81 /** 82 * @brief Populate the collection members from a GetSubTreePaths search of 83 * inventory 84 * 85 * @param[i,o] asyncResp Async response object 86 * @param[i] collectionPath Redfish collection path which is used for the 87 * Members Redfish Path 88 * @param[i] interfaces List of interfaces to constrain the GetSubTree search 89 * @param[in] subtree D-Bus base path to constrain search to. 90 * @param[in] jsonKeyName Key name in which the collection members will be 91 * stored. 92 * 93 * @return void 94 */ 95 inline void getCollectionToKey( 96 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 97 const boost::urls::url& collectionPath, 98 std::span<const std::string_view> interfaces, const std::string& subtree, 99 const nlohmann::json::json_pointer& jsonKeyName) 100 { 101 BMCWEB_LOG_DEBUG("Get collection members for: {}", collectionPath.buffer()); 102 dbus::utility::getSubTreePaths( 103 subtree, 0, interfaces, 104 std::bind_front(handleCollectionMembers, asyncResp, collectionPath, 105 jsonKeyName)); 106 } 107 inline void getCollectionMembers( 108 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 109 const boost::urls::url& collectionPath, 110 std::span<const std::string_view> interfaces, const std::string& subtree) 111 { 112 getCollectionToKey(asyncResp, collectionPath, interfaces, subtree, 113 nlohmann::json::json_pointer("/Members")); 114 } 115 116 } // namespace collection_util 117 } // namespace redfish 118