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 // Represents a Redfish EventDestination instance 16 std::string id; 17 boost::urls::url destinationUrl; 18 std::string protocol; 19 bool verifyCertificate = true; 20 std::string retryPolicy; 21 std::string customText; 22 std::string eventFormatType; 23 std::string subscriptionType; 24 std::vector<std::string> registryMsgIds; 25 std::vector<std::string> registryPrefixes; 26 std::vector<std::string> resourceTypes; 27 boost::beast::http::fields httpHeaders; 28 std::vector<std::string> metricReportDefinitions; 29 std::vector<std::string> originResources; 30 31 static std::optional<UserSubscription> fromJson( 32 const nlohmann::json::object_t& j, const bool loadFromOldConfig = false) 33 { 34 UserSubscription subvalue; 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 if (element.first == "OriginResources") 220 { 221 const nlohmann::json::array_t* obj = 222 element.second.get_ptr<const nlohmann::json::array_t*>(); 223 if (obj == nullptr) 224 { 225 continue; 226 } 227 for (const auto& val : *obj) 228 { 229 const std::string* value = 230 val.get_ptr<const std::string*>(); 231 if (value == nullptr) 232 { 233 continue; 234 } 235 subvalue.originResources.emplace_back(*value); 236 } 237 } 238 else 239 { 240 BMCWEB_LOG_ERROR( 241 "Got unexpected property reading persistent file: {}", 242 element.first); 243 continue; 244 } 245 } 246 247 if ((subvalue.id.empty() && !loadFromOldConfig) || 248 subvalue.destinationUrl.empty() || subvalue.protocol.empty() || 249 subvalue.retryPolicy.empty() || subvalue.eventFormatType.empty() || 250 subvalue.subscriptionType.empty()) 251 { 252 BMCWEB_LOG_ERROR("Subscription missing required field " 253 "information, refusing to restore"); 254 return std::nullopt; 255 } 256 257 return subvalue; 258 } 259 }; 260 261 struct EventServiceConfig 262 { 263 bool enabled = true; 264 uint32_t retryAttempts = 3; 265 uint32_t retryTimeoutInterval = 30; 266 267 void fromJson(const nlohmann::json::object_t& j) 268 { 269 for (const auto& element : j) 270 { 271 if (element.first == "ServiceEnabled") 272 { 273 const bool* value = element.second.get_ptr<const bool*>(); 274 if (value == nullptr) 275 { 276 continue; 277 } 278 enabled = *value; 279 } 280 else if (element.first == "DeliveryRetryAttempts") 281 { 282 const uint64_t* value = 283 element.second.get_ptr<const uint64_t*>(); 284 if ((value == nullptr) || 285 (*value > std::numeric_limits<uint32_t>::max())) 286 { 287 continue; 288 } 289 retryAttempts = static_cast<uint32_t>(*value); 290 } 291 else if (element.first == "DeliveryRetryIntervalSeconds") 292 { 293 const uint64_t* value = 294 element.second.get_ptr<const uint64_t*>(); 295 if ((value == nullptr) || 296 (*value > std::numeric_limits<uint32_t>::max())) 297 { 298 continue; 299 } 300 retryTimeoutInterval = static_cast<uint32_t>(*value); 301 } 302 } 303 } 304 }; 305 306 class EventServiceStore 307 { 308 public: 309 boost::container::flat_map<std::string, UserSubscription> 310 subscriptionsConfigMap; 311 EventServiceConfig eventServiceConfig; 312 313 static EventServiceStore& getInstance() 314 { 315 static EventServiceStore eventServiceStore; 316 return eventServiceStore; 317 } 318 319 EventServiceConfig& getEventServiceConfig() 320 { 321 return eventServiceConfig; 322 } 323 }; 324 325 } // namespace persistent_data 326