140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2019 Intel Corporation 470304cb5SJason M. Bills #pragma once 5c5ba4c27SEd Tanous 656b81992SEd Tanous #include "bmcweb_config.h" 756b81992SEd Tanous 865e4f1f7SEd Tanous #include <nlohmann/json.hpp> 965e4f1f7SEd Tanous 10d5c80ad9SNan Zhou #include <array> 1180f595e7SEd Tanous #include <charconv> 12d5c80ad9SNan Zhou #include <cstddef> 1356b81992SEd Tanous #include <format> 14*4a102cd4SPatrick Williams #include <functional> 15*4a102cd4SPatrick Williams #include <map> 16*4a102cd4SPatrick Williams #include <optional> 17c5ba4c27SEd Tanous #include <span> 18c5ba4c27SEd Tanous #include <string> 19c5ba4c27SEd Tanous #include <string_view> 20d7857201SEd Tanous #include <system_error> 21d5c80ad9SNan Zhou #include <utility> 22d5c80ad9SNan Zhou 23fffb8c1fSEd Tanous namespace redfish::registries 2470304cb5SJason M. Bills { 25351d3063SJason M. Bills struct Header 26351d3063SJason M. Bills { 27351d3063SJason M. Bills const char* copyright; 28351d3063SJason M. Bills const char* type; 2956b81992SEd Tanous unsigned int versionMajor; 3056b81992SEd Tanous unsigned int versionMinor; 3156b81992SEd Tanous unsigned int versionPatch; 32351d3063SJason M. Bills const char* name; 33351d3063SJason M. Bills const char* language; 34351d3063SJason M. Bills const char* description; 35351d3063SJason M. Bills const char* registryPrefix; 36351d3063SJason M. Bills const char* owningEntity; 37351d3063SJason M. Bills }; 3870304cb5SJason M. Bills 3970304cb5SJason M. Bills struct Message 4070304cb5SJason M. Bills { 4170304cb5SJason M. Bills const char* description; 4270304cb5SJason M. Bills const char* message; 43e7808c93SGunnar Mills const char* messageSeverity; 44271584abSEd Tanous const size_t numberOfArgs; 4570304cb5SJason M. Bills std::array<const char*, 5> paramTypes; 4670304cb5SJason M. Bills const char* resolution; 4770304cb5SJason M. Bills }; 4870304cb5SJason M. Bills using MessageEntry = std::pair<const char*, const Message>; 49*4a102cd4SPatrick Williams using MessageEntries = std::span<const MessageEntry>; 50*4a102cd4SPatrick Williams 51*4a102cd4SPatrick Williams struct RegistryEntry 52*4a102cd4SPatrick Williams { 53*4a102cd4SPatrick Williams const Header& header; 54*4a102cd4SPatrick Williams const char* url; 55*4a102cd4SPatrick Williams MessageEntries entries; 56*4a102cd4SPatrick Williams }; 57*4a102cd4SPatrick Williams using RegistryEntryRef = std::reference_wrapper<RegistryEntry>; 58*4a102cd4SPatrick Williams 59*4a102cd4SPatrick Williams auto allRegistries() -> std::map<std::string, RegistryEntry>&; 60*4a102cd4SPatrick Williams 61*4a102cd4SPatrick Williams auto getRegistryFromPrefix(const std::string& registryName) 62*4a102cd4SPatrick Williams -> std::optional<RegistryEntryRef>; 63*4a102cd4SPatrick Williams 64*4a102cd4SPatrick Williams auto getRegistryMessagesFromPrefix(const std::string& registryName) 65*4a102cd4SPatrick Williams -> MessageEntries; 66*4a102cd4SPatrick Williams 67*4a102cd4SPatrick Williams template <typename T> 68*4a102cd4SPatrick Williams void registerRegistry() 69*4a102cd4SPatrick Williams { 70*4a102cd4SPatrick Williams allRegistries().emplace(T::header.registryPrefix, 71*4a102cd4SPatrick Williams RegistryEntry{T::header, T::url, T::registry}); 72*4a102cd4SPatrick Williams } 73c5ba4c27SEd Tanous 74bd79bce8SPatrick Williams inline std::string fillMessageArgs( 75bd79bce8SPatrick Williams const std::span<const std::string_view> messageArgs, std::string_view msg) 76c5ba4c27SEd Tanous { 7780f595e7SEd Tanous std::string ret; 7880f595e7SEd Tanous size_t reserve = msg.size(); 7926ccae32SEd Tanous for (std::string_view arg : messageArgs) 80c5ba4c27SEd Tanous { 8180f595e7SEd Tanous reserve += arg.size(); 82c5ba4c27SEd Tanous } 8380f595e7SEd Tanous ret.reserve(reserve); 8480f595e7SEd Tanous 8580f595e7SEd Tanous for (size_t stringIndex = msg.find('%'); stringIndex != std::string::npos; 8680f595e7SEd Tanous stringIndex = msg.find('%')) 8780f595e7SEd Tanous { 8880f595e7SEd Tanous ret += msg.substr(0, stringIndex); 8980f595e7SEd Tanous msg.remove_prefix(stringIndex + 1); 9080f595e7SEd Tanous size_t number = 0; 917da633f0SEd Tanous auto it = std::from_chars(&*msg.begin(), &*msg.end(), number); 9280f595e7SEd Tanous if (it.ec != std::errc()) 9380f595e7SEd Tanous { 9480f595e7SEd Tanous return ""; 95c5ba4c27SEd Tanous } 9680f595e7SEd Tanous msg.remove_prefix(1); 9780f595e7SEd Tanous // Redfish message args are 1 indexed. 9880f595e7SEd Tanous number--; 9980f595e7SEd Tanous if (number >= messageArgs.size()) 10080f595e7SEd Tanous { 10180f595e7SEd Tanous return ""; 10280f595e7SEd Tanous } 10380f595e7SEd Tanous ret += messageArgs[number]; 10480f595e7SEd Tanous } 10580f595e7SEd Tanous ret += msg; 10680f595e7SEd Tanous return ret; 107c5ba4c27SEd Tanous } 108c5ba4c27SEd Tanous 109bd79bce8SPatrick Williams inline nlohmann::json::object_t getLogFromRegistry( 110bd79bce8SPatrick Williams const Header& header, std::span<const MessageEntry> registry, size_t index, 11165e4f1f7SEd Tanous std::span<const std::string_view> args) 11265e4f1f7SEd Tanous { 11365e4f1f7SEd Tanous const redfish::registries::MessageEntry& entry = registry[index]; 11465e4f1f7SEd Tanous // Intentionally make a copy of the string, so we can append in the 11565e4f1f7SEd Tanous // parameters. 1162e30bc2dSKrzysztof Grobelny std::string msg = 1172e30bc2dSKrzysztof Grobelny redfish::registries::fillMessageArgs(args, entry.second.message); 11865e4f1f7SEd Tanous nlohmann::json jArgs = nlohmann::json::array(); 11926ccae32SEd Tanous for (std::string_view arg : args) 12065e4f1f7SEd Tanous { 12165e4f1f7SEd Tanous jArgs.push_back(arg); 12265e4f1f7SEd Tanous } 12356b81992SEd Tanous std::string msgId; 12456b81992SEd Tanous if (BMCWEB_REDFISH_USE_3_DIGIT_MESSAGEID) 12556b81992SEd Tanous { 12656b81992SEd Tanous msgId = std::format("{}.{}.{}.{}.{}", header.registryPrefix, 12756b81992SEd Tanous header.versionMajor, header.versionMinor, 12856b81992SEd Tanous header.versionPatch, entry.first); 12956b81992SEd Tanous } 13056b81992SEd Tanous else 13156b81992SEd Tanous { 13256b81992SEd Tanous msgId = 13356b81992SEd Tanous std::format("{}.{}.{}.{}", header.registryPrefix, 13456b81992SEd Tanous header.versionMajor, header.versionMinor, entry.first); 13556b81992SEd Tanous } 13665e4f1f7SEd Tanous nlohmann::json::object_t response; 13765e4f1f7SEd Tanous response["@odata.type"] = "#Message.v1_1_1.Message"; 13865e4f1f7SEd Tanous response["MessageId"] = std::move(msgId); 13965e4f1f7SEd Tanous response["Message"] = std::move(msg); 14065e4f1f7SEd Tanous response["MessageArgs"] = std::move(jArgs); 14165e4f1f7SEd Tanous response["MessageSeverity"] = entry.second.messageSeverity; 14265e4f1f7SEd Tanous response["Resolution"] = entry.second.resolution; 14365e4f1f7SEd Tanous return response; 14465e4f1f7SEd Tanous } 14565e4f1f7SEd Tanous 146d1d411f9SSui Chen const Message* getMessage(std::string_view messageID); 147d1d411f9SSui Chen 148d1d411f9SSui Chen const Message* getMessageFromRegistry(const std::string& messageKey, 149d1d411f9SSui Chen std::span<const MessageEntry> registry); 150d1d411f9SSui Chen 151fffb8c1fSEd Tanous } // namespace redfish::registries 152