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