1b52664e2SAppaRao Puli /* 26be832e2SEd Tanous Copyright (c) 2020 Intel Corporation 36be832e2SEd Tanous 46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 56be832e2SEd Tanous you may not use this file except in compliance with the License. 66be832e2SEd Tanous You may obtain a copy of the License at 76be832e2SEd Tanous 86be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 96be832e2SEd Tanous 106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136be832e2SEd Tanous See the License for the specific language governing permissions and 146be832e2SEd Tanous limitations under the License. 15b52664e2SAppaRao Puli */ 16b52664e2SAppaRao Puli #pragma once 17b26ff34dSEd Tanous #include "dbus_log_watcher.hpp" 18*fb546105SMyung Bae #include "dbus_singleton.hpp" 193ccb3adbSEd Tanous #include "dbus_utility.hpp" 203ccb3adbSEd Tanous #include "error_messages.hpp" 21b80ba2e4SAlexander Hansen #include "event_log.hpp" 22d3a48a14SEd Tanous #include "event_matches_filter.hpp" 233ccb3adbSEd Tanous #include "event_service_store.hpp" 242185ddeaSEd Tanous #include "filesystem_log_watcher.hpp" 25c0353249SWludzik, Jozef #include "metric_report.hpp" 262c6ffdb0SEd Tanous #include "ossl_random.hpp" 273ccb3adbSEd Tanous #include "persistent_data.hpp" 2802c1e29fSAlexander Hansen #include "subscription.hpp" 292ac69850SEd Tanous #include "utility.hpp" 302ac69850SEd Tanous #include "utils/dbus_event_log_entry.hpp" 312ac69850SEd Tanous #include "utils/json_utils.hpp" 325b90429aSEd Tanous #include "utils/time_utils.hpp" 337f4eb588SAppaRao Puli 34fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp> 35*fb546105SMyung Bae #include <boost/asio/steady_timer.hpp> 36f80a87f2SEd Tanous #include <boost/circular_buffer.hpp> 37b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp> 38ef4c65b7SEd Tanous #include <boost/url/format.hpp> 394a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp> 401214b7e7SGunnar Mills 415e44e3d8SAppaRao Puli #include <algorithm> 42b52664e2SAppaRao Puli #include <cstdlib> 43b52664e2SAppaRao Puli #include <ctime> 44a14c9113SEd Tanous #include <format> 451bf712bcSAyushi Smriti #include <fstream> 46b52664e2SAppaRao Puli #include <memory> 47a14c9113SEd Tanous #include <string> 4856ba386dSMyung Bae #include <string_view> 495fe4ef35SMyung Bae #include <utility> 502ac69850SEd Tanous #include <variant> 51b52664e2SAppaRao Puli 52b52664e2SAppaRao Puli namespace redfish 53b52664e2SAppaRao Puli { 54156d6b00SAppaRao Puli 55156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event"; 56156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport"; 57156d6b00SAppaRao Puli 581bf712bcSAyushi Smriti static constexpr const char* eventServiceFile = 591bf712bcSAyushi Smriti "/var/lib/bmcweb/eventservice_config.json"; 601bf712bcSAyushi Smriti 61b52664e2SAppaRao Puli class EventServiceManager 62b52664e2SAppaRao Puli { 63b52664e2SAppaRao Puli private: 64d3a9e084SEd Tanous bool serviceEnabled = false; 65d3a9e084SEd Tanous uint32_t retryAttempts = 0; 66d3a9e084SEd Tanous uint32_t retryTimeoutInterval = 0; 677d1cc387SAppaRao Puli 689f616dd1SEd Tanous size_t noOfEventLogSubscribers{0}; 699f616dd1SEd Tanous size_t noOfMetricReportSubscribers{0}; 706c58a03eSAlexander Hansen std::optional<DbusEventLogMonitor> dbusEventLogMonitor; 712ac69850SEd Tanous std::optional<DbusTelemetryMonitor> matchTelemetryMonitor; 727b669723SEd Tanous std::optional<FilesystemLogWatcher> filesystemLogMonitor; 73b52664e2SAppaRao Puli boost::container::flat_map<std::string, std::shared_ptr<Subscription>> 74b52664e2SAppaRao Puli subscriptionsMap; 75b52664e2SAppaRao Puli 769f616dd1SEd Tanous uint64_t eventId{1}; 7796330b99SSunitha Harish 78f80a87f2SEd Tanous struct Event 79f80a87f2SEd Tanous { 80f80a87f2SEd Tanous std::string id; 81f80a87f2SEd Tanous nlohmann::json message; 82f80a87f2SEd Tanous }; 83f80a87f2SEd Tanous 84f80a87f2SEd Tanous constexpr static size_t maxMessages = 200; 85f80a87f2SEd Tanous boost::circular_buffer<Event> messages{maxMessages}; 86f80a87f2SEd Tanous 87f8ca6d79SEd Tanous boost::asio::io_context& ioc; 88f8ca6d79SEd Tanous 89b52664e2SAppaRao Puli public: 909f616dd1SEd Tanous EventServiceManager(const EventServiceManager&) = delete; 919f616dd1SEd Tanous EventServiceManager& operator=(const EventServiceManager&) = delete; 929f616dd1SEd Tanous EventServiceManager(EventServiceManager&&) = delete; 939f616dd1SEd Tanous EventServiceManager& operator=(EventServiceManager&&) = delete; 94ecd6a3a2SEd Tanous ~EventServiceManager() = default; 959f616dd1SEd Tanous 96f8ca6d79SEd Tanous explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn) 97b52664e2SAppaRao Puli { 98f8ca6d79SEd Tanous // Load config from persist store. 99f8ca6d79SEd Tanous initConfig(); 100f8ca6d79SEd Tanous } 101f8ca6d79SEd Tanous 102f8ca6d79SEd Tanous static EventServiceManager& 103f8ca6d79SEd Tanous getInstance(boost::asio::io_context* ioc = nullptr) 104f8ca6d79SEd Tanous { 105f8ca6d79SEd Tanous static EventServiceManager handler(*ioc); 106b52664e2SAppaRao Puli return handler; 107b52664e2SAppaRao Puli } 108b52664e2SAppaRao Puli 1091bf712bcSAyushi Smriti void initConfig() 1101bf712bcSAyushi Smriti { 11128afb49cSJunLin Chen loadOldBehavior(); 1121bf712bcSAyushi Smriti 11328afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 11428afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 11528afb49cSJunLin Chen .getEventServiceConfig(); 1161bf712bcSAyushi Smriti 11728afb49cSJunLin Chen serviceEnabled = eventServiceConfig.enabled; 11828afb49cSJunLin Chen retryAttempts = eventServiceConfig.retryAttempts; 11928afb49cSJunLin Chen retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval; 1201bf712bcSAyushi Smriti 12128afb49cSJunLin Chen for (const auto& it : persistent_data::EventServiceStore::getInstance() 12228afb49cSJunLin Chen .subscriptionsConfigMap) 1231bf712bcSAyushi Smriti { 1245fe4ef35SMyung Bae std::shared_ptr<persistent_data::UserSubscription> newSub = 1255fe4ef35SMyung Bae it.second; 1264bbf237fSAppaRao Puli 1276fd29553SEd Tanous boost::system::result<boost::urls::url> url = 1285fe4ef35SMyung Bae boost::urls::parse_absolute_uri(newSub->destinationUrl); 1291bf712bcSAyushi Smriti 130a716aa74SEd Tanous if (!url) 1311bf712bcSAyushi Smriti { 13262598e31SEd Tanous BMCWEB_LOG_ERROR( 13362598e31SEd Tanous "Failed to validate and split destination url"); 1341bf712bcSAyushi Smriti continue; 1351bf712bcSAyushi Smriti } 1361bf712bcSAyushi Smriti std::shared_ptr<Subscription> subValue = 13721a94d5cSMyung Bae std::make_shared<Subscription>(newSub, *url, ioc); 1385fe4ef35SMyung Bae std::string id = subValue->userSub->id; 139a0969c70SMyung Bae subValue->deleter = [id]() { 140a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 141a0969c70SMyung Bae }; 1421bf712bcSAyushi Smriti 143a0969c70SMyung Bae subscriptionsMap.emplace(id, subValue); 14428afb49cSJunLin Chen 14528afb49cSJunLin Chen updateNoOfSubscribersCount(); 14628afb49cSJunLin Chen 14728afb49cSJunLin Chen // Update retry configuration. 14828afb49cSJunLin Chen subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 149*fb546105SMyung Bae 150*fb546105SMyung Bae // schedule a heartbeat if sendHeartbeat was set to true 151*fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 152*fb546105SMyung Bae { 153*fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 154*fb546105SMyung Bae } 1551bf712bcSAyushi Smriti } 1561bf712bcSAyushi Smriti } 1571bf712bcSAyushi Smriti 15856d2396dSEd Tanous static void loadOldBehavior() 159b52664e2SAppaRao Puli { 16028afb49cSJunLin Chen std::ifstream eventConfigFile(eventServiceFile); 16128afb49cSJunLin Chen if (!eventConfigFile.good()) 1621bf712bcSAyushi Smriti { 16362598e31SEd Tanous BMCWEB_LOG_DEBUG("Old eventService config not exist"); 16428afb49cSJunLin Chen return; 16528afb49cSJunLin Chen } 16628afb49cSJunLin Chen auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false); 16728afb49cSJunLin Chen if (jsonData.is_discarded()) 1684bbf237fSAppaRao Puli { 16962598e31SEd Tanous BMCWEB_LOG_ERROR("Old eventService config parse error."); 17028afb49cSJunLin Chen return; 17128afb49cSJunLin Chen } 17228afb49cSJunLin Chen 1730bdda665SEd Tanous const nlohmann::json::object_t* obj = 1740bdda665SEd Tanous jsonData.get_ptr<const nlohmann::json::object_t*>(); 1750bdda665SEd Tanous for (const auto& item : *obj) 17628afb49cSJunLin Chen { 1770bdda665SEd Tanous if (item.first == "Configuration") 17828afb49cSJunLin Chen { 17928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 18028afb49cSJunLin Chen .getEventServiceConfig() 1810bdda665SEd Tanous .fromJson(item.second); 18228afb49cSJunLin Chen } 1830bdda665SEd Tanous else if (item.first == "Subscriptions") 18428afb49cSJunLin Chen { 1850bdda665SEd Tanous for (const auto& elem : item.second) 18628afb49cSJunLin Chen { 1874b712a29SEd Tanous std::optional<persistent_data::UserSubscription> 18828afb49cSJunLin Chen newSubscription = 18928afb49cSJunLin Chen persistent_data::UserSubscription::fromJson(elem, 19028afb49cSJunLin Chen true); 1914b712a29SEd Tanous if (!newSubscription) 19228afb49cSJunLin Chen { 19362598e31SEd Tanous BMCWEB_LOG_ERROR("Problem reading subscription " 19462598e31SEd Tanous "from old persistent store"); 1954bbf237fSAppaRao Puli continue; 1964bbf237fSAppaRao Puli } 1974b712a29SEd Tanous persistent_data::UserSubscription& newSub = 1984b712a29SEd Tanous *newSubscription; 1991bf712bcSAyushi Smriti 20028afb49cSJunLin Chen std::uniform_int_distribution<uint32_t> dist(0); 20128afb49cSJunLin Chen bmcweb::OpenSSLGenerator gen; 2021bf712bcSAyushi Smriti 20328afb49cSJunLin Chen std::string id; 2041bf712bcSAyushi Smriti 20528afb49cSJunLin Chen int retry = 3; 206e662eae8SEd Tanous while (retry != 0) 2071bf712bcSAyushi Smriti { 20828afb49cSJunLin Chen id = std::to_string(dist(gen)); 20928afb49cSJunLin Chen if (gen.error()) 2107d1cc387SAppaRao Puli { 21128afb49cSJunLin Chen retry = 0; 21228afb49cSJunLin Chen break; 21328afb49cSJunLin Chen } 2144b712a29SEd Tanous newSub.id = id; 21528afb49cSJunLin Chen auto inserted = 21628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 2175fe4ef35SMyung Bae .subscriptionsConfigMap.insert(std::pair( 2185fe4ef35SMyung Bae id, std::make_shared< 2195fe4ef35SMyung Bae persistent_data::UserSubscription>( 2205fe4ef35SMyung Bae newSub))); 22128afb49cSJunLin Chen if (inserted.second) 22228afb49cSJunLin Chen { 22328afb49cSJunLin Chen break; 22428afb49cSJunLin Chen } 22528afb49cSJunLin Chen --retry; 2267d1cc387SAppaRao Puli } 2277d1cc387SAppaRao Puli 22828afb49cSJunLin Chen if (retry <= 0) 22928afb49cSJunLin Chen { 23062598e31SEd Tanous BMCWEB_LOG_ERROR( 23162598e31SEd Tanous "Failed to generate random number from old " 23262598e31SEd Tanous "persistent store"); 23328afb49cSJunLin Chen continue; 23428afb49cSJunLin Chen } 23528afb49cSJunLin Chen } 23628afb49cSJunLin Chen } 23728afb49cSJunLin Chen 23828afb49cSJunLin Chen persistent_data::getConfig().writeData(); 2394c521c3cSEd Tanous std::error_code ec; 2404c521c3cSEd Tanous std::filesystem::remove(eventServiceFile, ec); 2414c521c3cSEd Tanous if (ec) 2424c521c3cSEd Tanous { 2434c521c3cSEd Tanous BMCWEB_LOG_DEBUG( 2444c521c3cSEd Tanous "Failed to remove old event service file. Ignoring"); 2454c521c3cSEd Tanous } 2464c521c3cSEd Tanous else 2474c521c3cSEd Tanous { 24862598e31SEd Tanous BMCWEB_LOG_DEBUG("Remove old eventservice config"); 24928afb49cSJunLin Chen } 25028afb49cSJunLin Chen } 2514c521c3cSEd Tanous } 25228afb49cSJunLin Chen 2539eb808c1SEd Tanous void updateSubscriptionData() const 25428afb49cSJunLin Chen { 25528afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25628afb49cSJunLin Chen .eventServiceConfig.enabled = serviceEnabled; 25728afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25828afb49cSJunLin Chen .eventServiceConfig.retryAttempts = retryAttempts; 25928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 26028afb49cSJunLin Chen .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval; 26128afb49cSJunLin Chen 26228afb49cSJunLin Chen persistent_data::getConfig().writeData(); 26328afb49cSJunLin Chen } 26428afb49cSJunLin Chen 26528afb49cSJunLin Chen void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg) 2667d1cc387SAppaRao Puli { 2677d1cc387SAppaRao Puli bool updateConfig = false; 268fe44eb0bSAyushi Smriti bool updateRetryCfg = false; 2697d1cc387SAppaRao Puli 2702ac69850SEd Tanous if (serviceEnabled) 2717d1cc387SAppaRao Puli { 2727b669723SEd Tanous if (noOfEventLogSubscribers > 0U) 2737b669723SEd Tanous { 2746c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 2756c58a03eSAlexander Hansen { 2766c58a03eSAlexander Hansen if (!dbusEventLogMonitor) 2776c58a03eSAlexander Hansen { 2786c58a03eSAlexander Hansen if constexpr ( 2796c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 2806c58a03eSAlexander Hansen { 2816c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 2826c58a03eSAlexander Hansen } 2836c58a03eSAlexander Hansen } 2846c58a03eSAlexander Hansen } 2856c58a03eSAlexander Hansen else 2867b669723SEd Tanous { 2877b669723SEd Tanous if (!filesystemLogMonitor) 2887b669723SEd Tanous { 2897b669723SEd Tanous filesystemLogMonitor.emplace(ioc); 2907b669723SEd Tanous } 2917b669723SEd Tanous } 2927b669723SEd Tanous } 2937b669723SEd Tanous else 2947b669723SEd Tanous { 2956c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 2967b669723SEd Tanous filesystemLogMonitor.reset(); 2977b669723SEd Tanous } 2987b669723SEd Tanous 2992ac69850SEd Tanous if (noOfMetricReportSubscribers > 0U) 3007d1cc387SAppaRao Puli { 3012ac69850SEd Tanous if (!matchTelemetryMonitor) 3022ac69850SEd Tanous { 3032ac69850SEd Tanous matchTelemetryMonitor.emplace(); 3042ac69850SEd Tanous } 3057d1cc387SAppaRao Puli } 3067d1cc387SAppaRao Puli else 3077d1cc387SAppaRao Puli { 3082ac69850SEd Tanous matchTelemetryMonitor.reset(); 3097d1cc387SAppaRao Puli } 3102ac69850SEd Tanous } 3112ac69850SEd Tanous else 3122ac69850SEd Tanous { 3132ac69850SEd Tanous matchTelemetryMonitor.reset(); 3146c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3157b669723SEd Tanous filesystemLogMonitor.reset(); 3162ac69850SEd Tanous } 3172ac69850SEd Tanous 3182ac69850SEd Tanous if (serviceEnabled != cfg.enabled) 3192ac69850SEd Tanous { 3202ac69850SEd Tanous serviceEnabled = cfg.enabled; 3217d1cc387SAppaRao Puli updateConfig = true; 3227d1cc387SAppaRao Puli } 3237d1cc387SAppaRao Puli 32428afb49cSJunLin Chen if (retryAttempts != cfg.retryAttempts) 3257d1cc387SAppaRao Puli { 32628afb49cSJunLin Chen retryAttempts = cfg.retryAttempts; 3277d1cc387SAppaRao Puli updateConfig = true; 328fe44eb0bSAyushi Smriti updateRetryCfg = true; 3297d1cc387SAppaRao Puli } 3307d1cc387SAppaRao Puli 33128afb49cSJunLin Chen if (retryTimeoutInterval != cfg.retryTimeoutInterval) 3327d1cc387SAppaRao Puli { 33328afb49cSJunLin Chen retryTimeoutInterval = cfg.retryTimeoutInterval; 3347d1cc387SAppaRao Puli updateConfig = true; 335fe44eb0bSAyushi Smriti updateRetryCfg = true; 3367d1cc387SAppaRao Puli } 3377d1cc387SAppaRao Puli 3387d1cc387SAppaRao Puli if (updateConfig) 3397d1cc387SAppaRao Puli { 3407d1cc387SAppaRao Puli updateSubscriptionData(); 3417d1cc387SAppaRao Puli } 342fe44eb0bSAyushi Smriti 343fe44eb0bSAyushi Smriti if (updateRetryCfg) 344fe44eb0bSAyushi Smriti { 345fe44eb0bSAyushi Smriti // Update the changed retry config to all subscriptions 346fe44eb0bSAyushi Smriti for (const auto& it : 347fe44eb0bSAyushi Smriti EventServiceManager::getInstance().subscriptionsMap) 348fe44eb0bSAyushi Smriti { 3495e44e3d8SAppaRao Puli Subscription& entry = *it.second; 3505e44e3d8SAppaRao Puli entry.updateRetryConfig(retryAttempts, retryTimeoutInterval); 351fe44eb0bSAyushi Smriti } 352fe44eb0bSAyushi Smriti } 3537d1cc387SAppaRao Puli } 3547d1cc387SAppaRao Puli 3557d1cc387SAppaRao Puli void updateNoOfSubscribersCount() 3567d1cc387SAppaRao Puli { 3577d1cc387SAppaRao Puli size_t eventLogSubCount = 0; 3587d1cc387SAppaRao Puli size_t metricReportSubCount = 0; 3597d1cc387SAppaRao Puli for (const auto& it : subscriptionsMap) 3607d1cc387SAppaRao Puli { 3617d1cc387SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 3625fe4ef35SMyung Bae if (entry->userSub->eventFormatType == eventFormatType) 3637d1cc387SAppaRao Puli { 3647d1cc387SAppaRao Puli eventLogSubCount++; 3657d1cc387SAppaRao Puli } 3665fe4ef35SMyung Bae else if (entry->userSub->eventFormatType == metricReportFormatType) 3677d1cc387SAppaRao Puli { 3687d1cc387SAppaRao Puli metricReportSubCount++; 3697d1cc387SAppaRao Puli } 3707d1cc387SAppaRao Puli } 3717d1cc387SAppaRao Puli noOfEventLogSubscribers = eventLogSubCount; 3726c58a03eSAlexander Hansen if (eventLogSubCount > 0U) 3737d1cc387SAppaRao Puli { 3746c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 3756c58a03eSAlexander Hansen { 3766c58a03eSAlexander Hansen if (!dbusEventLogMonitor && 3776c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 3786c58a03eSAlexander Hansen { 3796c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 3806c58a03eSAlexander Hansen } 3816c58a03eSAlexander Hansen } 3826c58a03eSAlexander Hansen else 3836c58a03eSAlexander Hansen { 3846c58a03eSAlexander Hansen if (!filesystemLogMonitor) 3856c58a03eSAlexander Hansen { 3866c58a03eSAlexander Hansen filesystemLogMonitor.emplace(ioc); 3876c58a03eSAlexander Hansen } 3886c58a03eSAlexander Hansen } 3896c58a03eSAlexander Hansen } 3906c58a03eSAlexander Hansen else 3916c58a03eSAlexander Hansen { 3926c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3936c58a03eSAlexander Hansen filesystemLogMonitor.reset(); 3946c58a03eSAlexander Hansen } 3956c58a03eSAlexander Hansen 3967d1cc387SAppaRao Puli noOfMetricReportSubscribers = metricReportSubCount; 3976c58a03eSAlexander Hansen if (metricReportSubCount > 0U) 3987d1cc387SAppaRao Puli { 3992ac69850SEd Tanous if (!matchTelemetryMonitor) 4002ac69850SEd Tanous { 4012ac69850SEd Tanous matchTelemetryMonitor.emplace(); 4022ac69850SEd Tanous } 4037d1cc387SAppaRao Puli } 4047d1cc387SAppaRao Puli else 4057d1cc387SAppaRao Puli { 4062ac69850SEd Tanous matchTelemetryMonitor.reset(); 4077d1cc387SAppaRao Puli } 4087d1cc387SAppaRao Puli } 4097d1cc387SAppaRao Puli 410b52664e2SAppaRao Puli std::shared_ptr<Subscription> getSubscription(const std::string& id) 411b52664e2SAppaRao Puli { 412b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 413b52664e2SAppaRao Puli if (obj == subscriptionsMap.end()) 414b52664e2SAppaRao Puli { 41562598e31SEd Tanous BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id); 416b52664e2SAppaRao Puli return nullptr; 417b52664e2SAppaRao Puli } 418b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = obj->second; 419b52664e2SAppaRao Puli return subValue; 420b52664e2SAppaRao Puli } 421b52664e2SAppaRao Puli 422f80a87f2SEd Tanous std::string 423f80a87f2SEd Tanous addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue) 424b52664e2SAppaRao Puli { 425fc76b8acSEd Tanous std::uniform_int_distribution<uint32_t> dist(0); 426fc76b8acSEd Tanous bmcweb::OpenSSLGenerator gen; 427fc76b8acSEd Tanous 428b52664e2SAppaRao Puli std::string id; 429b52664e2SAppaRao Puli 430b52664e2SAppaRao Puli int retry = 3; 431e662eae8SEd Tanous while (retry != 0) 432b52664e2SAppaRao Puli { 433fc76b8acSEd Tanous id = std::to_string(dist(gen)); 434fc76b8acSEd Tanous if (gen.error()) 435fc76b8acSEd Tanous { 436fc76b8acSEd Tanous retry = 0; 437fc76b8acSEd Tanous break; 438fc76b8acSEd Tanous } 439b52664e2SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 440b52664e2SAppaRao Puli if (inserted.second) 441b52664e2SAppaRao Puli { 442b52664e2SAppaRao Puli break; 443b52664e2SAppaRao Puli } 444b52664e2SAppaRao Puli --retry; 44523a21a1cSEd Tanous } 446b52664e2SAppaRao Puli 447b52664e2SAppaRao Puli if (retry <= 0) 448b52664e2SAppaRao Puli { 44962598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to generate random number"); 450abb93cddSEd Tanous return ""; 451b52664e2SAppaRao Puli } 452b52664e2SAppaRao Puli 45356ba386dSMyung Bae // Set Subscription ID for back trace 4545fe4ef35SMyung Bae subValue->userSub->id = id; 455a14c9113SEd Tanous 45628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 4575fe4ef35SMyung Bae .subscriptionsConfigMap.emplace(id, subValue->userSub); 45828afb49cSJunLin Chen 4597d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 4601bf712bcSAyushi Smriti 461fe44eb0bSAyushi Smriti // Update retry configuration. 462fe44eb0bSAyushi Smriti subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 463fe44eb0bSAyushi Smriti 464f80a87f2SEd Tanous return id; 465f80a87f2SEd Tanous } 466f80a87f2SEd Tanous 467f80a87f2SEd Tanous std::string 468f80a87f2SEd Tanous addSSESubscription(const std::shared_ptr<Subscription>& subValue, 469f80a87f2SEd Tanous std::string_view lastEventId) 470f80a87f2SEd Tanous { 471f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 472f80a87f2SEd Tanous 473f80a87f2SEd Tanous if (!lastEventId.empty()) 474f80a87f2SEd Tanous { 475f80a87f2SEd Tanous BMCWEB_LOG_INFO("Attempting to find message for last id {}", 476f80a87f2SEd Tanous lastEventId); 477f80a87f2SEd Tanous boost::circular_buffer<Event>::iterator lastEvent = 478f80a87f2SEd Tanous std::find_if(messages.begin(), messages.end(), 479f80a87f2SEd Tanous [&lastEventId](const Event& event) { 480f80a87f2SEd Tanous return event.id == lastEventId; 481f80a87f2SEd Tanous }); 482f80a87f2SEd Tanous // Can't find a matching ID 483f80a87f2SEd Tanous if (lastEvent == messages.end()) 484f80a87f2SEd Tanous { 485f80a87f2SEd Tanous nlohmann::json msg = messages::eventBufferExceeded(); 486f80a87f2SEd Tanous // If the buffer overloaded, send all messages. 4876d799e14SEd Tanous subValue->sendEventToSubscriber(msg); 488f80a87f2SEd Tanous lastEvent = messages.begin(); 489f80a87f2SEd Tanous } 490f80a87f2SEd Tanous else 491f80a87f2SEd Tanous { 492f80a87f2SEd Tanous // Skip the last event the user already has 493f80a87f2SEd Tanous lastEvent++; 494f80a87f2SEd Tanous } 495f80a87f2SEd Tanous 496f80a87f2SEd Tanous for (boost::circular_buffer<Event>::const_iterator event = 497f80a87f2SEd Tanous lastEvent; 498f80a87f2SEd Tanous lastEvent != messages.end(); lastEvent++) 499f80a87f2SEd Tanous { 5006d799e14SEd Tanous subValue->sendEventToSubscriber(event->message); 501f80a87f2SEd Tanous } 502f80a87f2SEd Tanous } 503f80a87f2SEd Tanous return id; 504f80a87f2SEd Tanous } 505f80a87f2SEd Tanous 506f80a87f2SEd Tanous std::string 507f80a87f2SEd Tanous addPushSubscription(const std::shared_ptr<Subscription>& subValue) 508f80a87f2SEd Tanous { 509f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 510a0969c70SMyung Bae subValue->deleter = [id]() { 511a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 512a0969c70SMyung Bae }; 513f80a87f2SEd Tanous updateSubscriptionData(); 514b52664e2SAppaRao Puli return id; 515b52664e2SAppaRao Puli } 516b52664e2SAppaRao Puli 517b52664e2SAppaRao Puli bool isSubscriptionExist(const std::string& id) 518b52664e2SAppaRao Puli { 519b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 52055f79e6fSEd Tanous return obj != subscriptionsMap.end(); 521b52664e2SAppaRao Puli } 522b52664e2SAppaRao Puli 5234b712a29SEd Tanous bool deleteSubscription(const std::string& id) 524b52664e2SAppaRao Puli { 525b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 5264b712a29SEd Tanous if (obj == subscriptionsMap.end()) 527b52664e2SAppaRao Puli { 5284b712a29SEd Tanous BMCWEB_LOG_WARNING("Could not find subscription with id {}", id); 5294b712a29SEd Tanous return false; 5304b712a29SEd Tanous } 531b52664e2SAppaRao Puli subscriptionsMap.erase(obj); 5324b712a29SEd Tanous auto& event = persistent_data::EventServiceStore::getInstance(); 5334b712a29SEd Tanous auto persistentObj = event.subscriptionsConfigMap.find(id); 5344b712a29SEd Tanous if (persistentObj == event.subscriptionsConfigMap.end()) 5354b712a29SEd Tanous { 5364b712a29SEd Tanous BMCWEB_LOG_ERROR("Subscription wasn't in persistent data"); 5374b712a29SEd Tanous return true; 5384b712a29SEd Tanous } 53928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 5404b712a29SEd Tanous .subscriptionsConfigMap.erase(persistentObj); 5417d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 542b52664e2SAppaRao Puli updateSubscriptionData(); 5434b712a29SEd Tanous 5444b712a29SEd Tanous return true; 545b52664e2SAppaRao Puli } 546b52664e2SAppaRao Puli 5475e44e3d8SAppaRao Puli void deleteSseSubscription(const crow::sse_socket::Connection& thisConn) 5485e44e3d8SAppaRao Puli { 549bdbfae2aSEd Tanous for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();) 5505e44e3d8SAppaRao Puli { 551bdbfae2aSEd Tanous std::shared_ptr<Subscription> entry = it->second; 5525e44e3d8SAppaRao Puli bool entryIsThisConn = entry->matchSseId(thisConn); 5535e44e3d8SAppaRao Puli if (entryIsThisConn) 5545e44e3d8SAppaRao Puli { 5555e44e3d8SAppaRao Puli persistent_data::EventServiceStore::getInstance() 5565fe4ef35SMyung Bae .subscriptionsConfigMap.erase(entry->userSub->id); 557bdbfae2aSEd Tanous it = subscriptionsMap.erase(it); 5585e44e3d8SAppaRao Puli return; 5595e44e3d8SAppaRao Puli } 560bdbfae2aSEd Tanous it++; 5615e44e3d8SAppaRao Puli } 5625e44e3d8SAppaRao Puli } 5635e44e3d8SAppaRao Puli 5645e44e3d8SAppaRao Puli size_t getNumberOfSubscriptions() const 565b52664e2SAppaRao Puli { 566b52664e2SAppaRao Puli return subscriptionsMap.size(); 567b52664e2SAppaRao Puli } 568b52664e2SAppaRao Puli 5695e44e3d8SAppaRao Puli size_t getNumberOfSSESubscriptions() const 5705e44e3d8SAppaRao Puli { 5713544d2a7SEd Tanous auto size = std::ranges::count_if( 5723544d2a7SEd Tanous subscriptionsMap, 5735e44e3d8SAppaRao Puli [](const std::pair<std::string, std::shared_ptr<Subscription>>& 5745e44e3d8SAppaRao Puli entry) { 5755fe4ef35SMyung Bae return (entry.second->userSub->subscriptionType == 5764b712a29SEd Tanous subscriptionTypeSSE); 5775e44e3d8SAppaRao Puli }); 5785e44e3d8SAppaRao Puli return static_cast<size_t>(size); 5795e44e3d8SAppaRao Puli } 5805e44e3d8SAppaRao Puli 581b52664e2SAppaRao Puli std::vector<std::string> getAllIDs() 582b52664e2SAppaRao Puli { 583b52664e2SAppaRao Puli std::vector<std::string> idList; 584b52664e2SAppaRao Puli for (const auto& it : subscriptionsMap) 585b52664e2SAppaRao Puli { 586b52664e2SAppaRao Puli idList.emplace_back(it.first); 587b52664e2SAppaRao Puli } 588b52664e2SAppaRao Puli return idList; 589b52664e2SAppaRao Puli } 590b52664e2SAppaRao Puli 5916ba8c82eSsunharis_in bool sendTestEventLog() 5920b4bdd93SAppaRao Puli { 5935e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 5940b4bdd93SAppaRao Puli { 5950b4bdd93SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 5966ba8c82eSsunharis_in if (!entry->sendTestEventLog()) 5976ba8c82eSsunharis_in { 5986ba8c82eSsunharis_in return false; 5990b4bdd93SAppaRao Puli } 6000b4bdd93SAppaRao Puli } 6016ba8c82eSsunharis_in return true; 6026ba8c82eSsunharis_in } 603e9a14131SAppaRao Puli 6043433b03aSEd Tanous static void 6053433b03aSEd Tanous sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords) 6063433b03aSEd Tanous { 6073433b03aSEd Tanous for (const auto& it : 6083433b03aSEd Tanous EventServiceManager::getInstance().subscriptionsMap) 6093433b03aSEd Tanous { 6103433b03aSEd Tanous Subscription& entry = *it.second; 6113433b03aSEd Tanous entry.filterAndSendEventLogs(eventRecords); 6123433b03aSEd Tanous } 6133433b03aSEd Tanous } 6143433b03aSEd Tanous 615b26ff34dSEd Tanous static void sendTelemetryReportToSubs( 616b26ff34dSEd Tanous const std::string& reportId, const telemetry::TimestampReadings& var) 617b26ff34dSEd Tanous { 618b26ff34dSEd Tanous for (const auto& it : 619b26ff34dSEd Tanous EventServiceManager::getInstance().subscriptionsMap) 620b26ff34dSEd Tanous { 621b26ff34dSEd Tanous Subscription& entry = *it.second; 622b26ff34dSEd Tanous entry.filterAndSendReports(reportId, var); 623b26ff34dSEd Tanous } 624b26ff34dSEd Tanous } 625b26ff34dSEd Tanous 626f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 627f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 62896330b99SSunitha Harish { 629613dabeaSEd Tanous eventMessage["EventId"] = eventId; 630f80a87f2SEd Tanous 631613dabeaSEd Tanous eventMessage["EventTimestamp"] = 632613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 633613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 634613dabeaSEd Tanous 635f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 636788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 63796330b99SSunitha Harish 638f80a87f2SEd Tanous messages.push_back(Event(std::to_string(eventId), eventMessage)); 639f80a87f2SEd Tanous 640f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 64196330b99SSunitha Harish { 642f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 6435fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 6445fe4ef35SMyung Bae resourceType)) 64596330b99SSunitha Harish { 646f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 647f80a87f2SEd Tanous continue; 64896330b99SSunitha Harish } 649f80a87f2SEd Tanous 650f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 651f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 652f80a87f2SEd Tanous 653613dabeaSEd Tanous nlohmann::json msgJson; 654613dabeaSEd Tanous 655613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 656613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 657613dabeaSEd Tanous msgJson["Id"] = eventId; 658f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 659f52c03c1SCarson Labrado 660f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 661f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 6626d799e14SEd Tanous entry->sendEventToSubscriber(std::move(strMsg)); 6638ece0e45SEd Tanous eventId++; // increment the eventId 66496330b99SSunitha Harish } 66596330b99SSunitha Harish } 66623a21a1cSEd Tanous }; 667b52664e2SAppaRao Puli 668b52664e2SAppaRao Puli } // namespace redfish 669