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