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