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