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