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 <numeric> 15 #include <span> 16 #include <string> 17 #include <string_view> 18 #include <utility> 19 20 namespace redfish::registries 21 { 22 struct Header 23 { 24 const char* copyright; 25 const char* type; 26 unsigned int versionMajor; 27 unsigned int versionMinor; 28 unsigned int versionPatch; 29 const char* name; 30 const char* language; 31 const char* description; 32 const char* registryPrefix; 33 const char* owningEntity; 34 }; 35 36 struct Message 37 { 38 const char* description; 39 const char* message; 40 const char* messageSeverity; 41 const size_t numberOfArgs; 42 std::array<const char*, 5> paramTypes; 43 const char* resolution; 44 }; 45 using MessageEntry = std::pair<const char*, const Message>; 46 47 inline std::string fillMessageArgs( 48 const std::span<const std::string_view> messageArgs, std::string_view msg) 49 { 50 std::string ret; 51 size_t reserve = msg.size(); 52 for (std::string_view arg : messageArgs) 53 { 54 reserve += arg.size(); 55 } 56 ret.reserve(reserve); 57 58 for (size_t stringIndex = msg.find('%'); stringIndex != std::string::npos; 59 stringIndex = msg.find('%')) 60 { 61 ret += msg.substr(0, stringIndex); 62 msg.remove_prefix(stringIndex + 1); 63 size_t number = 0; 64 auto it = std::from_chars(&*msg.begin(), &*msg.end(), number); 65 if (it.ec != std::errc()) 66 { 67 return ""; 68 } 69 msg.remove_prefix(1); 70 // Redfish message args are 1 indexed. 71 number--; 72 if (number >= messageArgs.size()) 73 { 74 return ""; 75 } 76 ret += messageArgs[number]; 77 } 78 ret += msg; 79 return ret; 80 } 81 82 inline nlohmann::json::object_t getLogFromRegistry( 83 const Header& header, std::span<const MessageEntry> registry, size_t index, 84 std::span<const std::string_view> args) 85 { 86 const redfish::registries::MessageEntry& entry = registry[index]; 87 // Intentionally make a copy of the string, so we can append in the 88 // parameters. 89 std::string msg = 90 redfish::registries::fillMessageArgs(args, entry.second.message); 91 nlohmann::json jArgs = nlohmann::json::array(); 92 for (std::string_view arg : args) 93 { 94 jArgs.push_back(arg); 95 } 96 std::string msgId; 97 if (BMCWEB_REDFISH_USE_3_DIGIT_MESSAGEID) 98 { 99 msgId = std::format("{}.{}.{}.{}.{}", header.registryPrefix, 100 header.versionMajor, header.versionMinor, 101 header.versionPatch, entry.first); 102 } 103 else 104 { 105 msgId = 106 std::format("{}.{}.{}.{}", header.registryPrefix, 107 header.versionMajor, header.versionMinor, entry.first); 108 } 109 nlohmann::json::object_t response; 110 response["@odata.type"] = "#Message.v1_1_1.Message"; 111 response["MessageId"] = std::move(msgId); 112 response["Message"] = std::move(msg); 113 response["MessageArgs"] = std::move(jArgs); 114 response["MessageSeverity"] = entry.second.messageSeverity; 115 response["Resolution"] = entry.second.resolution; 116 return response; 117 } 118 119 const Message* getMessage(std::string_view messageID); 120 121 const Message* getMessageFromRegistry(const std::string& messageKey, 122 std::span<const MessageEntry> registry); 123 124 } // namespace redfish::registries 125