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> 68 void registerRegistry() 69 { 70 allRegistries().emplace(T::header.registryPrefix, 71 RegistryEntry{T::header, T::url, T::registry}); 72 } 73 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 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