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