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 #include <memory> 11 #include <string> 12 #include <vector> 13 14 namespace persistent_data 15 { 16 17 struct UserSubscription 18 { 19 // Represents a Redfish EventDestination instance 20 std::string id; 21 boost::urls::url destinationUrl; 22 std::string protocol; 23 bool verifyCertificate = true; 24 std::string retryPolicy; 25 std::string customText; 26 std::string eventFormatType; 27 std::string subscriptionType; 28 std::vector<std::string> registryMsgIds; 29 std::vector<std::string> registryPrefixes; 30 std::vector<std::string> resourceTypes; 31 boost::beast::http::fields httpHeaders; 32 std::vector<std::string> metricReportDefinitions; 33 std::vector<std::string> originResources; 34 fromJsonpersistent_data::UserSubscription35 static std::optional<UserSubscription> fromJson( 36 const nlohmann::json::object_t& j, const bool loadFromOldConfig = false) 37 { 38 UserSubscription subvalue; 39 for (const auto& element : j) 40 { 41 if (element.first == "Id") 42 { 43 const std::string* value = 44 element.second.get_ptr<const std::string*>(); 45 if (value == nullptr) 46 { 47 continue; 48 } 49 subvalue.id = *value; 50 } 51 else if (element.first == "Destination") 52 { 53 const std::string* value = 54 element.second.get_ptr<const std::string*>(); 55 if (value == nullptr) 56 { 57 continue; 58 } 59 boost::system::result<boost::urls::url> url = 60 boost::urls::parse_absolute_uri(*value); 61 if (!url) 62 { 63 continue; 64 } 65 subvalue.destinationUrl = std::move(*url); 66 } 67 else if (element.first == "Protocol") 68 { 69 const std::string* value = 70 element.second.get_ptr<const std::string*>(); 71 if (value == nullptr) 72 { 73 continue; 74 } 75 subvalue.protocol = *value; 76 } 77 else if (element.first == "VerifyCertificate") 78 { 79 const bool* value = element.second.get_ptr<const bool*>(); 80 if (value == nullptr) 81 { 82 continue; 83 } 84 subvalue.verifyCertificate = *value; 85 } 86 else if (element.first == "DeliveryRetryPolicy") 87 { 88 const std::string* value = 89 element.second.get_ptr<const std::string*>(); 90 if (value == nullptr) 91 { 92 continue; 93 } 94 subvalue.retryPolicy = *value; 95 } 96 else if (element.first == "Context") 97 { 98 const std::string* value = 99 element.second.get_ptr<const std::string*>(); 100 if (value == nullptr) 101 { 102 continue; 103 } 104 subvalue.customText = *value; 105 } 106 else if (element.first == "EventFormatType") 107 { 108 const std::string* value = 109 element.second.get_ptr<const std::string*>(); 110 if (value == nullptr) 111 { 112 continue; 113 } 114 subvalue.eventFormatType = *value; 115 } 116 else if (element.first == "SubscriptionType") 117 { 118 const std::string* value = 119 element.second.get_ptr<const std::string*>(); 120 if (value == nullptr) 121 { 122 continue; 123 } 124 subvalue.subscriptionType = *value; 125 } 126 else if (element.first == "MessageIds") 127 { 128 const nlohmann::json::array_t* obj = 129 element.second.get_ptr<const nlohmann::json::array_t*>(); 130 if (obj == nullptr) 131 { 132 continue; 133 } 134 for (const auto& val : *obj) 135 { 136 const std::string* value = 137 val.get_ptr<const std::string*>(); 138 if (value == nullptr) 139 { 140 continue; 141 } 142 subvalue.registryMsgIds.emplace_back(*value); 143 } 144 } 145 else if (element.first == "RegistryPrefixes") 146 { 147 const nlohmann::json::array_t* obj = 148 element.second.get_ptr<const nlohmann::json::array_t*>(); 149 if (obj == nullptr) 150 { 151 continue; 152 } 153 for (const auto& val : *obj) 154 { 155 const std::string* value = 156 val.get_ptr<const std::string*>(); 157 if (value == nullptr) 158 { 159 continue; 160 } 161 subvalue.registryPrefixes.emplace_back(*value); 162 } 163 } 164 else if (element.first == "ResourceTypes") 165 { 166 const nlohmann::json::array_t* obj = 167 element.second.get_ptr<const nlohmann::json::array_t*>(); 168 if (obj == nullptr) 169 { 170 continue; 171 } 172 for (const auto& val : *obj) 173 { 174 const std::string* value = 175 val.get_ptr<const std::string*>(); 176 if (value == nullptr) 177 { 178 continue; 179 } 180 subvalue.resourceTypes.emplace_back(*value); 181 } 182 } 183 else if (element.first == "HttpHeaders") 184 { 185 const nlohmann::json::object_t* obj = 186 element.second.get_ptr<const nlohmann::json::object_t*>(); 187 if (obj == nullptr) 188 { 189 continue; 190 } 191 for (const auto& val : *obj) 192 { 193 const std::string* value = 194 val.second.get_ptr<const std::string*>(); 195 if (value == nullptr) 196 { 197 BMCWEB_LOG_ERROR("Failed to parse value for key{}", 198 val.first); 199 continue; 200 } 201 subvalue.httpHeaders.set(val.first, *value); 202 } 203 } 204 else if (element.first == "MetricReportDefinitions") 205 { 206 const nlohmann::json::array_t* obj = 207 element.second.get_ptr<const nlohmann::json::array_t*>(); 208 if (obj == nullptr) 209 { 210 continue; 211 } 212 for (const auto& val : *obj) 213 { 214 const std::string* value = 215 val.get_ptr<const std::string*>(); 216 if (value == nullptr) 217 { 218 continue; 219 } 220 subvalue.metricReportDefinitions.emplace_back(*value); 221 } 222 } 223 else if (element.first == "OriginResources") 224 { 225 const nlohmann::json::array_t* obj = 226 element.second.get_ptr<const nlohmann::json::array_t*>(); 227 if (obj == nullptr) 228 { 229 continue; 230 } 231 for (const auto& val : *obj) 232 { 233 const std::string* value = 234 val.get_ptr<const std::string*>(); 235 if (value == nullptr) 236 { 237 continue; 238 } 239 subvalue.originResources.emplace_back(*value); 240 } 241 } 242 else 243 { 244 BMCWEB_LOG_ERROR( 245 "Got unexpected property reading persistent file: {}", 246 element.first); 247 continue; 248 } 249 } 250 251 if ((subvalue.id.empty() && !loadFromOldConfig) || 252 subvalue.destinationUrl.empty() || subvalue.protocol.empty() || 253 subvalue.retryPolicy.empty() || subvalue.eventFormatType.empty() || 254 subvalue.subscriptionType.empty()) 255 { 256 BMCWEB_LOG_ERROR("Subscription missing required field " 257 "information, refusing to restore"); 258 return std::nullopt; 259 } 260 261 return subvalue; 262 } 263 }; 264 265 struct EventServiceConfig 266 { 267 bool enabled = true; 268 uint32_t retryAttempts = 3; 269 uint32_t retryTimeoutInterval = 30; 270 fromJsonpersistent_data::EventServiceConfig271 void fromJson(const nlohmann::json::object_t& j) 272 { 273 for (const auto& element : j) 274 { 275 if (element.first == "ServiceEnabled") 276 { 277 const bool* value = element.second.get_ptr<const bool*>(); 278 if (value == nullptr) 279 { 280 continue; 281 } 282 enabled = *value; 283 } 284 else if (element.first == "DeliveryRetryAttempts") 285 { 286 const uint64_t* value = 287 element.second.get_ptr<const uint64_t*>(); 288 if ((value == nullptr) || 289 (*value > std::numeric_limits<uint32_t>::max())) 290 { 291 continue; 292 } 293 retryAttempts = static_cast<uint32_t>(*value); 294 } 295 else if (element.first == "DeliveryRetryIntervalSeconds") 296 { 297 const uint64_t* value = 298 element.second.get_ptr<const uint64_t*>(); 299 if ((value == nullptr) || 300 (*value > std::numeric_limits<uint32_t>::max())) 301 { 302 continue; 303 } 304 retryTimeoutInterval = static_cast<uint32_t>(*value); 305 } 306 } 307 } 308 }; 309 310 class EventServiceStore 311 { 312 public: 313 boost::container::flat_map<std::string, std::shared_ptr<UserSubscription>> 314 subscriptionsConfigMap; 315 EventServiceConfig eventServiceConfig; 316 getInstance()317 static EventServiceStore& getInstance() 318 { 319 static EventServiceStore eventServiceStore; 320 return eventServiceStore; 321 } 322 getEventServiceConfig()323 EventServiceConfig& getEventServiceConfig() 324 { 325 return eventServiceConfig; 326 } 327 }; 328 329 } // namespace persistent_data 330