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(
58     const std::span<const std::string_view> messageArgs, std::string_view msg)
59 {
60     std::string ret;
61     size_t reserve = msg.size();
62     for (std::string_view arg : messageArgs)
63     {
64         reserve += arg.size();
65     }
66     ret.reserve(reserve);
67 
68     for (size_t stringIndex = msg.find('%'); stringIndex != std::string::npos;
69          stringIndex = msg.find('%'))
70     {
71         ret += msg.substr(0, stringIndex);
72         msg.remove_prefix(stringIndex + 1);
73         size_t number = 0;
74         auto it = std::from_chars(msg.data(), &*msg.end(), number);
75         if (it.ec != std::errc())
76         {
77             return "";
78         }
79         msg.remove_prefix(1);
80         // Redfish message args are 1 indexed.
81         number--;
82         if (number >= messageArgs.size())
83         {
84             return "";
85         }
86         ret += messageArgs[number];
87     }
88     ret += msg;
89     return ret;
90 }
91 
92 inline nlohmann::json::object_t getLogFromRegistry(
93     const Header& header, std::span<const MessageEntry> registry, size_t index,
94     std::span<const std::string_view> args)
95 {
96     const redfish::registries::MessageEntry& entry = registry[index];
97     // Intentionally make a copy of the string, so we can append in the
98     // parameters.
99     std::string msg =
100         redfish::registries::fillMessageArgs(args, entry.second.message);
101     nlohmann::json jArgs = nlohmann::json::array();
102     for (std::string_view arg : args)
103     {
104         jArgs.push_back(arg);
105     }
106     std::string msgId = header.id;
107     msgId += ".";
108     msgId += entry.first;
109 
110     nlohmann::json::object_t response;
111     response["@odata.type"] = "#Message.v1_1_1.Message";
112     response["MessageId"] = std::move(msgId);
113     response["Message"] = std::move(msg);
114     response["MessageArgs"] = std::move(jArgs);
115     response["MessageSeverity"] = entry.second.messageSeverity;
116     response["Resolution"] = entry.second.resolution;
117     return response;
118 }
119 
120 const Message* getMessage(std::string_view messageID);
121 
122 const Message* getMessageFromRegistry(const std::string& messageKey,
123                                       std::span<const MessageEntry> registry);
124 
125 } // namespace redfish::registries
126