xref: /openbmc/bmcweb/redfish-core/include/registries.hpp (revision d9495964cd857f8775677f3f5c1f35f0cf00c0a6)
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 
49 struct MessageId
50 {
51     std::string registryName;
52     std::string majorVersion;
53     std::string minorVersion;
54     std::string messageKey;
55 };
56 
57 using MessageEntry = std::pair<const char*, const Message>;
58 using MessageEntries = std::span<const MessageEntry>;
59 
60 struct RegistryEntry
61 {
62     const Header& header;
63     const char* url;
64     MessageEntries entries;
65 };
66 using RegistryEntryRef = std::reference_wrapper<RegistryEntry>;
67 
68 auto allRegistries() -> std::map<std::string, RegistryEntry>&;
69 
70 auto getRegistryFromPrefix(const std::string& registryName)
71     -> std::optional<RegistryEntryRef>;
72 
73 auto getRegistryMessagesFromPrefix(const std::string& registryName)
74     -> MessageEntries;
75 
76 template <typename T>
registerRegistry()77 void registerRegistry()
78 {
79     allRegistries().emplace(T::header.registryPrefix,
80                             RegistryEntry{T::header, T::url, T::registry});
81 }
82 
fillMessageArgs(const std::span<const std::string_view> messageArgs,std::string_view msg)83 inline std::string fillMessageArgs(
84     const std::span<const std::string_view> messageArgs, std::string_view msg)
85 {
86     std::string ret;
87     size_t reserve = msg.size();
88     for (std::string_view arg : messageArgs)
89     {
90         reserve += arg.size();
91     }
92     ret.reserve(reserve);
93 
94     for (size_t stringIndex = msg.find('%'); stringIndex != std::string::npos;
95          stringIndex = msg.find('%'))
96     {
97         ret += msg.substr(0, stringIndex);
98         msg.remove_prefix(stringIndex + 1);
99         size_t number = 0;
100         auto it = std::from_chars(&*msg.begin(), &*msg.end(), number);
101         if (it.ec != std::errc())
102         {
103             return "";
104         }
105         msg.remove_prefix(1);
106         // Redfish message args are 1 indexed.
107         number--;
108         if (number >= messageArgs.size())
109         {
110             return "";
111         }
112         ret += messageArgs[number];
113     }
114     ret += msg;
115     return ret;
116 }
117 
getLogFromRegistry(const Header & header,std::span<const MessageEntry> registry,size_t index,std::span<const std::string_view> args)118 inline nlohmann::json::object_t getLogFromRegistry(
119     const Header& header, std::span<const MessageEntry> registry, size_t index,
120     std::span<const std::string_view> args)
121 {
122     const redfish::registries::MessageEntry& entry = registry[index];
123     // Intentionally make a copy of the string, so we can append in the
124     // parameters.
125     std::string msg =
126         redfish::registries::fillMessageArgs(args, entry.second.message);
127     nlohmann::json jArgs = nlohmann::json::array();
128     for (std::string_view arg : args)
129     {
130         jArgs.push_back(arg);
131     }
132     std::string msgId =
133         std::format("{}.{}.{}.{}", header.registryPrefix, header.versionMajor,
134                     header.versionMinor, entry.first);
135     nlohmann::json::object_t response;
136     response["@odata.type"] = "#Message.v1_1_1.Message";
137     response["MessageId"] = std::move(msgId);
138     response["Message"] = std::move(msg);
139     response["MessageArgs"] = std::move(jArgs);
140     response["MessageSeverity"] = entry.second.messageSeverity;
141     response["Resolution"] = entry.second.resolution;
142     return response;
143 }
144 
145 const Message* getMessage(std::string_view messageID);
146 
147 const Message* getMessageFromRegistry(const std::string& messageKey,
148                                       std::span<const MessageEntry> registry);
149 
150 std::optional<MessageId> getMessageComponents(std::string_view message);
151 
152 } // namespace redfish::registries
153