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 /**
24  * @brief Populate the collection "Members" from a GetSubTreePaths search of
25  *        inventory
26  *
27  * @param[i,o] asyncResp  Async response object
28  * @param[i]   collectionPath  Redfish collection path which is used for the
29  *             Members Redfish Path
30  * @param[i]   interfaces  List of interfaces to constrain the GetSubTree search
31  * @param[in]  subtree     D-Bus base path to constrain search to.
32  *
33  * @return void
34  */
35 inline void
36     getCollectionMembers(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
37                          const boost::urls::url& collectionPath,
38                          std::span<const std::string_view> interfaces,
39                          const char* subtree = "/xyz/openbmc_project/inventory")
40 {
41     BMCWEB_LOG_DEBUG("Get collection members for: {}", collectionPath.buffer());
42     dbus::utility::getSubTreePaths(
43         subtree, 0, interfaces,
44         [collectionPath, asyncResp{std::move(asyncResp)}](
45             const boost::system::error_code& ec,
46             const dbus::utility::MapperGetSubTreePathsResponse& objects) {
47         if (ec == boost::system::errc::io_error)
48         {
49             asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
50             asyncResp->res.jsonValue["Members@odata.count"] = 0;
51             return;
52         }
53 
54         if (ec)
55         {
56             BMCWEB_LOG_DEBUG("DBUS response error {}", ec.value());
57             messages::internalError(asyncResp->res);
58             return;
59         }
60 
61         std::vector<std::string> pathNames;
62         for (const auto& object : objects)
63         {
64             sdbusplus::message::object_path path(object);
65             std::string leaf = path.filename();
66             if (leaf.empty())
67             {
68                 continue;
69             }
70             pathNames.push_back(leaf);
71         }
72         std::ranges::sort(pathNames, AlphanumLess<std::string>());
73 
74         nlohmann::json& members = asyncResp->res.jsonValue["Members"];
75         members = nlohmann::json::array();
76         for (const std::string& leaf : pathNames)
77         {
78             boost::urls::url url = collectionPath;
79             crow::utility::appendUrlPieces(url, leaf);
80             nlohmann::json::object_t member;
81             member["@odata.id"] = std::move(url);
82             members.emplace_back(std::move(member));
83         }
84         asyncResp->res.jsonValue["Members@odata.count"] = members.size();
85         });
86 }
87 
88 } // namespace collection_util
89 } // namespace redfish
90