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