xref: /openbmc/bmcweb/include/event_service_store.hpp (revision fdbce79b9a238aefd52f70b2a3b3d119b595d7ca)
1 #pragma once
2 #include "logging.hpp"
3 
4 #include <boost/beast/http/fields.hpp>
5 #include <boost/container/flat_map.hpp>
6 #include <boost/url/parse.hpp>
7 #include <boost/url/url.hpp>
8 #include <nlohmann/json.hpp>
9 
10 namespace persistent_data
11 {
12 
13 struct UserSubscription
14 {
15     std::string id;
16     boost::urls::url destinationUrl;
17     std::string protocol;
18     bool verifyCertificate = true;
19     std::string retryPolicy;
20     std::string customText;
21     std::string eventFormatType;
22     std::string subscriptionType;
23     std::vector<std::string> registryMsgIds;
24     std::vector<std::string> registryPrefixes;
25     std::vector<std::string> resourceTypes;
26     boost::beast::http::fields httpHeaders;
27     std::vector<std::string> metricReportDefinitions;
28 
29     static std::shared_ptr<UserSubscription>
30         fromJson(const nlohmann::json::object_t& j,
31                  const bool loadFromOldConfig = false)
32     {
33         std::shared_ptr<UserSubscription> subvalue =
34             std::make_shared<UserSubscription>();
35         for (const auto& element : j)
36         {
37             if (element.first == "Id")
38             {
39                 const std::string* value =
40                     element.second.get_ptr<const std::string*>();
41                 if (value == nullptr)
42                 {
43                     continue;
44                 }
45                 subvalue->id = *value;
46             }
47             else if (element.first == "Destination")
48             {
49                 const std::string* value =
50                     element.second.get_ptr<const std::string*>();
51                 if (value == nullptr)
52                 {
53                     continue;
54                 }
55                 boost::system::result<boost::urls::url> url =
56                     boost::urls::parse_absolute_uri(*value);
57                 if (!url)
58                 {
59                     continue;
60                 }
61                 subvalue->destinationUrl = std::move(*url);
62             }
63             else if (element.first == "Protocol")
64             {
65                 const std::string* value =
66                     element.second.get_ptr<const std::string*>();
67                 if (value == nullptr)
68                 {
69                     continue;
70                 }
71                 subvalue->protocol = *value;
72             }
73             else if (element.first == "VerifyCertificate")
74             {
75                 const bool* value = element.second.get_ptr<const bool*>();
76                 if (value == nullptr)
77                 {
78                     continue;
79                 }
80                 subvalue->verifyCertificate = *value;
81             }
82             else if (element.first == "DeliveryRetryPolicy")
83             {
84                 const std::string* value =
85                     element.second.get_ptr<const std::string*>();
86                 if (value == nullptr)
87                 {
88                     continue;
89                 }
90                 subvalue->retryPolicy = *value;
91             }
92             else if (element.first == "Context")
93             {
94                 const std::string* value =
95                     element.second.get_ptr<const std::string*>();
96                 if (value == nullptr)
97                 {
98                     continue;
99                 }
100                 subvalue->customText = *value;
101             }
102             else if (element.first == "EventFormatType")
103             {
104                 const std::string* value =
105                     element.second.get_ptr<const std::string*>();
106                 if (value == nullptr)
107                 {
108                     continue;
109                 }
110                 subvalue->eventFormatType = *value;
111             }
112             else if (element.first == "SubscriptionType")
113             {
114                 const std::string* value =
115                     element.second.get_ptr<const std::string*>();
116                 if (value == nullptr)
117                 {
118                     continue;
119                 }
120                 subvalue->subscriptionType = *value;
121             }
122             else if (element.first == "MessageIds")
123             {
124                 const nlohmann::json::array_t* obj =
125                     element.second.get_ptr<const nlohmann::json::array_t*>();
126                 if (obj == nullptr)
127                 {
128                     continue;
129                 }
130                 for (const auto& val : *obj)
131                 {
132                     const std::string* value =
133                         val.get_ptr<const std::string*>();
134                     if (value == nullptr)
135                     {
136                         continue;
137                     }
138                     subvalue->registryMsgIds.emplace_back(*value);
139                 }
140             }
141             else if (element.first == "RegistryPrefixes")
142             {
143                 const nlohmann::json::array_t* obj =
144                     element.second.get_ptr<const nlohmann::json::array_t*>();
145                 if (obj == nullptr)
146                 {
147                     continue;
148                 }
149                 for (const auto& val : *obj)
150                 {
151                     const std::string* value =
152                         val.get_ptr<const std::string*>();
153                     if (value == nullptr)
154                     {
155                         continue;
156                     }
157                     subvalue->registryPrefixes.emplace_back(*value);
158                 }
159             }
160             else if (element.first == "ResourceTypes")
161             {
162                 const nlohmann::json::array_t* obj =
163                     element.second.get_ptr<const nlohmann::json::array_t*>();
164                 if (obj == nullptr)
165                 {
166                     continue;
167                 }
168                 for (const auto& val : *obj)
169                 {
170                     const std::string* value =
171                         val.get_ptr<const std::string*>();
172                     if (value == nullptr)
173                     {
174                         continue;
175                     }
176                     subvalue->resourceTypes.emplace_back(*value);
177                 }
178             }
179             else if (element.first == "HttpHeaders")
180             {
181                 const nlohmann::json::object_t* obj =
182                     element.second.get_ptr<const nlohmann::json::object_t*>();
183                 if (obj == nullptr)
184                 {
185                     continue;
186                 }
187                 for (const auto& val : *obj)
188                 {
189                     const std::string* value =
190                         val.second.get_ptr<const std::string*>();
191                     if (value == nullptr)
192                     {
193                         BMCWEB_LOG_ERROR("Failed to parse value for key{}",
194                                          val.first);
195                         continue;
196                     }
197                     subvalue->httpHeaders.set(val.first, *value);
198                 }
199             }
200             else if (element.first == "MetricReportDefinitions")
201             {
202                 const nlohmann::json::array_t* obj =
203                     element.second.get_ptr<const nlohmann::json::array_t*>();
204                 if (obj == nullptr)
205                 {
206                     continue;
207                 }
208                 for (const auto& val : *obj)
209                 {
210                     const std::string* value =
211                         val.get_ptr<const std::string*>();
212                     if (value == nullptr)
213                     {
214                         continue;
215                     }
216                     subvalue->metricReportDefinitions.emplace_back(*value);
217                 }
218             }
219             else
220             {
221                 BMCWEB_LOG_ERROR(
222                     "Got unexpected property reading persistent file: {}",
223                     element.first);
224                 continue;
225             }
226         }
227 
228         if ((subvalue->id.empty() && !loadFromOldConfig) ||
229             subvalue->destinationUrl.empty() || subvalue->protocol.empty() ||
230             subvalue->retryPolicy.empty() ||
231             subvalue->eventFormatType.empty() ||
232             subvalue->subscriptionType.empty())
233         {
234             BMCWEB_LOG_ERROR("Subscription missing required field "
235                              "information, refusing to restore");
236             return nullptr;
237         }
238 
239         return subvalue;
240     }
241 };
242 
243 struct EventServiceConfig
244 {
245     bool enabled = true;
246     uint32_t retryAttempts = 3;
247     uint32_t retryTimeoutInterval = 30;
248 
249     void fromJson(const nlohmann::json::object_t& j)
250     {
251         for (const auto& element : j)
252         {
253             if (element.first == "ServiceEnabled")
254             {
255                 const bool* value = element.second.get_ptr<const bool*>();
256                 if (value == nullptr)
257                 {
258                     continue;
259                 }
260                 enabled = *value;
261             }
262             else if (element.first == "DeliveryRetryAttempts")
263             {
264                 const uint64_t* value =
265                     element.second.get_ptr<const uint64_t*>();
266                 if ((value == nullptr) ||
267                     (*value > std::numeric_limits<uint32_t>::max()))
268                 {
269                     continue;
270                 }
271                 retryAttempts = static_cast<uint32_t>(*value);
272             }
273             else if (element.first == "DeliveryRetryIntervalSeconds")
274             {
275                 const uint64_t* value =
276                     element.second.get_ptr<const uint64_t*>();
277                 if ((value == nullptr) ||
278                     (*value > std::numeric_limits<uint32_t>::max()))
279                 {
280                     continue;
281                 }
282                 retryTimeoutInterval = static_cast<uint32_t>(*value);
283             }
284         }
285     }
286 };
287 
288 class EventServiceStore
289 {
290   public:
291     boost::container::flat_map<std::string, std::shared_ptr<UserSubscription>>
292         subscriptionsConfigMap;
293     EventServiceConfig eventServiceConfig;
294 
295     static EventServiceStore& getInstance()
296     {
297         static EventServiceStore eventServiceStore;
298         return eventServiceStore;
299     }
300 
301     EventServiceConfig& getEventServiceConfig()
302     {
303         return eventServiceConfig;
304     }
305 };
306 
307 } // namespace persistent_data
308