1 /*
2 // Copyright (c) 2019 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 
18 #include <nlohmann/json.hpp>
19 
20 #include <array>
21 #include <charconv>
22 #include <cstddef>
23 #include <numeric>
24 #include <span>
25 #include <string>
26 #include <string_view>
27 #include <utility>
28 
29 // IWYU pragma: no_include <stddef.h>
30 
31 namespace redfish::registries
32 {
33 struct Header
34 {
35     const char* copyright;
36     const char* type;
37     const char* id;
38     const char* name;
39     const char* language;
40     const char* description;
41     const char* registryPrefix;
42     const char* registryVersion;
43     const char* owningEntity;
44 };
45 
46 struct Message
47 {
48     const char* description;
49     const char* message;
50     const char* messageSeverity;
51     const size_t numberOfArgs;
52     std::array<const char*, 5> paramTypes;
53     const char* resolution;
54 };
55 using MessageEntry = std::pair<const char*, const Message>;
56 
57 inline std::string
fillMessageArgs(const std::span<const std::string_view> messageArgs,std::string_view msg)58     fillMessageArgs(const std::span<const std::string_view> messageArgs,
59                     std::string_view msg)
60 {
61     std::string ret;
62     size_t reserve = msg.size();
63     for (std::string_view arg : messageArgs)
64     {
65         reserve += arg.size();
66     }
67     ret.reserve(reserve);
68 
69     for (size_t stringIndex = msg.find('%'); stringIndex != std::string::npos;
70          stringIndex = msg.find('%'))
71     {
72         ret += msg.substr(0, stringIndex);
73         msg.remove_prefix(stringIndex + 1);
74         size_t number = 0;
75         auto it = std::from_chars(msg.data(), &*msg.end(), number);
76         if (it.ec != std::errc())
77         {
78             return "";
79         }
80         msg.remove_prefix(1);
81         // Redfish message args are 1 indexed.
82         number--;
83         if (number >= messageArgs.size())
84         {
85             return "";
86         }
87         ret += messageArgs[number];
88     }
89     ret += msg;
90     return ret;
91 }
92 
93 inline nlohmann::json::object_t
getLogFromRegistry(const Header & header,std::span<const MessageEntry> registry,size_t index,std::span<const std::string_view> args)94     getLogFromRegistry(const Header& header,
95                        std::span<const MessageEntry> registry, size_t index,
96                        std::span<const std::string_view> args)
97 {
98     const redfish::registries::MessageEntry& entry = registry[index];
99     // Intentionally make a copy of the string, so we can append in the
100     // parameters.
101     std::string msg =
102         redfish::registries::fillMessageArgs(args, entry.second.message);
103     nlohmann::json jArgs = nlohmann::json::array();
104     for (std::string_view arg : args)
105     {
106         jArgs.push_back(arg);
107     }
108     std::string msgId = header.id;
109     msgId += ".";
110     msgId += entry.first;
111 
112     nlohmann::json::object_t response;
113     response["@odata.type"] = "#Message.v1_1_1.Message";
114     response["MessageId"] = std::move(msgId);
115     response["Message"] = std::move(msg);
116     response["MessageArgs"] = std::move(jArgs);
117     response["MessageSeverity"] = entry.second.messageSeverity;
118     response["Resolution"] = entry.second.resolution;
119     return response;
120 }
121 
122 const Message* getMessage(std::string_view messageID);
123 
124 const Message* getMessageFromRegistry(const std::string& messageKey,
125                                       std::span<const MessageEntry> registry);
126 
127 } // namespace redfish::registries
128