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 std::string id; 16 boost::urls::url destinationUrl; 17 std::string protocol; 18 bool verifyCertificate = true; 19 std::string retryPolicy; 20 std::string customText; 21 std::string eventFormatType; 22 std::string subscriptionType; 23 std::vector<std::string> registryMsgIds; 24 std::vector<std::string> registryPrefixes; 25 std::vector<std::string> resourceTypes; 26 boost::beast::http::fields httpHeaders; 27 std::vector<std::string> metricReportDefinitions; 28 std::vector<std::string> originResources; 29 30 static std::shared_ptr<UserSubscription> fromJson( 31 const nlohmann::json::object_t& j, const bool loadFromOldConfig = false) 32 { 33 std::shared_ptr<UserSubscription> subvalue = 34 std::make_shared<UserSubscription>(); 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() || 250 subvalue->eventFormatType.empty() || 251 subvalue->subscriptionType.empty()) 252 { 253 BMCWEB_LOG_ERROR("Subscription missing required field " 254 "information, refusing to restore"); 255 return nullptr; 256 } 257 258 return subvalue; 259 } 260 }; 261 262 struct EventServiceConfig 263 { 264 bool enabled = true; 265 uint32_t retryAttempts = 3; 266 uint32_t retryTimeoutInterval = 30; 267 268 void fromJson(const nlohmann::json::object_t& j) 269 { 270 for (const auto& element : j) 271 { 272 if (element.first == "ServiceEnabled") 273 { 274 const bool* value = element.second.get_ptr<const bool*>(); 275 if (value == nullptr) 276 { 277 continue; 278 } 279 enabled = *value; 280 } 281 else if (element.first == "DeliveryRetryAttempts") 282 { 283 const uint64_t* value = 284 element.second.get_ptr<const uint64_t*>(); 285 if ((value == nullptr) || 286 (*value > std::numeric_limits<uint32_t>::max())) 287 { 288 continue; 289 } 290 retryAttempts = static_cast<uint32_t>(*value); 291 } 292 else if (element.first == "DeliveryRetryIntervalSeconds") 293 { 294 const uint64_t* value = 295 element.second.get_ptr<const uint64_t*>(); 296 if ((value == nullptr) || 297 (*value > std::numeric_limits<uint32_t>::max())) 298 { 299 continue; 300 } 301 retryTimeoutInterval = static_cast<uint32_t>(*value); 302 } 303 } 304 } 305 }; 306 307 class EventServiceStore 308 { 309 public: 310 boost::container::flat_map<std::string, std::shared_ptr<UserSubscription>> 311 subscriptionsConfigMap; 312 EventServiceConfig eventServiceConfig; 313 314 static EventServiceStore& getInstance() 315 { 316 static EventServiceStore eventServiceStore; 317 return eventServiceStore; 318 } 319 320 EventServiceConfig& getEventServiceConfig() 321 { 322 return eventServiceConfig; 323 } 324 }; 325 326 } // namespace persistent_data 327