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