xref: /openbmc/bmcweb/redfish-core/include/utils/collection.hpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
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