blob: 8b24fcbe838d4efea58a020a8b3f3bd93d70bbea [file] [log] [blame]
JunLin Chen28afb492021-02-24 17:13:29 +08001#pragma once
2#include "logging.hpp"
3
Ed Tanous601c71a2021-09-08 16:40:12 -07004#include <boost/beast/http/fields.hpp>
JunLin Chen28afb492021-02-24 17:13:29 +08005#include <boost/container/flat_map.hpp>
Ed Tanousa716aa72023-08-01 11:35:53 -07006#include <boost/url/parse.hpp>
JunLin Chen28afb492021-02-24 17:13:29 +08007#include <nlohmann/json.hpp>
8
9namespace persistent_data
10{
11
12struct UserSubscription
13{
14 std::string id;
Ed Tanousa716aa72023-08-01 11:35:53 -070015 boost::urls::url destinationUrl;
JunLin Chen28afb492021-02-24 17:13:29 +080016 std::string protocol;
17 std::string retryPolicy;
18 std::string customText;
19 std::string eventFormatType;
20 std::string subscriptionType;
21 std::vector<std::string> registryMsgIds;
22 std::vector<std::string> registryPrefixes;
23 std::vector<std::string> resourceTypes;
Ed Tanous601c71a2021-09-08 16:40:12 -070024 boost::beast::http::fields httpHeaders;
JunLin Chen28afb492021-02-24 17:13:29 +080025 std::vector<std::string> metricReportDefinitions;
26
27 static std::shared_ptr<UserSubscription>
28 fromJson(const nlohmann::json& j, const bool loadFromOldConfig = false)
29 {
30 std::shared_ptr<UserSubscription> subvalue =
31 std::make_shared<UserSubscription>();
32 for (const auto& element : j.items())
33 {
34 if (element.key() == "Id")
35 {
36 const std::string* value =
37 element.value().get_ptr<const std::string*>();
38 if (value == nullptr)
39 {
40 continue;
41 }
42 subvalue->id = *value;
43 }
44 else if (element.key() == "Destination")
45 {
46 const std::string* value =
47 element.value().get_ptr<const std::string*>();
48 if (value == nullptr)
49 {
50 continue;
51 }
Ed Tanousa716aa72023-08-01 11:35:53 -070052 boost::urls::result<boost::urls::url> url =
53 boost::urls::parse_absolute_uri(*value);
54 if (!url)
55 {
56 continue;
57 }
58 subvalue->destinationUrl = std::move(*url);
JunLin Chen28afb492021-02-24 17:13:29 +080059 }
60 else if (element.key() == "Protocol")
61 {
62 const std::string* value =
63 element.value().get_ptr<const std::string*>();
64 if (value == nullptr)
65 {
66 continue;
67 }
68 subvalue->protocol = *value;
69 }
70 else if (element.key() == "DeliveryRetryPolicy")
71 {
72 const std::string* value =
73 element.value().get_ptr<const std::string*>();
74 if (value == nullptr)
75 {
76 continue;
77 }
78 subvalue->retryPolicy = *value;
79 }
80 else if (element.key() == "Context")
81 {
82 const std::string* value =
83 element.value().get_ptr<const std::string*>();
84 if (value == nullptr)
85 {
86 continue;
87 }
88 subvalue->customText = *value;
89 }
90 else if (element.key() == "EventFormatType")
91 {
92 const std::string* value =
93 element.value().get_ptr<const std::string*>();
94 if (value == nullptr)
95 {
96 continue;
97 }
98 subvalue->eventFormatType = *value;
99 }
100 else if (element.key() == "SubscriptionType")
101 {
102 const std::string* value =
103 element.value().get_ptr<const std::string*>();
104 if (value == nullptr)
105 {
106 continue;
107 }
108 subvalue->subscriptionType = *value;
109 }
110 else if (element.key() == "MessageIds")
111 {
112 const auto& obj = element.value();
113 for (const auto& val : obj.items())
114 {
115 const std::string* value =
116 val.value().get_ptr<const std::string*>();
117 if (value == nullptr)
118 {
119 continue;
120 }
121 subvalue->registryMsgIds.emplace_back(*value);
122 }
123 }
124 else if (element.key() == "RegistryPrefixes")
125 {
126 const auto& obj = element.value();
127 for (const auto& val : obj.items())
128 {
129 const std::string* value =
130 val.value().get_ptr<const std::string*>();
131 if (value == nullptr)
132 {
133 continue;
134 }
135 subvalue->registryPrefixes.emplace_back(*value);
136 }
137 }
138 else if (element.key() == "ResourceTypes")
139 {
140 const auto& obj = element.value();
141 for (const auto& val : obj.items())
142 {
143 const std::string* value =
144 val.value().get_ptr<const std::string*>();
145 if (value == nullptr)
146 {
147 continue;
148 }
149 subvalue->resourceTypes.emplace_back(*value);
150 }
151 }
152 else if (element.key() == "HttpHeaders")
153 {
154 const auto& obj = element.value();
155 for (const auto& val : obj.items())
156 {
Ed Tanous601c71a2021-09-08 16:40:12 -0700157 const std::string* value =
158 val.value().get_ptr<const std::string*>();
JunLin Chen28afb492021-02-24 17:13:29 +0800159 if (value == nullptr)
160 {
Ed Tanous62598e32023-07-17 17:06:25 -0700161 BMCWEB_LOG_ERROR("Failed to parse value for key{}",
162 val.key());
JunLin Chen28afb492021-02-24 17:13:29 +0800163 continue;
164 }
Ed Tanous601c71a2021-09-08 16:40:12 -0700165 subvalue->httpHeaders.set(val.key(), *value);
JunLin Chen28afb492021-02-24 17:13:29 +0800166 }
167 }
168 else if (element.key() == "MetricReportDefinitions")
169 {
170 const auto& obj = element.value();
171 for (const auto& val : obj.items())
172 {
173 const std::string* value =
174 val.value().get_ptr<const std::string*>();
175 if (value == nullptr)
176 {
177 continue;
178 }
179 subvalue->metricReportDefinitions.emplace_back(*value);
180 }
181 }
182 else
183 {
Ed Tanous62598e32023-07-17 17:06:25 -0700184 BMCWEB_LOG_ERROR(
185 "Got unexpected property reading persistent file: {}",
186 element.key());
JunLin Chen28afb492021-02-24 17:13:29 +0800187 continue;
188 }
189 }
190
191 if ((subvalue->id.empty() && !loadFromOldConfig) ||
192 subvalue->destinationUrl.empty() || subvalue->protocol.empty() ||
Sunitha Harishe6a71652021-08-06 03:15:59 -0500193 subvalue->retryPolicy.empty() ||
JunLin Chen28afb492021-02-24 17:13:29 +0800194 subvalue->eventFormatType.empty() ||
Sunitha Harishe6a71652021-08-06 03:15:59 -0500195 subvalue->subscriptionType.empty())
JunLin Chen28afb492021-02-24 17:13:29 +0800196 {
Ed Tanous62598e32023-07-17 17:06:25 -0700197 BMCWEB_LOG_ERROR("Subscription missing required field "
198 "information, refusing to restore");
JunLin Chen28afb492021-02-24 17:13:29 +0800199 return nullptr;
200 }
201
202 return subvalue;
203 }
204};
205
206struct EventServiceConfig
207{
208 bool enabled = true;
209 uint32_t retryAttempts = 3;
210 uint32_t retryTimeoutInterval = 30;
211
212 void fromJson(const nlohmann::json& j)
213 {
214 for (const auto& element : j.items())
215 {
216 if (element.key() == "ServiceEnabled")
217 {
218 const bool* value = element.value().get_ptr<const bool*>();
219 if (value == nullptr)
220 {
221 continue;
222 }
223 enabled = *value;
224 }
225 else if (element.key() == "DeliveryRetryAttempts")
226 {
227 const uint64_t* value =
228 element.value().get_ptr<const uint64_t*>();
229 if ((value == nullptr) ||
JunLin Chen28afb492021-02-24 17:13:29 +0800230 (*value > std::numeric_limits<uint32_t>::max()))
231 {
232 continue;
233 }
234 retryAttempts = static_cast<uint32_t>(*value);
235 }
236 else if (element.key() == "DeliveryRetryIntervalSeconds")
237 {
238 const uint64_t* value =
239 element.value().get_ptr<const uint64_t*>();
240 if ((value == nullptr) ||
JunLin Chen28afb492021-02-24 17:13:29 +0800241 (*value > std::numeric_limits<uint32_t>::max()))
242 {
243 continue;
244 }
245 retryTimeoutInterval = static_cast<uint32_t>(*value);
246 }
247 }
248 }
249};
250
251class EventServiceStore
252{
253 public:
254 boost::container::flat_map<std::string, std::shared_ptr<UserSubscription>>
255 subscriptionsConfigMap;
256 EventServiceConfig eventServiceConfig;
257
258 static EventServiceStore& getInstance()
259 {
260 static EventServiceStore eventServiceStore;
261 return eventServiceStore;
262 }
263
264 EventServiceConfig& getEventServiceConfig()
265 {
266 return eventServiceConfig;
267 }
268};
269
270} // namespace persistent_data