1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2020 Intel Corporation 4b52664e2SAppaRao Puli #pragma once 5b26ff34dSEd Tanous #include "dbus_log_watcher.hpp" 6fb546105SMyung Bae #include "dbus_singleton.hpp" 73ccb3adbSEd Tanous #include "dbus_utility.hpp" 83ccb3adbSEd Tanous #include "error_messages.hpp" 9b80ba2e4SAlexander Hansen #include "event_log.hpp" 10d3a48a14SEd Tanous #include "event_matches_filter.hpp" 113ccb3adbSEd Tanous #include "event_service_store.hpp" 122185ddeaSEd Tanous #include "filesystem_log_watcher.hpp" 13c0353249SWludzik, Jozef #include "metric_report.hpp" 142c6ffdb0SEd Tanous #include "ossl_random.hpp" 153ccb3adbSEd Tanous #include "persistent_data.hpp" 1602c1e29fSAlexander Hansen #include "subscription.hpp" 172ac69850SEd Tanous #include "utility.hpp" 182ac69850SEd Tanous #include "utils/dbus_event_log_entry.hpp" 192ac69850SEd Tanous #include "utils/json_utils.hpp" 205b90429aSEd Tanous #include "utils/time_utils.hpp" 217f4eb588SAppaRao Puli 22fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp> 23fb546105SMyung Bae #include <boost/asio/steady_timer.hpp> 24f80a87f2SEd Tanous #include <boost/circular_buffer.hpp> 25b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp> 26ef4c65b7SEd Tanous #include <boost/url/format.hpp> 274a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp> 281214b7e7SGunnar Mills 295e44e3d8SAppaRao Puli #include <algorithm> 30b52664e2SAppaRao Puli #include <cstdlib> 31b52664e2SAppaRao Puli #include <ctime> 32a14c9113SEd Tanous #include <format> 331bf712bcSAyushi Smriti #include <fstream> 34b52664e2SAppaRao Puli #include <memory> 35a14c9113SEd Tanous #include <string> 3656ba386dSMyung Bae #include <string_view> 375fe4ef35SMyung Bae #include <utility> 382ac69850SEd Tanous #include <variant> 39b52664e2SAppaRao Puli 40b52664e2SAppaRao Puli namespace redfish 41b52664e2SAppaRao Puli { 42156d6b00SAppaRao Puli 43156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event"; 44156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport"; 45156d6b00SAppaRao Puli 461bf712bcSAyushi Smriti static constexpr const char* eventServiceFile = 471bf712bcSAyushi Smriti "/var/lib/bmcweb/eventservice_config.json"; 481bf712bcSAyushi Smriti 49b52664e2SAppaRao Puli class EventServiceManager 50b52664e2SAppaRao Puli { 51b52664e2SAppaRao Puli private: 52d3a9e084SEd Tanous bool serviceEnabled = false; 53d3a9e084SEd Tanous uint32_t retryAttempts = 0; 54d3a9e084SEd Tanous uint32_t retryTimeoutInterval = 0; 557d1cc387SAppaRao Puli 569f616dd1SEd Tanous size_t noOfEventLogSubscribers{0}; 579f616dd1SEd Tanous size_t noOfMetricReportSubscribers{0}; 586c58a03eSAlexander Hansen std::optional<DbusEventLogMonitor> dbusEventLogMonitor; 592ac69850SEd Tanous std::optional<DbusTelemetryMonitor> matchTelemetryMonitor; 607b669723SEd Tanous std::optional<FilesystemLogWatcher> filesystemLogMonitor; 61b52664e2SAppaRao Puli boost::container::flat_map<std::string, std::shared_ptr<Subscription>> 62b52664e2SAppaRao Puli subscriptionsMap; 63b52664e2SAppaRao Puli 649f616dd1SEd Tanous uint64_t eventId{1}; 6596330b99SSunitha Harish 66f80a87f2SEd Tanous struct Event 67f80a87f2SEd Tanous { 68f80a87f2SEd Tanous std::string id; 69f80a87f2SEd Tanous nlohmann::json message; 70f80a87f2SEd Tanous }; 71f80a87f2SEd Tanous 72f80a87f2SEd Tanous constexpr static size_t maxMessages = 200; 73f80a87f2SEd Tanous boost::circular_buffer<Event> messages{maxMessages}; 74f80a87f2SEd Tanous 75f8ca6d79SEd Tanous boost::asio::io_context& ioc; 76f8ca6d79SEd Tanous 77b52664e2SAppaRao Puli public: 789f616dd1SEd Tanous EventServiceManager(const EventServiceManager&) = delete; 799f616dd1SEd Tanous EventServiceManager& operator=(const EventServiceManager&) = delete; 809f616dd1SEd Tanous EventServiceManager(EventServiceManager&&) = delete; 819f616dd1SEd Tanous EventServiceManager& operator=(EventServiceManager&&) = delete; 82ecd6a3a2SEd Tanous ~EventServiceManager() = default; 839f616dd1SEd Tanous 84f8ca6d79SEd Tanous explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn) 85b52664e2SAppaRao Puli { 86f8ca6d79SEd Tanous // Load config from persist store. 87f8ca6d79SEd Tanous initConfig(); 88f8ca6d79SEd Tanous } 89f8ca6d79SEd Tanous 90f8ca6d79SEd Tanous static EventServiceManager& 91f8ca6d79SEd Tanous getInstance(boost::asio::io_context* ioc = nullptr) 92f8ca6d79SEd Tanous { 93f8ca6d79SEd Tanous static EventServiceManager handler(*ioc); 94b52664e2SAppaRao Puli return handler; 95b52664e2SAppaRao Puli } 96b52664e2SAppaRao Puli 971bf712bcSAyushi Smriti void initConfig() 981bf712bcSAyushi Smriti { 9928afb49cSJunLin Chen loadOldBehavior(); 1001bf712bcSAyushi Smriti 10128afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 10228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 10328afb49cSJunLin Chen .getEventServiceConfig(); 1041bf712bcSAyushi Smriti 10528afb49cSJunLin Chen serviceEnabled = eventServiceConfig.enabled; 10628afb49cSJunLin Chen retryAttempts = eventServiceConfig.retryAttempts; 10728afb49cSJunLin Chen retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval; 1081bf712bcSAyushi Smriti 10928afb49cSJunLin Chen for (const auto& it : persistent_data::EventServiceStore::getInstance() 11028afb49cSJunLin Chen .subscriptionsConfigMap) 1111bf712bcSAyushi Smriti { 1125fe4ef35SMyung Bae std::shared_ptr<persistent_data::UserSubscription> newSub = 1135fe4ef35SMyung Bae it.second; 1144bbf237fSAppaRao Puli 1156fd29553SEd Tanous boost::system::result<boost::urls::url> url = 1165fe4ef35SMyung Bae boost::urls::parse_absolute_uri(newSub->destinationUrl); 1171bf712bcSAyushi Smriti 118a716aa74SEd Tanous if (!url) 1191bf712bcSAyushi Smriti { 12062598e31SEd Tanous BMCWEB_LOG_ERROR( 12162598e31SEd Tanous "Failed to validate and split destination url"); 1221bf712bcSAyushi Smriti continue; 1231bf712bcSAyushi Smriti } 1241bf712bcSAyushi Smriti std::shared_ptr<Subscription> subValue = 12521a94d5cSMyung Bae std::make_shared<Subscription>(newSub, *url, ioc); 1265fe4ef35SMyung Bae std::string id = subValue->userSub->id; 127a0969c70SMyung Bae subValue->deleter = [id]() { 128a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 129a0969c70SMyung Bae }; 1301bf712bcSAyushi Smriti 131a0969c70SMyung Bae subscriptionsMap.emplace(id, subValue); 13228afb49cSJunLin Chen 13328afb49cSJunLin Chen updateNoOfSubscribersCount(); 13428afb49cSJunLin Chen 13528afb49cSJunLin Chen // Update retry configuration. 13628afb49cSJunLin Chen subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 137fb546105SMyung Bae 138fb546105SMyung Bae // schedule a heartbeat if sendHeartbeat was set to true 139fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 140fb546105SMyung Bae { 141fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 142fb546105SMyung Bae } 1431bf712bcSAyushi Smriti } 1441bf712bcSAyushi Smriti } 1451bf712bcSAyushi Smriti 14656d2396dSEd Tanous static void loadOldBehavior() 147b52664e2SAppaRao Puli { 14828afb49cSJunLin Chen std::ifstream eventConfigFile(eventServiceFile); 14928afb49cSJunLin Chen if (!eventConfigFile.good()) 1501bf712bcSAyushi Smriti { 15162598e31SEd Tanous BMCWEB_LOG_DEBUG("Old eventService config not exist"); 15228afb49cSJunLin Chen return; 15328afb49cSJunLin Chen } 15428afb49cSJunLin Chen auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false); 15528afb49cSJunLin Chen if (jsonData.is_discarded()) 1564bbf237fSAppaRao Puli { 15762598e31SEd Tanous BMCWEB_LOG_ERROR("Old eventService config parse error."); 15828afb49cSJunLin Chen return; 15928afb49cSJunLin Chen } 16028afb49cSJunLin Chen 1610bdda665SEd Tanous const nlohmann::json::object_t* obj = 1620bdda665SEd Tanous jsonData.get_ptr<const nlohmann::json::object_t*>(); 1631c588de9SAbiola Asojo if (obj == nullptr) 1641c588de9SAbiola Asojo { 1651c588de9SAbiola Asojo return; 1661c588de9SAbiola Asojo } 1670bdda665SEd Tanous for (const auto& item : *obj) 16828afb49cSJunLin Chen { 1690bdda665SEd Tanous if (item.first == "Configuration") 17028afb49cSJunLin Chen { 17128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 17228afb49cSJunLin Chen .getEventServiceConfig() 1730bdda665SEd Tanous .fromJson(item.second); 17428afb49cSJunLin Chen } 1750bdda665SEd Tanous else if (item.first == "Subscriptions") 17628afb49cSJunLin Chen { 1770bdda665SEd Tanous for (const auto& elem : item.second) 17828afb49cSJunLin Chen { 1794b712a29SEd Tanous std::optional<persistent_data::UserSubscription> 18028afb49cSJunLin Chen newSubscription = 18128afb49cSJunLin Chen persistent_data::UserSubscription::fromJson(elem, 18228afb49cSJunLin Chen true); 1834b712a29SEd Tanous if (!newSubscription) 18428afb49cSJunLin Chen { 18562598e31SEd Tanous BMCWEB_LOG_ERROR("Problem reading subscription " 18662598e31SEd Tanous "from old persistent store"); 1874bbf237fSAppaRao Puli continue; 1884bbf237fSAppaRao Puli } 1894b712a29SEd Tanous persistent_data::UserSubscription& newSub = 1904b712a29SEd Tanous *newSubscription; 1911bf712bcSAyushi Smriti 19228afb49cSJunLin Chen std::uniform_int_distribution<uint32_t> dist(0); 19328afb49cSJunLin Chen bmcweb::OpenSSLGenerator gen; 1941bf712bcSAyushi Smriti 19528afb49cSJunLin Chen std::string id; 1961bf712bcSAyushi Smriti 19728afb49cSJunLin Chen int retry = 3; 198e662eae8SEd Tanous while (retry != 0) 1991bf712bcSAyushi Smriti { 20028afb49cSJunLin Chen id = std::to_string(dist(gen)); 20128afb49cSJunLin Chen if (gen.error()) 2027d1cc387SAppaRao Puli { 20328afb49cSJunLin Chen retry = 0; 20428afb49cSJunLin Chen break; 20528afb49cSJunLin Chen } 2064b712a29SEd Tanous newSub.id = id; 20728afb49cSJunLin Chen auto inserted = 20828afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 2095fe4ef35SMyung Bae .subscriptionsConfigMap.insert(std::pair( 2105fe4ef35SMyung Bae id, std::make_shared< 2115fe4ef35SMyung Bae persistent_data::UserSubscription>( 2125fe4ef35SMyung Bae newSub))); 21328afb49cSJunLin Chen if (inserted.second) 21428afb49cSJunLin Chen { 21528afb49cSJunLin Chen break; 21628afb49cSJunLin Chen } 21728afb49cSJunLin Chen --retry; 2187d1cc387SAppaRao Puli } 2197d1cc387SAppaRao Puli 22028afb49cSJunLin Chen if (retry <= 0) 22128afb49cSJunLin Chen { 22262598e31SEd Tanous BMCWEB_LOG_ERROR( 22362598e31SEd Tanous "Failed to generate random number from old " 22462598e31SEd Tanous "persistent store"); 22528afb49cSJunLin Chen continue; 22628afb49cSJunLin Chen } 22728afb49cSJunLin Chen } 22828afb49cSJunLin Chen } 22928afb49cSJunLin Chen 23028afb49cSJunLin Chen persistent_data::getConfig().writeData(); 2314c521c3cSEd Tanous std::error_code ec; 2324c521c3cSEd Tanous std::filesystem::remove(eventServiceFile, ec); 2334c521c3cSEd Tanous if (ec) 2344c521c3cSEd Tanous { 2354c521c3cSEd Tanous BMCWEB_LOG_DEBUG( 2364c521c3cSEd Tanous "Failed to remove old event service file. Ignoring"); 2374c521c3cSEd Tanous } 2384c521c3cSEd Tanous else 2394c521c3cSEd Tanous { 24062598e31SEd Tanous BMCWEB_LOG_DEBUG("Remove old eventservice config"); 24128afb49cSJunLin Chen } 24228afb49cSJunLin Chen } 2434c521c3cSEd Tanous } 24428afb49cSJunLin Chen 2459eb808c1SEd Tanous void updateSubscriptionData() const 24628afb49cSJunLin Chen { 24728afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 24828afb49cSJunLin Chen .eventServiceConfig.enabled = serviceEnabled; 24928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25028afb49cSJunLin Chen .eventServiceConfig.retryAttempts = retryAttempts; 25128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25228afb49cSJunLin Chen .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval; 25328afb49cSJunLin Chen 25428afb49cSJunLin Chen persistent_data::getConfig().writeData(); 25528afb49cSJunLin Chen } 25628afb49cSJunLin Chen 25728afb49cSJunLin Chen void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg) 2587d1cc387SAppaRao Puli { 2597d1cc387SAppaRao Puli bool updateConfig = false; 260fe44eb0bSAyushi Smriti bool updateRetryCfg = false; 2617d1cc387SAppaRao Puli 2622ac69850SEd Tanous if (serviceEnabled) 2637d1cc387SAppaRao Puli { 2647b669723SEd Tanous if (noOfEventLogSubscribers > 0U) 2657b669723SEd Tanous { 2666c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 2676c58a03eSAlexander Hansen { 2686c58a03eSAlexander Hansen if (!dbusEventLogMonitor) 2696c58a03eSAlexander Hansen { 2706c58a03eSAlexander Hansen if constexpr ( 2716c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 2726c58a03eSAlexander Hansen { 2736c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 2746c58a03eSAlexander Hansen } 2756c58a03eSAlexander Hansen } 2766c58a03eSAlexander Hansen } 2776c58a03eSAlexander Hansen else 2787b669723SEd Tanous { 2797b669723SEd Tanous if (!filesystemLogMonitor) 2807b669723SEd Tanous { 2817b669723SEd Tanous filesystemLogMonitor.emplace(ioc); 2827b669723SEd Tanous } 2837b669723SEd Tanous } 2847b669723SEd Tanous } 2857b669723SEd Tanous else 2867b669723SEd Tanous { 2876c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 2887b669723SEd Tanous filesystemLogMonitor.reset(); 2897b669723SEd Tanous } 2907b669723SEd Tanous 2912ac69850SEd Tanous if (noOfMetricReportSubscribers > 0U) 2927d1cc387SAppaRao Puli { 2932ac69850SEd Tanous if (!matchTelemetryMonitor) 2942ac69850SEd Tanous { 2952ac69850SEd Tanous matchTelemetryMonitor.emplace(); 2962ac69850SEd Tanous } 2977d1cc387SAppaRao Puli } 2987d1cc387SAppaRao Puli else 2997d1cc387SAppaRao Puli { 3002ac69850SEd Tanous matchTelemetryMonitor.reset(); 3017d1cc387SAppaRao Puli } 3022ac69850SEd Tanous } 3032ac69850SEd Tanous else 3042ac69850SEd Tanous { 3052ac69850SEd Tanous matchTelemetryMonitor.reset(); 3066c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3077b669723SEd Tanous filesystemLogMonitor.reset(); 3082ac69850SEd Tanous } 3092ac69850SEd Tanous 3102ac69850SEd Tanous if (serviceEnabled != cfg.enabled) 3112ac69850SEd Tanous { 3122ac69850SEd Tanous serviceEnabled = cfg.enabled; 3137d1cc387SAppaRao Puli updateConfig = true; 3147d1cc387SAppaRao Puli } 3157d1cc387SAppaRao Puli 31628afb49cSJunLin Chen if (retryAttempts != cfg.retryAttempts) 3177d1cc387SAppaRao Puli { 31828afb49cSJunLin Chen retryAttempts = cfg.retryAttempts; 3197d1cc387SAppaRao Puli updateConfig = true; 320fe44eb0bSAyushi Smriti updateRetryCfg = true; 3217d1cc387SAppaRao Puli } 3227d1cc387SAppaRao Puli 32328afb49cSJunLin Chen if (retryTimeoutInterval != cfg.retryTimeoutInterval) 3247d1cc387SAppaRao Puli { 32528afb49cSJunLin Chen retryTimeoutInterval = cfg.retryTimeoutInterval; 3267d1cc387SAppaRao Puli updateConfig = true; 327fe44eb0bSAyushi Smriti updateRetryCfg = true; 3287d1cc387SAppaRao Puli } 3297d1cc387SAppaRao Puli 3307d1cc387SAppaRao Puli if (updateConfig) 3317d1cc387SAppaRao Puli { 3327d1cc387SAppaRao Puli updateSubscriptionData(); 3337d1cc387SAppaRao Puli } 334fe44eb0bSAyushi Smriti 335fe44eb0bSAyushi Smriti if (updateRetryCfg) 336fe44eb0bSAyushi Smriti { 337fe44eb0bSAyushi Smriti // Update the changed retry config to all subscriptions 338fe44eb0bSAyushi Smriti for (const auto& it : 339fe44eb0bSAyushi Smriti EventServiceManager::getInstance().subscriptionsMap) 340fe44eb0bSAyushi Smriti { 3415e44e3d8SAppaRao Puli Subscription& entry = *it.second; 3425e44e3d8SAppaRao Puli entry.updateRetryConfig(retryAttempts, retryTimeoutInterval); 343fe44eb0bSAyushi Smriti } 344fe44eb0bSAyushi Smriti } 3457d1cc387SAppaRao Puli } 3467d1cc387SAppaRao Puli 3477d1cc387SAppaRao Puli void updateNoOfSubscribersCount() 3487d1cc387SAppaRao Puli { 3497d1cc387SAppaRao Puli size_t eventLogSubCount = 0; 3507d1cc387SAppaRao Puli size_t metricReportSubCount = 0; 3517d1cc387SAppaRao Puli for (const auto& it : subscriptionsMap) 3527d1cc387SAppaRao Puli { 3537d1cc387SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 3545fe4ef35SMyung Bae if (entry->userSub->eventFormatType == eventFormatType) 3557d1cc387SAppaRao Puli { 3567d1cc387SAppaRao Puli eventLogSubCount++; 3577d1cc387SAppaRao Puli } 3585fe4ef35SMyung Bae else if (entry->userSub->eventFormatType == metricReportFormatType) 3597d1cc387SAppaRao Puli { 3607d1cc387SAppaRao Puli metricReportSubCount++; 3617d1cc387SAppaRao Puli } 3627d1cc387SAppaRao Puli } 3637d1cc387SAppaRao Puli noOfEventLogSubscribers = eventLogSubCount; 3646c58a03eSAlexander Hansen if (eventLogSubCount > 0U) 3657d1cc387SAppaRao Puli { 3666c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 3676c58a03eSAlexander Hansen { 3686c58a03eSAlexander Hansen if (!dbusEventLogMonitor && 3696c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 3706c58a03eSAlexander Hansen { 3716c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 3726c58a03eSAlexander Hansen } 3736c58a03eSAlexander Hansen } 3746c58a03eSAlexander Hansen else 3756c58a03eSAlexander Hansen { 3766c58a03eSAlexander Hansen if (!filesystemLogMonitor) 3776c58a03eSAlexander Hansen { 3786c58a03eSAlexander Hansen filesystemLogMonitor.emplace(ioc); 3796c58a03eSAlexander Hansen } 3806c58a03eSAlexander Hansen } 3816c58a03eSAlexander Hansen } 3826c58a03eSAlexander Hansen else 3836c58a03eSAlexander Hansen { 3846c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3856c58a03eSAlexander Hansen filesystemLogMonitor.reset(); 3866c58a03eSAlexander Hansen } 3876c58a03eSAlexander Hansen 3887d1cc387SAppaRao Puli noOfMetricReportSubscribers = metricReportSubCount; 3896c58a03eSAlexander Hansen if (metricReportSubCount > 0U) 3907d1cc387SAppaRao Puli { 3912ac69850SEd Tanous if (!matchTelemetryMonitor) 3922ac69850SEd Tanous { 3932ac69850SEd Tanous matchTelemetryMonitor.emplace(); 3942ac69850SEd Tanous } 3957d1cc387SAppaRao Puli } 3967d1cc387SAppaRao Puli else 3977d1cc387SAppaRao Puli { 3982ac69850SEd Tanous matchTelemetryMonitor.reset(); 3997d1cc387SAppaRao Puli } 4007d1cc387SAppaRao Puli } 4017d1cc387SAppaRao Puli 402b52664e2SAppaRao Puli std::shared_ptr<Subscription> getSubscription(const std::string& id) 403b52664e2SAppaRao Puli { 404b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 405b52664e2SAppaRao Puli if (obj == subscriptionsMap.end()) 406b52664e2SAppaRao Puli { 40762598e31SEd Tanous BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id); 408b52664e2SAppaRao Puli return nullptr; 409b52664e2SAppaRao Puli } 410b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = obj->second; 411b52664e2SAppaRao Puli return subValue; 412b52664e2SAppaRao Puli } 413b52664e2SAppaRao Puli 414f80a87f2SEd Tanous std::string 415f80a87f2SEd Tanous addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue) 416b52664e2SAppaRao Puli { 417fc76b8acSEd Tanous std::uniform_int_distribution<uint32_t> dist(0); 418fc76b8acSEd Tanous bmcweb::OpenSSLGenerator gen; 419fc76b8acSEd Tanous 420b52664e2SAppaRao Puli std::string id; 421b52664e2SAppaRao Puli 422b52664e2SAppaRao Puli int retry = 3; 423e662eae8SEd Tanous while (retry != 0) 424b52664e2SAppaRao Puli { 425fc76b8acSEd Tanous id = std::to_string(dist(gen)); 426fc76b8acSEd Tanous if (gen.error()) 427fc76b8acSEd Tanous { 428fc76b8acSEd Tanous retry = 0; 429fc76b8acSEd Tanous break; 430fc76b8acSEd Tanous } 431b52664e2SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 432b52664e2SAppaRao Puli if (inserted.second) 433b52664e2SAppaRao Puli { 434b52664e2SAppaRao Puli break; 435b52664e2SAppaRao Puli } 436b52664e2SAppaRao Puli --retry; 43723a21a1cSEd Tanous } 438b52664e2SAppaRao Puli 439b52664e2SAppaRao Puli if (retry <= 0) 440b52664e2SAppaRao Puli { 44162598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to generate random number"); 442abb93cddSEd Tanous return ""; 443b52664e2SAppaRao Puli } 444b52664e2SAppaRao Puli 44556ba386dSMyung Bae // Set Subscription ID for back trace 4465fe4ef35SMyung Bae subValue->userSub->id = id; 447a14c9113SEd Tanous 44828afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 4495fe4ef35SMyung Bae .subscriptionsConfigMap.emplace(id, subValue->userSub); 45028afb49cSJunLin Chen 4517d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 4521bf712bcSAyushi Smriti 453fe44eb0bSAyushi Smriti // Update retry configuration. 454fe44eb0bSAyushi Smriti subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 455fe44eb0bSAyushi Smriti 456f80a87f2SEd Tanous return id; 457f80a87f2SEd Tanous } 458f80a87f2SEd Tanous 459f80a87f2SEd Tanous std::string 460f80a87f2SEd Tanous addSSESubscription(const std::shared_ptr<Subscription>& subValue, 461f80a87f2SEd Tanous std::string_view lastEventId) 462f80a87f2SEd Tanous { 463f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 464f80a87f2SEd Tanous 465f80a87f2SEd Tanous if (!lastEventId.empty()) 466f80a87f2SEd Tanous { 467f80a87f2SEd Tanous BMCWEB_LOG_INFO("Attempting to find message for last id {}", 468f80a87f2SEd Tanous lastEventId); 469f80a87f2SEd Tanous boost::circular_buffer<Event>::iterator lastEvent = 470f80a87f2SEd Tanous std::find_if(messages.begin(), messages.end(), 471f80a87f2SEd Tanous [&lastEventId](const Event& event) { 472f80a87f2SEd Tanous return event.id == lastEventId; 473f80a87f2SEd Tanous }); 474f80a87f2SEd Tanous // Can't find a matching ID 475f80a87f2SEd Tanous if (lastEvent == messages.end()) 476f80a87f2SEd Tanous { 477f80a87f2SEd Tanous nlohmann::json msg = messages::eventBufferExceeded(); 478f80a87f2SEd Tanous // If the buffer overloaded, send all messages. 4796d799e14SEd Tanous subValue->sendEventToSubscriber(msg); 480f80a87f2SEd Tanous lastEvent = messages.begin(); 481f80a87f2SEd Tanous } 482f80a87f2SEd Tanous else 483f80a87f2SEd Tanous { 484f80a87f2SEd Tanous // Skip the last event the user already has 485f80a87f2SEd Tanous lastEvent++; 486f80a87f2SEd Tanous } 487f80a87f2SEd Tanous 488f80a87f2SEd Tanous for (boost::circular_buffer<Event>::const_iterator event = 489f80a87f2SEd Tanous lastEvent; 490f80a87f2SEd Tanous lastEvent != messages.end(); lastEvent++) 491f80a87f2SEd Tanous { 4926d799e14SEd Tanous subValue->sendEventToSubscriber(event->message); 493f80a87f2SEd Tanous } 494f80a87f2SEd Tanous } 495f80a87f2SEd Tanous return id; 496f80a87f2SEd Tanous } 497f80a87f2SEd Tanous 498f80a87f2SEd Tanous std::string 499f80a87f2SEd Tanous addPushSubscription(const std::shared_ptr<Subscription>& subValue) 500f80a87f2SEd Tanous { 501f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 502a0969c70SMyung Bae subValue->deleter = [id]() { 503a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 504a0969c70SMyung Bae }; 505f80a87f2SEd Tanous updateSubscriptionData(); 506b52664e2SAppaRao Puli return id; 507b52664e2SAppaRao Puli } 508b52664e2SAppaRao Puli 509b52664e2SAppaRao Puli bool isSubscriptionExist(const std::string& id) 510b52664e2SAppaRao Puli { 511b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 51255f79e6fSEd Tanous return obj != subscriptionsMap.end(); 513b52664e2SAppaRao Puli } 514b52664e2SAppaRao Puli 5154b712a29SEd Tanous bool deleteSubscription(const std::string& id) 516b52664e2SAppaRao Puli { 517b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 5184b712a29SEd Tanous if (obj == subscriptionsMap.end()) 519b52664e2SAppaRao Puli { 5204b712a29SEd Tanous BMCWEB_LOG_WARNING("Could not find subscription with id {}", id); 5214b712a29SEd Tanous return false; 5224b712a29SEd Tanous } 523b52664e2SAppaRao Puli subscriptionsMap.erase(obj); 5244b712a29SEd Tanous auto& event = persistent_data::EventServiceStore::getInstance(); 5254b712a29SEd Tanous auto persistentObj = event.subscriptionsConfigMap.find(id); 5264b712a29SEd Tanous if (persistentObj == event.subscriptionsConfigMap.end()) 5274b712a29SEd Tanous { 5284b712a29SEd Tanous BMCWEB_LOG_ERROR("Subscription wasn't in persistent data"); 5294b712a29SEd Tanous return true; 5304b712a29SEd Tanous } 53128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 5324b712a29SEd Tanous .subscriptionsConfigMap.erase(persistentObj); 5337d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 534b52664e2SAppaRao Puli updateSubscriptionData(); 5354b712a29SEd Tanous 5364b712a29SEd Tanous return true; 537b52664e2SAppaRao Puli } 538b52664e2SAppaRao Puli 5395e44e3d8SAppaRao Puli void deleteSseSubscription(const crow::sse_socket::Connection& thisConn) 5405e44e3d8SAppaRao Puli { 541bdbfae2aSEd Tanous for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();) 5425e44e3d8SAppaRao Puli { 543bdbfae2aSEd Tanous std::shared_ptr<Subscription> entry = it->second; 5445e44e3d8SAppaRao Puli bool entryIsThisConn = entry->matchSseId(thisConn); 5455e44e3d8SAppaRao Puli if (entryIsThisConn) 5465e44e3d8SAppaRao Puli { 5475e44e3d8SAppaRao Puli persistent_data::EventServiceStore::getInstance() 5485fe4ef35SMyung Bae .subscriptionsConfigMap.erase(entry->userSub->id); 549bdbfae2aSEd Tanous it = subscriptionsMap.erase(it); 5505e44e3d8SAppaRao Puli return; 5515e44e3d8SAppaRao Puli } 552bdbfae2aSEd Tanous it++; 5535e44e3d8SAppaRao Puli } 5545e44e3d8SAppaRao Puli } 5555e44e3d8SAppaRao Puli 5565e44e3d8SAppaRao Puli size_t getNumberOfSubscriptions() const 557b52664e2SAppaRao Puli { 558b52664e2SAppaRao Puli return subscriptionsMap.size(); 559b52664e2SAppaRao Puli } 560b52664e2SAppaRao Puli 5615e44e3d8SAppaRao Puli size_t getNumberOfSSESubscriptions() const 5625e44e3d8SAppaRao Puli { 5633544d2a7SEd Tanous auto size = std::ranges::count_if( 5643544d2a7SEd Tanous subscriptionsMap, 5655e44e3d8SAppaRao Puli [](const std::pair<std::string, std::shared_ptr<Subscription>>& 5665e44e3d8SAppaRao Puli entry) { 5675fe4ef35SMyung Bae return (entry.second->userSub->subscriptionType == 5684b712a29SEd Tanous subscriptionTypeSSE); 5695e44e3d8SAppaRao Puli }); 5705e44e3d8SAppaRao Puli return static_cast<size_t>(size); 5715e44e3d8SAppaRao Puli } 5725e44e3d8SAppaRao Puli 573b52664e2SAppaRao Puli std::vector<std::string> getAllIDs() 574b52664e2SAppaRao Puli { 575b52664e2SAppaRao Puli std::vector<std::string> idList; 576b52664e2SAppaRao Puli for (const auto& it : subscriptionsMap) 577b52664e2SAppaRao Puli { 578b52664e2SAppaRao Puli idList.emplace_back(it.first); 579b52664e2SAppaRao Puli } 580b52664e2SAppaRao Puli return idList; 581b52664e2SAppaRao Puli } 582b52664e2SAppaRao Puli 58381ee0e74SChandramohan Harkude bool sendTestEventLog(TestEvent& testEvent) 5840b4bdd93SAppaRao Puli { 5855e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 5860b4bdd93SAppaRao Puli { 5870b4bdd93SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 58881ee0e74SChandramohan Harkude if (!entry->sendTestEventLog(testEvent)) 5896ba8c82eSsunharis_in { 5906ba8c82eSsunharis_in return false; 5910b4bdd93SAppaRao Puli } 5920b4bdd93SAppaRao Puli } 5936ba8c82eSsunharis_in return true; 5946ba8c82eSsunharis_in } 595e9a14131SAppaRao Puli 5963433b03aSEd Tanous static void 5973433b03aSEd Tanous sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords) 5983433b03aSEd Tanous { 5993433b03aSEd Tanous for (const auto& it : 6003433b03aSEd Tanous EventServiceManager::getInstance().subscriptionsMap) 6013433b03aSEd Tanous { 6023433b03aSEd Tanous Subscription& entry = *it.second; 6033433b03aSEd Tanous entry.filterAndSendEventLogs(eventRecords); 6043433b03aSEd Tanous } 6053433b03aSEd Tanous } 6063433b03aSEd Tanous 607b26ff34dSEd Tanous static void sendTelemetryReportToSubs( 608b26ff34dSEd Tanous const std::string& reportId, const telemetry::TimestampReadings& var) 609b26ff34dSEd Tanous { 610b26ff34dSEd Tanous for (const auto& it : 611b26ff34dSEd Tanous EventServiceManager::getInstance().subscriptionsMap) 612b26ff34dSEd Tanous { 613b26ff34dSEd Tanous Subscription& entry = *it.second; 614b26ff34dSEd Tanous entry.filterAndSendReports(reportId, var); 615b26ff34dSEd Tanous } 616b26ff34dSEd Tanous } 617b26ff34dSEd Tanous 618f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 619f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 62096330b99SSunitha Harish { 621613dabeaSEd Tanous eventMessage["EventId"] = eventId; 622f80a87f2SEd Tanous 623613dabeaSEd Tanous eventMessage["EventTimestamp"] = 624613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 625613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 626613dabeaSEd Tanous 627f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 628788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 62996330b99SSunitha Harish 630f80a87f2SEd Tanous messages.push_back(Event(std::to_string(eventId), eventMessage)); 631f80a87f2SEd Tanous 632f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 63396330b99SSunitha Harish { 634f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 6355fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 6365fe4ef35SMyung Bae resourceType)) 63796330b99SSunitha Harish { 638f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 639f80a87f2SEd Tanous continue; 64096330b99SSunitha Harish } 641f80a87f2SEd Tanous 642f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 643f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 644f80a87f2SEd Tanous 645613dabeaSEd Tanous nlohmann::json msgJson; 646613dabeaSEd Tanous 647613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 648613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 649613dabeaSEd Tanous msgJson["Id"] = eventId; 650f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 651f52c03c1SCarson Labrado 652f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 653f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 6546d799e14SEd Tanous entry->sendEventToSubscriber(std::move(strMsg)); 65596330b99SSunitha Harish } 65621c0ba6eSMyung Bae eventId++; // increment the eventId 65796330b99SSunitha Harish } 65823a21a1cSEd Tanous }; 659b52664e2SAppaRao Puli 660b52664e2SAppaRao Puli } // namespace redfish 661