xref: /openbmc/bmcweb/redfish-core/include/registries.hpp (revision 4a102cd48c588d32c0a4d6610b4a9ed616f255f3)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 // SPDX-FileCopyrightText: Copyright 2019 Intel Corporation
4 #pragma once
5 
6 #include "bmcweb_config.h"
7 
8 #include <nlohmann/json.hpp>
9 
10 #include <array>
11 #include <charconv>
12 #include <cstddef>
13 #include <format>
14 #include <functional>
15 #include <map>
16 #include <optional>
17 #include <span>
18 #include <string>
19 #include <string_view>
20 #include <system_error>
21 #include <utility>
22 
23 namespace redfish::registries
24 {
25 struct Header
26 {
27     const char* copyright;
28     const char* type;
29     unsigned int versionMajor;
30     unsigned int versionMinor;
31     unsigned int versionPatch;
32     const char* name;
33     const char* language;
34     const char* description;
35     const char* registryPrefix;
36     const char* owningEntity;
37 };
38 
39 struct Message
40 {
41     const char* description;
42     const char* message;
43     const char* messageSeverity;
44     const size_t numberOfArgs;
45     std::array<const char*, 5> paramTypes;
46     const char* resolution;
47 };
48 using MessageEntry = std::pair<const char*, const Message>;
49 using MessageEntries = std::span<const MessageEntry>;
50 
51 struct RegistryEntry
52 {
53     const Header& header;
54     const char* url;
55     MessageEntries entries;
56 };
57 using RegistryEntryRef = std::reference_wrapper<RegistryEntry>;
58 
59 auto allRegistries() -> std::map<std::string, RegistryEntry>&;
60 
61 auto getRegistryFromPrefix(const std::string& registryName)
62     -> std::optional<RegistryEntryRef>;
63 
64 auto getRegistryMessagesFromPrefix(const std::string& registryName)
65     -> MessageEntries;
66 
67 template <typename T>
registerRegistry()68 void registerRegistry()
69 {
70     allRegistries().emplace(T::header.registryPrefix,
71                             RegistryEntry{T::header, T::url, T::registry});
72 }
73 
fillMessageArgs(const std::span<const std::string_view> messageArgs,std::string_view msg)74 inline std::string fillMessageArgs(
75     const std::span<const std::string_view> messageArgs, std::string_view msg)
76 {
77     std::string ret;
78     size_t reserve = msg.size();
79     for (std::string_view arg : messageArgs)
80     {
81         reserve += arg.size();
82     }
83     ret.reserve(reserve);
84 
85     for (size_t stringIndex = msg.find('%'); stringIndex != std::string::npos;
86          stringIndex = msg.find('%'))
87     {
88         ret += msg.substr(0, stringIndex);
89         msg.remove_prefix(stringIndex + 1);
90         size_t number = 0;
91         auto it = std::from_chars(&*msg.begin(), &*msg.end(), number);
92         if (it.ec != std::errc())
93         {
94             return "";
95         }
96         msg.remove_prefix(1);
97         // Redfish message args are 1 indexed.
98         number--;
99         if (number >= messageArgs.size())
100         {
101             return "";
102         }
103         ret += messageArgs[number];
104     }
105     ret += msg;
106     return ret;
107 }
108 
getLogFromRegistry(const Header & header,std::span<const MessageEntry> registry,size_t index,std::span<const std::string_view> args)109 inline nlohmann::json::object_t getLogFromRegistry(
110     const Header& header, std::span<const MessageEntry> registry, size_t index,
111     std::span<const std::string_view> args)
112 {
113     const redfish::registries::MessageEntry& entry = registry[index];
114     // Intentionally make a copy of the string, so we can append in the
115     // parameters.
116     std::string msg =
117         redfish::registries::fillMessageArgs(args, entry.second.message);
118     nlohmann::json jArgs = nlohmann::json::array();
119     for (std::string_view arg : args)
120     {
121         jArgs.push_back(arg);
122     }
123     std::string msgId;
124     if (BMCWEB_REDFISH_USE_3_DIGIT_MESSAGEID)
125     {
126         msgId = std::format("{}.{}.{}.{}.{}", header.registryPrefix,
127                             header.versionMajor, header.versionMinor,
128                             header.versionPatch, entry.first);
129     }
130     else
131     {
132         msgId =
133             std::format("{}.{}.{}.{}", header.registryPrefix,
134                         header.versionMajor, header.versionMinor, entry.first);
135     }
136     nlohmann::json::object_t response;
137     response["@odata.type"] = "#Message.v1_1_1.Message";
138     response["MessageId"] = std::move(msgId);
139     response["Message"] = std::move(msg);
140     response["MessageArgs"] = std::move(jArgs);
141     response["MessageSeverity"] = entry.second.messageSeverity;
142     response["Resolution"] = entry.second.resolution;
143     return response;
144 }
145 
146 const Message* getMessage(std::string_view messageID);
147 
148 const Message* getMessageFromRegistry(const std::string& messageKey,
149                                       std::span<const MessageEntry> registry);
150 
151 } // namespace redfish::registries
152