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