blob: 6cc305f37a85bb837f0e7f9b1abe2d3333dcd406 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
JunLin Chen28afb492021-02-24 17:13:29 +08003#pragma once
4#include "logging.hpp"
5
Ed Tanous601c71a2021-09-08 16:40:12 -07006#include <boost/beast/http/fields.hpp>
JunLin Chen28afb492021-02-24 17:13:29 +08007#include <boost/container/flat_map.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -08008#include <boost/system/result.hpp>
Ed Tanousa716aa72023-08-01 11:35:53 -07009#include <boost/url/parse.hpp>
Ed Tanous4a7fbef2024-04-06 16:03:49 -070010#include <boost/url/url.hpp>
JunLin Chen28afb492021-02-24 17:13:29 +080011#include <nlohmann/json.hpp>
12
Ed Tanousd7857202025-01-28 15:32:26 -080013#include <cstdint>
Myung Bae5064a252024-10-04 09:34:25 -070014#include <limits>
Myung Bae56ba3862024-10-10 17:09:37 -070015#include <memory>
Ed Tanousd7857202025-01-28 15:32:26 -080016#include <optional>
Myung Bae56ba3862024-10-10 17:09:37 -070017#include <string>
Ed Tanousd7857202025-01-28 15:32:26 -080018#include <utility>
Myung Bae56ba3862024-10-10 17:09:37 -070019#include <vector>
20
JunLin Chen28afb492021-02-24 17:13:29 +080021namespace persistent_data
22{
23
24struct UserSubscription
25{
Ed Tanous4b712a22023-08-02 12:56:52 -070026 // Represents a Redfish EventDestination instance
JunLin Chen28afb492021-02-24 17:13:29 +080027 std::string id;
Ed Tanousa716aa72023-08-01 11:35:53 -070028 boost::urls::url destinationUrl;
JunLin Chen28afb492021-02-24 17:13:29 +080029 std::string protocol;
Ed Tanous19bb3622024-07-05 10:07:40 -050030 bool verifyCertificate = true;
JunLin Chen28afb492021-02-24 17:13:29 +080031 std::string retryPolicy;
Myung Bae5064a252024-10-04 09:34:25 -070032 bool sendHeartbeat = false;
33 // This value of hbIntervalMinutes is just a reasonable default value and
34 // most clients will update it if sendHeartbeat is turned on
35 uint64_t hbIntervalMinutes = 10;
JunLin Chen28afb492021-02-24 17:13:29 +080036 std::string customText;
37 std::string eventFormatType;
38 std::string subscriptionType;
39 std::vector<std::string> registryMsgIds;
40 std::vector<std::string> registryPrefixes;
41 std::vector<std::string> resourceTypes;
Ed Tanous601c71a2021-09-08 16:40:12 -070042 boost::beast::http::fields httpHeaders;
JunLin Chen28afb492021-02-24 17:13:29 +080043 std::vector<std::string> metricReportDefinitions;
Ed Tanousa14c9112024-09-04 10:46:47 -070044 std::vector<std::string> originResources;
JunLin Chen28afb492021-02-24 17:13:29 +080045
Ed Tanous4b712a22023-08-02 12:56:52 -070046 static std::optional<UserSubscription> fromJson(
Patrick Williamsbd79bce2024-08-16 15:22:20 -040047 const nlohmann::json::object_t& j, const bool loadFromOldConfig = false)
JunLin Chen28afb492021-02-24 17:13:29 +080048 {
Ed Tanous4b712a22023-08-02 12:56:52 -070049 UserSubscription subvalue;
Ed Tanous0bdda662023-08-03 17:27:34 -070050 for (const auto& element : j)
JunLin Chen28afb492021-02-24 17:13:29 +080051 {
Ed Tanous0bdda662023-08-03 17:27:34 -070052 if (element.first == "Id")
JunLin Chen28afb492021-02-24 17:13:29 +080053 {
54 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -070055 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +080056 if (value == nullptr)
57 {
58 continue;
59 }
Ed Tanous4b712a22023-08-02 12:56:52 -070060 subvalue.id = *value;
JunLin Chen28afb492021-02-24 17:13:29 +080061 }
Ed Tanous0bdda662023-08-03 17:27:34 -070062 else if (element.first == "Destination")
JunLin Chen28afb492021-02-24 17:13:29 +080063 {
64 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -070065 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +080066 if (value == nullptr)
67 {
68 continue;
69 }
Ed Tanous6fd29552023-10-04 09:40:14 -070070 boost::system::result<boost::urls::url> url =
Ed Tanousa716aa72023-08-01 11:35:53 -070071 boost::urls::parse_absolute_uri(*value);
72 if (!url)
73 {
74 continue;
75 }
Ed Tanous4b712a22023-08-02 12:56:52 -070076 subvalue.destinationUrl = std::move(*url);
JunLin Chen28afb492021-02-24 17:13:29 +080077 }
Ed Tanous0bdda662023-08-03 17:27:34 -070078 else if (element.first == "Protocol")
JunLin Chen28afb492021-02-24 17:13:29 +080079 {
80 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -070081 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +080082 if (value == nullptr)
83 {
84 continue;
85 }
Ed Tanous4b712a22023-08-02 12:56:52 -070086 subvalue.protocol = *value;
JunLin Chen28afb492021-02-24 17:13:29 +080087 }
Ed Tanous19bb3622024-07-05 10:07:40 -050088 else if (element.first == "VerifyCertificate")
89 {
90 const bool* value = element.second.get_ptr<const bool*>();
91 if (value == nullptr)
92 {
93 continue;
94 }
Ed Tanous4b712a22023-08-02 12:56:52 -070095 subvalue.verifyCertificate = *value;
Ed Tanous19bb3622024-07-05 10:07:40 -050096 }
Ed Tanous0bdda662023-08-03 17:27:34 -070097 else if (element.first == "DeliveryRetryPolicy")
JunLin Chen28afb492021-02-24 17:13:29 +080098 {
99 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700100 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800101 if (value == nullptr)
102 {
103 continue;
104 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700105 subvalue.retryPolicy = *value;
JunLin Chen28afb492021-02-24 17:13:29 +0800106 }
Myung Bae5064a252024-10-04 09:34:25 -0700107 else if (element.first == "SendHeartbeat")
108 {
109 const bool* value = element.second.get_ptr<const bool*>();
110 if (value == nullptr)
111 {
112 continue;
113 }
114 subvalue.sendHeartbeat = *value;
115 }
116 else if (element.first == "HeartbeatIntervalMinutes")
117 {
118 const uint64_t* value =
119 element.second.get_ptr<const uint64_t*>();
120 if (value == nullptr || *value < 1 || *value > 65535)
121 {
122 continue;
123 }
124 subvalue.hbIntervalMinutes = *value;
125 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700126 else if (element.first == "Context")
JunLin Chen28afb492021-02-24 17:13:29 +0800127 {
128 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700129 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800130 if (value == nullptr)
131 {
132 continue;
133 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700134 subvalue.customText = *value;
JunLin Chen28afb492021-02-24 17:13:29 +0800135 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700136 else if (element.first == "EventFormatType")
JunLin Chen28afb492021-02-24 17:13:29 +0800137 {
138 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700139 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800140 if (value == nullptr)
141 {
142 continue;
143 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700144 subvalue.eventFormatType = *value;
JunLin Chen28afb492021-02-24 17:13:29 +0800145 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700146 else if (element.first == "SubscriptionType")
JunLin Chen28afb492021-02-24 17:13:29 +0800147 {
148 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700149 element.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800150 if (value == nullptr)
151 {
152 continue;
153 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700154 subvalue.subscriptionType = *value;
JunLin Chen28afb492021-02-24 17:13:29 +0800155 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700156 else if (element.first == "MessageIds")
JunLin Chen28afb492021-02-24 17:13:29 +0800157 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700158 const nlohmann::json::array_t* obj =
159 element.second.get_ptr<const nlohmann::json::array_t*>();
160 if (obj == nullptr)
161 {
162 continue;
163 }
164 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800165 {
166 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700167 val.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800168 if (value == nullptr)
169 {
170 continue;
171 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700172 subvalue.registryMsgIds.emplace_back(*value);
JunLin Chen28afb492021-02-24 17:13:29 +0800173 }
174 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700175 else if (element.first == "RegistryPrefixes")
JunLin Chen28afb492021-02-24 17:13:29 +0800176 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700177 const nlohmann::json::array_t* obj =
178 element.second.get_ptr<const nlohmann::json::array_t*>();
179 if (obj == nullptr)
180 {
181 continue;
182 }
183 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800184 {
185 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700186 val.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800187 if (value == nullptr)
188 {
189 continue;
190 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700191 subvalue.registryPrefixes.emplace_back(*value);
JunLin Chen28afb492021-02-24 17:13:29 +0800192 }
193 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700194 else if (element.first == "ResourceTypes")
JunLin Chen28afb492021-02-24 17:13:29 +0800195 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700196 const nlohmann::json::array_t* obj =
197 element.second.get_ptr<const nlohmann::json::array_t*>();
198 if (obj == nullptr)
199 {
200 continue;
201 }
202 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800203 {
204 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700205 val.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800206 if (value == nullptr)
207 {
208 continue;
209 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700210 subvalue.resourceTypes.emplace_back(*value);
JunLin Chen28afb492021-02-24 17:13:29 +0800211 }
212 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700213 else if (element.first == "HttpHeaders")
JunLin Chen28afb492021-02-24 17:13:29 +0800214 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700215 const nlohmann::json::object_t* obj =
216 element.second.get_ptr<const nlohmann::json::object_t*>();
217 if (obj == nullptr)
218 {
219 continue;
220 }
221 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800222 {
Ed Tanous601c71a2021-09-08 16:40:12 -0700223 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700224 val.second.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800225 if (value == nullptr)
226 {
Ed Tanous62598e32023-07-17 17:06:25 -0700227 BMCWEB_LOG_ERROR("Failed to parse value for key{}",
Ed Tanous0bdda662023-08-03 17:27:34 -0700228 val.first);
JunLin Chen28afb492021-02-24 17:13:29 +0800229 continue;
230 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700231 subvalue.httpHeaders.set(val.first, *value);
JunLin Chen28afb492021-02-24 17:13:29 +0800232 }
233 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700234 else if (element.first == "MetricReportDefinitions")
JunLin Chen28afb492021-02-24 17:13:29 +0800235 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700236 const nlohmann::json::array_t* obj =
237 element.second.get_ptr<const nlohmann::json::array_t*>();
238 if (obj == nullptr)
239 {
240 continue;
241 }
242 for (const auto& val : *obj)
JunLin Chen28afb492021-02-24 17:13:29 +0800243 {
244 const std::string* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700245 val.get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800246 if (value == nullptr)
247 {
248 continue;
249 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700250 subvalue.metricReportDefinitions.emplace_back(*value);
JunLin Chen28afb492021-02-24 17:13:29 +0800251 }
252 }
Ed Tanousa14c9112024-09-04 10:46:47 -0700253 else if (element.first == "OriginResources")
254 {
255 const nlohmann::json::array_t* obj =
256 element.second.get_ptr<const nlohmann::json::array_t*>();
257 if (obj == nullptr)
258 {
259 continue;
260 }
261 for (const auto& val : *obj)
262 {
263 const std::string* value =
264 val.get_ptr<const std::string*>();
265 if (value == nullptr)
266 {
267 continue;
268 }
Ed Tanous4b712a22023-08-02 12:56:52 -0700269 subvalue.originResources.emplace_back(*value);
Ed Tanousa14c9112024-09-04 10:46:47 -0700270 }
271 }
JunLin Chen28afb492021-02-24 17:13:29 +0800272 else
273 {
Ed Tanous62598e32023-07-17 17:06:25 -0700274 BMCWEB_LOG_ERROR(
275 "Got unexpected property reading persistent file: {}",
Ed Tanous0bdda662023-08-03 17:27:34 -0700276 element.first);
JunLin Chen28afb492021-02-24 17:13:29 +0800277 continue;
278 }
279 }
280
Ed Tanous4b712a22023-08-02 12:56:52 -0700281 if ((subvalue.id.empty() && !loadFromOldConfig) ||
282 subvalue.destinationUrl.empty() || subvalue.protocol.empty() ||
283 subvalue.retryPolicy.empty() || subvalue.eventFormatType.empty() ||
284 subvalue.subscriptionType.empty())
JunLin Chen28afb492021-02-24 17:13:29 +0800285 {
Ed Tanous62598e32023-07-17 17:06:25 -0700286 BMCWEB_LOG_ERROR("Subscription missing required field "
287 "information, refusing to restore");
Ed Tanous4b712a22023-08-02 12:56:52 -0700288 return std::nullopt;
JunLin Chen28afb492021-02-24 17:13:29 +0800289 }
290
291 return subvalue;
292 }
293};
294
295struct EventServiceConfig
296{
297 bool enabled = true;
298 uint32_t retryAttempts = 3;
299 uint32_t retryTimeoutInterval = 30;
300
Ed Tanous0bdda662023-08-03 17:27:34 -0700301 void fromJson(const nlohmann::json::object_t& j)
JunLin Chen28afb492021-02-24 17:13:29 +0800302 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700303 for (const auto& element : j)
JunLin Chen28afb492021-02-24 17:13:29 +0800304 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700305 if (element.first == "ServiceEnabled")
JunLin Chen28afb492021-02-24 17:13:29 +0800306 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700307 const bool* value = element.second.get_ptr<const bool*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800308 if (value == nullptr)
309 {
310 continue;
311 }
312 enabled = *value;
313 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700314 else if (element.first == "DeliveryRetryAttempts")
JunLin Chen28afb492021-02-24 17:13:29 +0800315 {
316 const uint64_t* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700317 element.second.get_ptr<const uint64_t*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800318 if ((value == nullptr) ||
JunLin Chen28afb492021-02-24 17:13:29 +0800319 (*value > std::numeric_limits<uint32_t>::max()))
320 {
321 continue;
322 }
323 retryAttempts = static_cast<uint32_t>(*value);
324 }
Ed Tanous0bdda662023-08-03 17:27:34 -0700325 else if (element.first == "DeliveryRetryIntervalSeconds")
JunLin Chen28afb492021-02-24 17:13:29 +0800326 {
327 const uint64_t* value =
Ed Tanous0bdda662023-08-03 17:27:34 -0700328 element.second.get_ptr<const uint64_t*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800329 if ((value == nullptr) ||
JunLin Chen28afb492021-02-24 17:13:29 +0800330 (*value > std::numeric_limits<uint32_t>::max()))
331 {
332 continue;
333 }
334 retryTimeoutInterval = static_cast<uint32_t>(*value);
335 }
336 }
337 }
338};
339
340class EventServiceStore
341{
342 public:
Myung Bae5fe4ef32024-10-19 09:56:02 -0400343 boost::container::flat_map<std::string, std::shared_ptr<UserSubscription>>
JunLin Chen28afb492021-02-24 17:13:29 +0800344 subscriptionsConfigMap;
345 EventServiceConfig eventServiceConfig;
346
347 static EventServiceStore& getInstance()
348 {
349 static EventServiceStore eventServiceStore;
350 return eventServiceStore;
351 }
352
353 EventServiceConfig& getEventServiceConfig()
354 {
355 return eventServiceConfig;
356 }
JunLin Chen28afb492021-02-24 17:13:29 +0800357};
358
359} // namespace persistent_data