140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2020 Intel Corporation 4b52664e2SAppaRao Puli #pragma once 5*d7857201SEd Tanous #include "bmcweb_config.h" 6*d7857201SEd Tanous 7b26ff34dSEd Tanous #include "dbus_log_watcher.hpp" 83ccb3adbSEd Tanous #include "error_messages.hpp" 9*d7857201SEd Tanous #include "event_logs_object_type.hpp" 10d3a48a14SEd Tanous #include "event_matches_filter.hpp" 113ccb3adbSEd Tanous #include "event_service_store.hpp" 122185ddeaSEd Tanous #include "filesystem_log_watcher.hpp" 13*d7857201SEd Tanous #include "logging.hpp" 14c0353249SWludzik, Jozef #include "metric_report.hpp" 152c6ffdb0SEd Tanous #include "ossl_random.hpp" 163ccb3adbSEd Tanous #include "persistent_data.hpp" 17*d7857201SEd Tanous #include "server_sent_event.hpp" 1802c1e29fSAlexander Hansen #include "subscription.hpp" 195b90429aSEd Tanous #include "utils/time_utils.hpp" 207f4eb588SAppaRao Puli 21fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp> 22f80a87f2SEd Tanous #include <boost/circular_buffer.hpp> 23*d7857201SEd Tanous #include <boost/circular_buffer/base.hpp> 24b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp> 25*d7857201SEd Tanous #include <boost/system/result.hpp> 26*d7857201SEd Tanous #include <boost/url/parse.hpp> 274a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp> 281214b7e7SGunnar Mills 295e44e3d8SAppaRao Puli #include <algorithm> 30*d7857201SEd Tanous #include <cstdint> 31b52664e2SAppaRao Puli #include <cstdlib> 32b52664e2SAppaRao Puli #include <ctime> 33*d7857201SEd Tanous #include <filesystem> 34a14c9113SEd Tanous #include <format> 351bf712bcSAyushi Smriti #include <fstream> 36b52664e2SAppaRao Puli #include <memory> 37*d7857201SEd Tanous #include <optional> 38*d7857201SEd Tanous #include <random> 39a14c9113SEd Tanous #include <string> 4056ba386dSMyung Bae #include <string_view> 41*d7857201SEd Tanous #include <system_error> 425fe4ef35SMyung Bae #include <utility> 43*d7857201SEd Tanous #include <vector> 44b52664e2SAppaRao Puli 45b52664e2SAppaRao Puli namespace redfish 46b52664e2SAppaRao Puli { 47156d6b00SAppaRao Puli 48156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event"; 49156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport"; 50156d6b00SAppaRao Puli 511bf712bcSAyushi Smriti static constexpr const char* eventServiceFile = 521bf712bcSAyushi Smriti "/var/lib/bmcweb/eventservice_config.json"; 531bf712bcSAyushi Smriti 54b52664e2SAppaRao Puli class EventServiceManager 55b52664e2SAppaRao Puli { 56b52664e2SAppaRao Puli private: 57d3a9e084SEd Tanous bool serviceEnabled = false; 58d3a9e084SEd Tanous uint32_t retryAttempts = 0; 59d3a9e084SEd Tanous uint32_t retryTimeoutInterval = 0; 607d1cc387SAppaRao Puli 619f616dd1SEd Tanous size_t noOfEventLogSubscribers{0}; 629f616dd1SEd Tanous size_t noOfMetricReportSubscribers{0}; 636c58a03eSAlexander Hansen std::optional<DbusEventLogMonitor> dbusEventLogMonitor; 642ac69850SEd Tanous std::optional<DbusTelemetryMonitor> matchTelemetryMonitor; 657b669723SEd Tanous std::optional<FilesystemLogWatcher> filesystemLogMonitor; 66b52664e2SAppaRao Puli boost::container::flat_map<std::string, std::shared_ptr<Subscription>> 67b52664e2SAppaRao Puli subscriptionsMap; 68b52664e2SAppaRao Puli 699f616dd1SEd Tanous uint64_t eventId{1}; 7096330b99SSunitha Harish 71f80a87f2SEd Tanous struct Event 72f80a87f2SEd Tanous { 73f80a87f2SEd Tanous std::string id; 74f80a87f2SEd Tanous nlohmann::json message; 75f80a87f2SEd Tanous }; 76f80a87f2SEd Tanous 77f80a87f2SEd Tanous constexpr static size_t maxMessages = 200; 78f80a87f2SEd Tanous boost::circular_buffer<Event> messages{maxMessages}; 79f80a87f2SEd Tanous 80f8ca6d79SEd Tanous boost::asio::io_context& ioc; 81f8ca6d79SEd Tanous 82b52664e2SAppaRao Puli public: 839f616dd1SEd Tanous EventServiceManager(const EventServiceManager&) = delete; 849f616dd1SEd Tanous EventServiceManager& operator=(const EventServiceManager&) = delete; 859f616dd1SEd Tanous EventServiceManager(EventServiceManager&&) = delete; 869f616dd1SEd Tanous EventServiceManager& operator=(EventServiceManager&&) = delete; 87ecd6a3a2SEd Tanous ~EventServiceManager() = default; 889f616dd1SEd Tanous 89f8ca6d79SEd Tanous explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn) 90b52664e2SAppaRao Puli { 91f8ca6d79SEd Tanous // Load config from persist store. 92f8ca6d79SEd Tanous initConfig(); 93f8ca6d79SEd Tanous } 94f8ca6d79SEd Tanous 95f8ca6d79SEd Tanous static EventServiceManager& 96f8ca6d79SEd Tanous getInstance(boost::asio::io_context* ioc = nullptr) 97f8ca6d79SEd Tanous { 98f8ca6d79SEd Tanous static EventServiceManager handler(*ioc); 99b52664e2SAppaRao Puli return handler; 100b52664e2SAppaRao Puli } 101b52664e2SAppaRao Puli 1021bf712bcSAyushi Smriti void initConfig() 1031bf712bcSAyushi Smriti { 10428afb49cSJunLin Chen loadOldBehavior(); 1051bf712bcSAyushi Smriti 10628afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 10728afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 10828afb49cSJunLin Chen .getEventServiceConfig(); 1091bf712bcSAyushi Smriti 11028afb49cSJunLin Chen serviceEnabled = eventServiceConfig.enabled; 11128afb49cSJunLin Chen retryAttempts = eventServiceConfig.retryAttempts; 11228afb49cSJunLin Chen retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval; 1131bf712bcSAyushi Smriti 11428afb49cSJunLin Chen for (const auto& it : persistent_data::EventServiceStore::getInstance() 11528afb49cSJunLin Chen .subscriptionsConfigMap) 1161bf712bcSAyushi Smriti { 1175fe4ef35SMyung Bae std::shared_ptr<persistent_data::UserSubscription> newSub = 1185fe4ef35SMyung Bae it.second; 1194bbf237fSAppaRao Puli 1206fd29553SEd Tanous boost::system::result<boost::urls::url> url = 1215fe4ef35SMyung Bae boost::urls::parse_absolute_uri(newSub->destinationUrl); 1221bf712bcSAyushi Smriti 123a716aa74SEd Tanous if (!url) 1241bf712bcSAyushi Smriti { 12562598e31SEd Tanous BMCWEB_LOG_ERROR( 12662598e31SEd Tanous "Failed to validate and split destination url"); 1271bf712bcSAyushi Smriti continue; 1281bf712bcSAyushi Smriti } 1291bf712bcSAyushi Smriti std::shared_ptr<Subscription> subValue = 13021a94d5cSMyung Bae std::make_shared<Subscription>(newSub, *url, ioc); 1315fe4ef35SMyung Bae std::string id = subValue->userSub->id; 132a0969c70SMyung Bae subValue->deleter = [id]() { 133a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 134a0969c70SMyung Bae }; 1351bf712bcSAyushi Smriti 136a0969c70SMyung Bae subscriptionsMap.emplace(id, subValue); 13728afb49cSJunLin Chen 13828afb49cSJunLin Chen updateNoOfSubscribersCount(); 13928afb49cSJunLin Chen 14028afb49cSJunLin Chen // Update retry configuration. 14128afb49cSJunLin Chen subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 142fb546105SMyung Bae 143fb546105SMyung Bae // schedule a heartbeat if sendHeartbeat was set to true 144fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 145fb546105SMyung Bae { 146fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 147fb546105SMyung Bae } 1481bf712bcSAyushi Smriti } 1491bf712bcSAyushi Smriti } 1501bf712bcSAyushi Smriti 15156d2396dSEd Tanous static void loadOldBehavior() 152b52664e2SAppaRao Puli { 15328afb49cSJunLin Chen std::ifstream eventConfigFile(eventServiceFile); 15428afb49cSJunLin Chen if (!eventConfigFile.good()) 1551bf712bcSAyushi Smriti { 15662598e31SEd Tanous BMCWEB_LOG_DEBUG("Old eventService config not exist"); 15728afb49cSJunLin Chen return; 15828afb49cSJunLin Chen } 15928afb49cSJunLin Chen auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false); 16028afb49cSJunLin Chen if (jsonData.is_discarded()) 1614bbf237fSAppaRao Puli { 16262598e31SEd Tanous BMCWEB_LOG_ERROR("Old eventService config parse error."); 16328afb49cSJunLin Chen return; 16428afb49cSJunLin Chen } 16528afb49cSJunLin Chen 1660bdda665SEd Tanous const nlohmann::json::object_t* obj = 1670bdda665SEd Tanous jsonData.get_ptr<const nlohmann::json::object_t*>(); 1681c588de9SAbiola Asojo if (obj == nullptr) 1691c588de9SAbiola Asojo { 1701c588de9SAbiola Asojo return; 1711c588de9SAbiola Asojo } 1720bdda665SEd Tanous for (const auto& item : *obj) 17328afb49cSJunLin Chen { 1740bdda665SEd Tanous if (item.first == "Configuration") 17528afb49cSJunLin Chen { 17628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 17728afb49cSJunLin Chen .getEventServiceConfig() 1780bdda665SEd Tanous .fromJson(item.second); 17928afb49cSJunLin Chen } 1800bdda665SEd Tanous else if (item.first == "Subscriptions") 18128afb49cSJunLin Chen { 1820bdda665SEd Tanous for (const auto& elem : item.second) 18328afb49cSJunLin Chen { 1844b712a29SEd Tanous std::optional<persistent_data::UserSubscription> 18528afb49cSJunLin Chen newSubscription = 18628afb49cSJunLin Chen persistent_data::UserSubscription::fromJson(elem, 18728afb49cSJunLin Chen true); 1884b712a29SEd Tanous if (!newSubscription) 18928afb49cSJunLin Chen { 19062598e31SEd Tanous BMCWEB_LOG_ERROR("Problem reading subscription " 19162598e31SEd Tanous "from old persistent store"); 1924bbf237fSAppaRao Puli continue; 1934bbf237fSAppaRao Puli } 1944b712a29SEd Tanous persistent_data::UserSubscription& newSub = 1954b712a29SEd Tanous *newSubscription; 1961bf712bcSAyushi Smriti 19728afb49cSJunLin Chen std::uniform_int_distribution<uint32_t> dist(0); 19828afb49cSJunLin Chen bmcweb::OpenSSLGenerator gen; 1991bf712bcSAyushi Smriti 20028afb49cSJunLin Chen std::string id; 2011bf712bcSAyushi Smriti 20228afb49cSJunLin Chen int retry = 3; 203e662eae8SEd Tanous while (retry != 0) 2041bf712bcSAyushi Smriti { 20528afb49cSJunLin Chen id = std::to_string(dist(gen)); 20628afb49cSJunLin Chen if (gen.error()) 2077d1cc387SAppaRao Puli { 20828afb49cSJunLin Chen retry = 0; 20928afb49cSJunLin Chen break; 21028afb49cSJunLin Chen } 2114b712a29SEd Tanous newSub.id = id; 21228afb49cSJunLin Chen auto inserted = 21328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 2145fe4ef35SMyung Bae .subscriptionsConfigMap.insert(std::pair( 2155fe4ef35SMyung Bae id, std::make_shared< 2165fe4ef35SMyung Bae persistent_data::UserSubscription>( 2175fe4ef35SMyung Bae newSub))); 21828afb49cSJunLin Chen if (inserted.second) 21928afb49cSJunLin Chen { 22028afb49cSJunLin Chen break; 22128afb49cSJunLin Chen } 22228afb49cSJunLin Chen --retry; 2237d1cc387SAppaRao Puli } 2247d1cc387SAppaRao Puli 22528afb49cSJunLin Chen if (retry <= 0) 22628afb49cSJunLin Chen { 22762598e31SEd Tanous BMCWEB_LOG_ERROR( 22862598e31SEd Tanous "Failed to generate random number from old " 22962598e31SEd Tanous "persistent store"); 23028afb49cSJunLin Chen continue; 23128afb49cSJunLin Chen } 23228afb49cSJunLin Chen } 23328afb49cSJunLin Chen } 23428afb49cSJunLin Chen 23528afb49cSJunLin Chen persistent_data::getConfig().writeData(); 2364c521c3cSEd Tanous std::error_code ec; 2374c521c3cSEd Tanous std::filesystem::remove(eventServiceFile, ec); 2384c521c3cSEd Tanous if (ec) 2394c521c3cSEd Tanous { 2404c521c3cSEd Tanous BMCWEB_LOG_DEBUG( 2414c521c3cSEd Tanous "Failed to remove old event service file. Ignoring"); 2424c521c3cSEd Tanous } 2434c521c3cSEd Tanous else 2444c521c3cSEd Tanous { 24562598e31SEd Tanous BMCWEB_LOG_DEBUG("Remove old eventservice config"); 24628afb49cSJunLin Chen } 24728afb49cSJunLin Chen } 2484c521c3cSEd Tanous } 24928afb49cSJunLin Chen 2509eb808c1SEd Tanous void updateSubscriptionData() const 25128afb49cSJunLin Chen { 25228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25328afb49cSJunLin Chen .eventServiceConfig.enabled = serviceEnabled; 25428afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25528afb49cSJunLin Chen .eventServiceConfig.retryAttempts = retryAttempts; 25628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25728afb49cSJunLin Chen .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval; 25828afb49cSJunLin Chen 25928afb49cSJunLin Chen persistent_data::getConfig().writeData(); 26028afb49cSJunLin Chen } 26128afb49cSJunLin Chen 26228afb49cSJunLin Chen void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg) 2637d1cc387SAppaRao Puli { 2647d1cc387SAppaRao Puli bool updateConfig = false; 265fe44eb0bSAyushi Smriti bool updateRetryCfg = false; 2667d1cc387SAppaRao Puli 2672ac69850SEd Tanous if (serviceEnabled) 2687d1cc387SAppaRao Puli { 2697b669723SEd Tanous if (noOfEventLogSubscribers > 0U) 2707b669723SEd Tanous { 2716c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 2726c58a03eSAlexander Hansen { 2736c58a03eSAlexander Hansen if (!dbusEventLogMonitor) 2746c58a03eSAlexander Hansen { 2756c58a03eSAlexander Hansen if constexpr ( 2766c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 2776c58a03eSAlexander Hansen { 2786c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 2796c58a03eSAlexander Hansen } 2806c58a03eSAlexander Hansen } 2816c58a03eSAlexander Hansen } 2826c58a03eSAlexander Hansen else 2837b669723SEd Tanous { 2847b669723SEd Tanous if (!filesystemLogMonitor) 2857b669723SEd Tanous { 2867b669723SEd Tanous filesystemLogMonitor.emplace(ioc); 2877b669723SEd Tanous } 2887b669723SEd Tanous } 2897b669723SEd Tanous } 2907b669723SEd Tanous else 2917b669723SEd Tanous { 2926c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 2937b669723SEd Tanous filesystemLogMonitor.reset(); 2947b669723SEd Tanous } 2957b669723SEd Tanous 2962ac69850SEd Tanous if (noOfMetricReportSubscribers > 0U) 2977d1cc387SAppaRao Puli { 2982ac69850SEd Tanous if (!matchTelemetryMonitor) 2992ac69850SEd Tanous { 3002ac69850SEd Tanous matchTelemetryMonitor.emplace(); 3012ac69850SEd Tanous } 3027d1cc387SAppaRao Puli } 3037d1cc387SAppaRao Puli else 3047d1cc387SAppaRao Puli { 3052ac69850SEd Tanous matchTelemetryMonitor.reset(); 3067d1cc387SAppaRao Puli } 3072ac69850SEd Tanous } 3082ac69850SEd Tanous else 3092ac69850SEd Tanous { 3102ac69850SEd Tanous matchTelemetryMonitor.reset(); 3116c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3127b669723SEd Tanous filesystemLogMonitor.reset(); 3132ac69850SEd Tanous } 3142ac69850SEd Tanous 3152ac69850SEd Tanous if (serviceEnabled != cfg.enabled) 3162ac69850SEd Tanous { 3172ac69850SEd Tanous serviceEnabled = cfg.enabled; 3187d1cc387SAppaRao Puli updateConfig = true; 3197d1cc387SAppaRao Puli } 3207d1cc387SAppaRao Puli 32128afb49cSJunLin Chen if (retryAttempts != cfg.retryAttempts) 3227d1cc387SAppaRao Puli { 32328afb49cSJunLin Chen retryAttempts = cfg.retryAttempts; 3247d1cc387SAppaRao Puli updateConfig = true; 325fe44eb0bSAyushi Smriti updateRetryCfg = true; 3267d1cc387SAppaRao Puli } 3277d1cc387SAppaRao Puli 32828afb49cSJunLin Chen if (retryTimeoutInterval != cfg.retryTimeoutInterval) 3297d1cc387SAppaRao Puli { 33028afb49cSJunLin Chen retryTimeoutInterval = cfg.retryTimeoutInterval; 3317d1cc387SAppaRao Puli updateConfig = true; 332fe44eb0bSAyushi Smriti updateRetryCfg = true; 3337d1cc387SAppaRao Puli } 3347d1cc387SAppaRao Puli 3357d1cc387SAppaRao Puli if (updateConfig) 3367d1cc387SAppaRao Puli { 3377d1cc387SAppaRao Puli updateSubscriptionData(); 3387d1cc387SAppaRao Puli } 339fe44eb0bSAyushi Smriti 340fe44eb0bSAyushi Smriti if (updateRetryCfg) 341fe44eb0bSAyushi Smriti { 342fe44eb0bSAyushi Smriti // Update the changed retry config to all subscriptions 343fe44eb0bSAyushi Smriti for (const auto& it : 344fe44eb0bSAyushi Smriti EventServiceManager::getInstance().subscriptionsMap) 345fe44eb0bSAyushi Smriti { 3465e44e3d8SAppaRao Puli Subscription& entry = *it.second; 3475e44e3d8SAppaRao Puli entry.updateRetryConfig(retryAttempts, retryTimeoutInterval); 348fe44eb0bSAyushi Smriti } 349fe44eb0bSAyushi Smriti } 3507d1cc387SAppaRao Puli } 3517d1cc387SAppaRao Puli 3527d1cc387SAppaRao Puli void updateNoOfSubscribersCount() 3537d1cc387SAppaRao Puli { 3547d1cc387SAppaRao Puli size_t eventLogSubCount = 0; 3557d1cc387SAppaRao Puli size_t metricReportSubCount = 0; 3567d1cc387SAppaRao Puli for (const auto& it : subscriptionsMap) 3577d1cc387SAppaRao Puli { 3587d1cc387SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 3595fe4ef35SMyung Bae if (entry->userSub->eventFormatType == eventFormatType) 3607d1cc387SAppaRao Puli { 3617d1cc387SAppaRao Puli eventLogSubCount++; 3627d1cc387SAppaRao Puli } 3635fe4ef35SMyung Bae else if (entry->userSub->eventFormatType == metricReportFormatType) 3647d1cc387SAppaRao Puli { 3657d1cc387SAppaRao Puli metricReportSubCount++; 3667d1cc387SAppaRao Puli } 3677d1cc387SAppaRao Puli } 3687d1cc387SAppaRao Puli noOfEventLogSubscribers = eventLogSubCount; 3696c58a03eSAlexander Hansen if (eventLogSubCount > 0U) 3707d1cc387SAppaRao Puli { 3716c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 3726c58a03eSAlexander Hansen { 3736c58a03eSAlexander Hansen if (!dbusEventLogMonitor && 3746c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 3756c58a03eSAlexander Hansen { 3766c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 3776c58a03eSAlexander Hansen } 3786c58a03eSAlexander Hansen } 3796c58a03eSAlexander Hansen else 3806c58a03eSAlexander Hansen { 3816c58a03eSAlexander Hansen if (!filesystemLogMonitor) 3826c58a03eSAlexander Hansen { 3836c58a03eSAlexander Hansen filesystemLogMonitor.emplace(ioc); 3846c58a03eSAlexander Hansen } 3856c58a03eSAlexander Hansen } 3866c58a03eSAlexander Hansen } 3876c58a03eSAlexander Hansen else 3886c58a03eSAlexander Hansen { 3896c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3906c58a03eSAlexander Hansen filesystemLogMonitor.reset(); 3916c58a03eSAlexander Hansen } 3926c58a03eSAlexander Hansen 3937d1cc387SAppaRao Puli noOfMetricReportSubscribers = metricReportSubCount; 3946c58a03eSAlexander Hansen if (metricReportSubCount > 0U) 3957d1cc387SAppaRao Puli { 3962ac69850SEd Tanous if (!matchTelemetryMonitor) 3972ac69850SEd Tanous { 3982ac69850SEd Tanous matchTelemetryMonitor.emplace(); 3992ac69850SEd Tanous } 4007d1cc387SAppaRao Puli } 4017d1cc387SAppaRao Puli else 4027d1cc387SAppaRao Puli { 4032ac69850SEd Tanous matchTelemetryMonitor.reset(); 4047d1cc387SAppaRao Puli } 4057d1cc387SAppaRao Puli } 4067d1cc387SAppaRao Puli 407b52664e2SAppaRao Puli std::shared_ptr<Subscription> getSubscription(const std::string& id) 408b52664e2SAppaRao Puli { 409b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 410b52664e2SAppaRao Puli if (obj == subscriptionsMap.end()) 411b52664e2SAppaRao Puli { 41262598e31SEd Tanous BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id); 413b52664e2SAppaRao Puli return nullptr; 414b52664e2SAppaRao Puli } 415b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = obj->second; 416b52664e2SAppaRao Puli return subValue; 417b52664e2SAppaRao Puli } 418b52664e2SAppaRao Puli 419f80a87f2SEd Tanous std::string 420f80a87f2SEd Tanous addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue) 421b52664e2SAppaRao Puli { 422fc76b8acSEd Tanous std::uniform_int_distribution<uint32_t> dist(0); 423fc76b8acSEd Tanous bmcweb::OpenSSLGenerator gen; 424fc76b8acSEd Tanous 425b52664e2SAppaRao Puli std::string id; 426b52664e2SAppaRao Puli 427b52664e2SAppaRao Puli int retry = 3; 428e662eae8SEd Tanous while (retry != 0) 429b52664e2SAppaRao Puli { 430fc76b8acSEd Tanous id = std::to_string(dist(gen)); 431fc76b8acSEd Tanous if (gen.error()) 432fc76b8acSEd Tanous { 433fc76b8acSEd Tanous retry = 0; 434fc76b8acSEd Tanous break; 435fc76b8acSEd Tanous } 436b52664e2SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 437b52664e2SAppaRao Puli if (inserted.second) 438b52664e2SAppaRao Puli { 439b52664e2SAppaRao Puli break; 440b52664e2SAppaRao Puli } 441b52664e2SAppaRao Puli --retry; 44223a21a1cSEd Tanous } 443b52664e2SAppaRao Puli 444b52664e2SAppaRao Puli if (retry <= 0) 445b52664e2SAppaRao Puli { 44662598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to generate random number"); 447abb93cddSEd Tanous return ""; 448b52664e2SAppaRao Puli } 449b52664e2SAppaRao Puli 45056ba386dSMyung Bae // Set Subscription ID for back trace 4515fe4ef35SMyung Bae subValue->userSub->id = id; 452a14c9113SEd Tanous 45328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 4545fe4ef35SMyung Bae .subscriptionsConfigMap.emplace(id, subValue->userSub); 45528afb49cSJunLin Chen 4567d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 4571bf712bcSAyushi Smriti 458fe44eb0bSAyushi Smriti // Update retry configuration. 459fe44eb0bSAyushi Smriti subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 460fe44eb0bSAyushi Smriti 461f80a87f2SEd Tanous return id; 462f80a87f2SEd Tanous } 463f80a87f2SEd Tanous 464f80a87f2SEd Tanous std::string 465f80a87f2SEd Tanous addSSESubscription(const std::shared_ptr<Subscription>& subValue, 466f80a87f2SEd Tanous std::string_view lastEventId) 467f80a87f2SEd Tanous { 468f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 469f80a87f2SEd Tanous 470f80a87f2SEd Tanous if (!lastEventId.empty()) 471f80a87f2SEd Tanous { 472f80a87f2SEd Tanous BMCWEB_LOG_INFO("Attempting to find message for last id {}", 473f80a87f2SEd Tanous lastEventId); 474f80a87f2SEd Tanous boost::circular_buffer<Event>::iterator lastEvent = 475f80a87f2SEd Tanous std::find_if(messages.begin(), messages.end(), 476f80a87f2SEd Tanous [&lastEventId](const Event& event) { 477f80a87f2SEd Tanous return event.id == lastEventId; 478f80a87f2SEd Tanous }); 479f80a87f2SEd Tanous // Can't find a matching ID 480f80a87f2SEd Tanous if (lastEvent == messages.end()) 481f80a87f2SEd Tanous { 482f80a87f2SEd Tanous nlohmann::json msg = messages::eventBufferExceeded(); 483f80a87f2SEd Tanous // If the buffer overloaded, send all messages. 4846d799e14SEd Tanous subValue->sendEventToSubscriber(msg); 485f80a87f2SEd Tanous lastEvent = messages.begin(); 486f80a87f2SEd Tanous } 487f80a87f2SEd Tanous else 488f80a87f2SEd Tanous { 489f80a87f2SEd Tanous // Skip the last event the user already has 490f80a87f2SEd Tanous lastEvent++; 491f80a87f2SEd Tanous } 492f80a87f2SEd Tanous 493f80a87f2SEd Tanous for (boost::circular_buffer<Event>::const_iterator event = 494f80a87f2SEd Tanous lastEvent; 495f80a87f2SEd Tanous lastEvent != messages.end(); lastEvent++) 496f80a87f2SEd Tanous { 4976d799e14SEd Tanous subValue->sendEventToSubscriber(event->message); 498f80a87f2SEd Tanous } 499f80a87f2SEd Tanous } 500f80a87f2SEd Tanous return id; 501f80a87f2SEd Tanous } 502f80a87f2SEd Tanous 503f80a87f2SEd Tanous std::string 504f80a87f2SEd Tanous addPushSubscription(const std::shared_ptr<Subscription>& subValue) 505f80a87f2SEd Tanous { 506f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 507a0969c70SMyung Bae subValue->deleter = [id]() { 508a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 509a0969c70SMyung Bae }; 510f80a87f2SEd Tanous updateSubscriptionData(); 511b52664e2SAppaRao Puli return id; 512b52664e2SAppaRao Puli } 513b52664e2SAppaRao Puli 514b52664e2SAppaRao Puli bool isSubscriptionExist(const std::string& id) 515b52664e2SAppaRao Puli { 516b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 51755f79e6fSEd Tanous return obj != subscriptionsMap.end(); 518b52664e2SAppaRao Puli } 519b52664e2SAppaRao Puli 5204b712a29SEd Tanous bool deleteSubscription(const std::string& id) 521b52664e2SAppaRao Puli { 522b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 5234b712a29SEd Tanous if (obj == subscriptionsMap.end()) 524b52664e2SAppaRao Puli { 5254b712a29SEd Tanous BMCWEB_LOG_WARNING("Could not find subscription with id {}", id); 5264b712a29SEd Tanous return false; 5274b712a29SEd Tanous } 528b52664e2SAppaRao Puli subscriptionsMap.erase(obj); 5294b712a29SEd Tanous auto& event = persistent_data::EventServiceStore::getInstance(); 5304b712a29SEd Tanous auto persistentObj = event.subscriptionsConfigMap.find(id); 5314b712a29SEd Tanous if (persistentObj == event.subscriptionsConfigMap.end()) 5324b712a29SEd Tanous { 5334b712a29SEd Tanous BMCWEB_LOG_ERROR("Subscription wasn't in persistent data"); 5344b712a29SEd Tanous return true; 5354b712a29SEd Tanous } 53628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 5374b712a29SEd Tanous .subscriptionsConfigMap.erase(persistentObj); 5387d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 539b52664e2SAppaRao Puli updateSubscriptionData(); 5404b712a29SEd Tanous 5414b712a29SEd Tanous return true; 542b52664e2SAppaRao Puli } 543b52664e2SAppaRao Puli 5445e44e3d8SAppaRao Puli void deleteSseSubscription(const crow::sse_socket::Connection& thisConn) 5455e44e3d8SAppaRao Puli { 546bdbfae2aSEd Tanous for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();) 5475e44e3d8SAppaRao Puli { 548bdbfae2aSEd Tanous std::shared_ptr<Subscription> entry = it->second; 5495e44e3d8SAppaRao Puli bool entryIsThisConn = entry->matchSseId(thisConn); 5505e44e3d8SAppaRao Puli if (entryIsThisConn) 5515e44e3d8SAppaRao Puli { 5525e44e3d8SAppaRao Puli persistent_data::EventServiceStore::getInstance() 5535fe4ef35SMyung Bae .subscriptionsConfigMap.erase(entry->userSub->id); 554bdbfae2aSEd Tanous it = subscriptionsMap.erase(it); 5555e44e3d8SAppaRao Puli return; 5565e44e3d8SAppaRao Puli } 557bdbfae2aSEd Tanous it++; 5585e44e3d8SAppaRao Puli } 5595e44e3d8SAppaRao Puli } 5605e44e3d8SAppaRao Puli 5615e44e3d8SAppaRao Puli size_t getNumberOfSubscriptions() const 562b52664e2SAppaRao Puli { 563b52664e2SAppaRao Puli return subscriptionsMap.size(); 564b52664e2SAppaRao Puli } 565b52664e2SAppaRao Puli 5665e44e3d8SAppaRao Puli size_t getNumberOfSSESubscriptions() const 5675e44e3d8SAppaRao Puli { 5683544d2a7SEd Tanous auto size = std::ranges::count_if( 5693544d2a7SEd Tanous subscriptionsMap, 5705e44e3d8SAppaRao Puli [](const std::pair<std::string, std::shared_ptr<Subscription>>& 5715e44e3d8SAppaRao Puli entry) { 5725fe4ef35SMyung Bae return (entry.second->userSub->subscriptionType == 5734b712a29SEd Tanous subscriptionTypeSSE); 5745e44e3d8SAppaRao Puli }); 5755e44e3d8SAppaRao Puli return static_cast<size_t>(size); 5765e44e3d8SAppaRao Puli } 5775e44e3d8SAppaRao Puli 578b52664e2SAppaRao Puli std::vector<std::string> getAllIDs() 579b52664e2SAppaRao Puli { 580b52664e2SAppaRao Puli std::vector<std::string> idList; 581b52664e2SAppaRao Puli for (const auto& it : subscriptionsMap) 582b52664e2SAppaRao Puli { 583b52664e2SAppaRao Puli idList.emplace_back(it.first); 584b52664e2SAppaRao Puli } 585b52664e2SAppaRao Puli return idList; 586b52664e2SAppaRao Puli } 587b52664e2SAppaRao Puli 58881ee0e74SChandramohan Harkude bool sendTestEventLog(TestEvent& testEvent) 5890b4bdd93SAppaRao Puli { 5905e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 5910b4bdd93SAppaRao Puli { 5920b4bdd93SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 59381ee0e74SChandramohan Harkude if (!entry->sendTestEventLog(testEvent)) 5946ba8c82eSsunharis_in { 5956ba8c82eSsunharis_in return false; 5960b4bdd93SAppaRao Puli } 5970b4bdd93SAppaRao Puli } 5986ba8c82eSsunharis_in return true; 5996ba8c82eSsunharis_in } 600e9a14131SAppaRao Puli 6013433b03aSEd Tanous static void 6023433b03aSEd Tanous sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords) 6033433b03aSEd Tanous { 6043433b03aSEd Tanous for (const auto& it : 6053433b03aSEd Tanous EventServiceManager::getInstance().subscriptionsMap) 6063433b03aSEd Tanous { 6073433b03aSEd Tanous Subscription& entry = *it.second; 6083433b03aSEd Tanous entry.filterAndSendEventLogs(eventRecords); 6093433b03aSEd Tanous } 6103433b03aSEd Tanous } 6113433b03aSEd Tanous 612b26ff34dSEd Tanous static void sendTelemetryReportToSubs( 613b26ff34dSEd Tanous const std::string& reportId, const telemetry::TimestampReadings& var) 614b26ff34dSEd Tanous { 615b26ff34dSEd Tanous for (const auto& it : 616b26ff34dSEd Tanous EventServiceManager::getInstance().subscriptionsMap) 617b26ff34dSEd Tanous { 618b26ff34dSEd Tanous Subscription& entry = *it.second; 619b26ff34dSEd Tanous entry.filterAndSendReports(reportId, var); 620b26ff34dSEd Tanous } 621b26ff34dSEd Tanous } 622b26ff34dSEd Tanous 623f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 624f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 62596330b99SSunitha Harish { 626613dabeaSEd Tanous eventMessage["EventId"] = eventId; 627f80a87f2SEd Tanous 628613dabeaSEd Tanous eventMessage["EventTimestamp"] = 629613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 630613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 631613dabeaSEd Tanous 632f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 633788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 63496330b99SSunitha Harish 635f80a87f2SEd Tanous messages.push_back(Event(std::to_string(eventId), eventMessage)); 636f80a87f2SEd Tanous 637f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 63896330b99SSunitha Harish { 639f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 6405fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 6415fe4ef35SMyung Bae resourceType)) 64296330b99SSunitha Harish { 643f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 644f80a87f2SEd Tanous continue; 64596330b99SSunitha Harish } 646f80a87f2SEd Tanous 647f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 648f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 649f80a87f2SEd Tanous 650613dabeaSEd Tanous nlohmann::json msgJson; 651613dabeaSEd Tanous 652613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 653613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 654613dabeaSEd Tanous msgJson["Id"] = eventId; 655f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 656f52c03c1SCarson Labrado 657f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 658f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 6596d799e14SEd Tanous entry->sendEventToSubscriber(std::move(strMsg)); 66096330b99SSunitha Harish } 66121c0ba6eSMyung Bae eventId++; // increment the eventId 66296330b99SSunitha Harish } 66323a21a1cSEd Tanous }; 664b52664e2SAppaRao Puli 665b52664e2SAppaRao Puli } // namespace redfish 666