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 5d7857201SEd Tanous #include "bmcweb_config.h" 6d7857201SEd Tanous 7b26ff34dSEd Tanous #include "dbus_log_watcher.hpp" 83ccb3adbSEd Tanous #include "error_messages.hpp" 9d7857201SEd 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" 139838eb20SEd Tanous #include "io_context_singleton.hpp" 14d7857201SEd Tanous #include "logging.hpp" 15c0353249SWludzik, Jozef #include "metric_report.hpp" 162c6ffdb0SEd Tanous #include "ossl_random.hpp" 173ccb3adbSEd Tanous #include "persistent_data.hpp" 18d7857201SEd Tanous #include "server_sent_event.hpp" 1902c1e29fSAlexander Hansen #include "subscription.hpp" 205b90429aSEd Tanous #include "utils/time_utils.hpp" 217f4eb588SAppaRao Puli 22f80a87f2SEd Tanous #include <boost/circular_buffer.hpp> 23d7857201SEd Tanous #include <boost/circular_buffer/base.hpp> 24b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp> 25d7857201SEd Tanous #include <boost/system/result.hpp> 26d7857201SEd Tanous #include <boost/url/parse.hpp> 274a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp> 281214b7e7SGunnar Mills 295e44e3d8SAppaRao Puli #include <algorithm> 30d7857201SEd Tanous #include <cstdint> 31b52664e2SAppaRao Puli #include <cstdlib> 32b52664e2SAppaRao Puli #include <ctime> 33d7857201SEd Tanous #include <filesystem> 34a14c9113SEd Tanous #include <format> 351bf712bcSAyushi Smriti #include <fstream> 36b52664e2SAppaRao Puli #include <memory> 37d7857201SEd Tanous #include <optional> 38d7857201SEd Tanous #include <random> 39a14c9113SEd Tanous #include <string> 4056ba386dSMyung Bae #include <string_view> 41d7857201SEd Tanous #include <system_error> 425fe4ef35SMyung Bae #include <utility> 43d7857201SEd 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 { 734a19a7b5SEd Tanous uint64_t id; 744a19a7b5SEd Tanous nlohmann::json::object_t message; 75f80a87f2SEd Tanous }; 76f80a87f2SEd Tanous 77f80a87f2SEd Tanous constexpr static size_t maxMessages = 200; 78f80a87f2SEd Tanous boost::circular_buffer<Event> messages{maxMessages}; 79f80a87f2SEd Tanous 80b52664e2SAppaRao Puli public: 819f616dd1SEd Tanous EventServiceManager(const EventServiceManager&) = delete; 829f616dd1SEd Tanous EventServiceManager& operator=(const EventServiceManager&) = delete; 839f616dd1SEd Tanous EventServiceManager(EventServiceManager&&) = delete; 849f616dd1SEd Tanous EventServiceManager& operator=(EventServiceManager&&) = delete; 85ecd6a3a2SEd Tanous ~EventServiceManager() = default; 869f616dd1SEd Tanous 879838eb20SEd Tanous explicit EventServiceManager() 88b52664e2SAppaRao Puli { 89f8ca6d79SEd Tanous // Load config from persist store. 90f8ca6d79SEd Tanous initConfig(); 91f8ca6d79SEd Tanous } 92f8ca6d79SEd Tanous 939838eb20SEd Tanous static EventServiceManager& getInstance() 94f8ca6d79SEd Tanous { 959838eb20SEd Tanous static EventServiceManager handler; 96b52664e2SAppaRao Puli return handler; 97b52664e2SAppaRao Puli } 98b52664e2SAppaRao Puli 991bf712bcSAyushi Smriti void initConfig() 1001bf712bcSAyushi Smriti { 10128afb49cSJunLin Chen loadOldBehavior(); 1021bf712bcSAyushi Smriti 10328afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 10428afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 10528afb49cSJunLin Chen .getEventServiceConfig(); 1061bf712bcSAyushi Smriti 10728afb49cSJunLin Chen serviceEnabled = eventServiceConfig.enabled; 10828afb49cSJunLin Chen retryAttempts = eventServiceConfig.retryAttempts; 10928afb49cSJunLin Chen retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval; 1101bf712bcSAyushi Smriti 11128afb49cSJunLin Chen for (const auto& it : persistent_data::EventServiceStore::getInstance() 11228afb49cSJunLin Chen .subscriptionsConfigMap) 1131bf712bcSAyushi Smriti { 1145fe4ef35SMyung Bae std::shared_ptr<persistent_data::UserSubscription> newSub = 1155fe4ef35SMyung Bae it.second; 1164bbf237fSAppaRao Puli 1176fd29553SEd Tanous boost::system::result<boost::urls::url> url = 1185fe4ef35SMyung Bae boost::urls::parse_absolute_uri(newSub->destinationUrl); 1191bf712bcSAyushi Smriti 120a716aa74SEd Tanous if (!url) 1211bf712bcSAyushi Smriti { 12262598e31SEd Tanous BMCWEB_LOG_ERROR( 12362598e31SEd Tanous "Failed to validate and split destination url"); 1241bf712bcSAyushi Smriti continue; 1251bf712bcSAyushi Smriti } 1261bf712bcSAyushi Smriti std::shared_ptr<Subscription> subValue = 1279838eb20SEd Tanous std::make_shared<Subscription>(newSub, *url, getIoContext()); 1285fe4ef35SMyung Bae std::string id = subValue->userSub->id; 129a0969c70SMyung Bae subValue->deleter = [id]() { 130a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 131a0969c70SMyung Bae }; 1321bf712bcSAyushi Smriti 133a0969c70SMyung Bae subscriptionsMap.emplace(id, subValue); 13428afb49cSJunLin Chen 13528afb49cSJunLin Chen updateNoOfSubscribersCount(); 13628afb49cSJunLin Chen 13728afb49cSJunLin Chen // Update retry configuration. 13828afb49cSJunLin Chen subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 139fb546105SMyung Bae 140fb546105SMyung Bae // schedule a heartbeat if sendHeartbeat was set to true 141fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 142fb546105SMyung Bae { 143fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 144fb546105SMyung Bae } 1451bf712bcSAyushi Smriti } 1461bf712bcSAyushi Smriti } 1471bf712bcSAyushi Smriti 14856d2396dSEd Tanous static void loadOldBehavior() 149b52664e2SAppaRao Puli { 15028afb49cSJunLin Chen std::ifstream eventConfigFile(eventServiceFile); 15128afb49cSJunLin Chen if (!eventConfigFile.good()) 1521bf712bcSAyushi Smriti { 15362598e31SEd Tanous BMCWEB_LOG_DEBUG("Old eventService config not exist"); 15428afb49cSJunLin Chen return; 15528afb49cSJunLin Chen } 15628afb49cSJunLin Chen auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false); 15728afb49cSJunLin Chen if (jsonData.is_discarded()) 1584bbf237fSAppaRao Puli { 15962598e31SEd Tanous BMCWEB_LOG_ERROR("Old eventService config parse error."); 16028afb49cSJunLin Chen return; 16128afb49cSJunLin Chen } 16228afb49cSJunLin Chen 1630bdda665SEd Tanous const nlohmann::json::object_t* obj = 1640bdda665SEd Tanous jsonData.get_ptr<const nlohmann::json::object_t*>(); 1651c588de9SAbiola Asojo if (obj == nullptr) 1661c588de9SAbiola Asojo { 1671c588de9SAbiola Asojo return; 1681c588de9SAbiola Asojo } 1690bdda665SEd Tanous for (const auto& item : *obj) 17028afb49cSJunLin Chen { 1710bdda665SEd Tanous if (item.first == "Configuration") 17228afb49cSJunLin Chen { 17328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 17428afb49cSJunLin Chen .getEventServiceConfig() 1750bdda665SEd Tanous .fromJson(item.second); 17628afb49cSJunLin Chen } 1770bdda665SEd Tanous else if (item.first == "Subscriptions") 17828afb49cSJunLin Chen { 1790bdda665SEd Tanous for (const auto& elem : item.second) 18028afb49cSJunLin Chen { 1814b712a29SEd Tanous std::optional<persistent_data::UserSubscription> 18228afb49cSJunLin Chen newSubscription = 18328afb49cSJunLin Chen persistent_data::UserSubscription::fromJson(elem, 18428afb49cSJunLin Chen true); 1854b712a29SEd Tanous if (!newSubscription) 18628afb49cSJunLin Chen { 18762598e31SEd Tanous BMCWEB_LOG_ERROR("Problem reading subscription " 18862598e31SEd Tanous "from old persistent store"); 1894bbf237fSAppaRao Puli continue; 1904bbf237fSAppaRao Puli } 1914b712a29SEd Tanous persistent_data::UserSubscription& newSub = 1924b712a29SEd Tanous *newSubscription; 1931bf712bcSAyushi Smriti 19428afb49cSJunLin Chen std::uniform_int_distribution<uint32_t> dist(0); 19528afb49cSJunLin Chen bmcweb::OpenSSLGenerator gen; 1961bf712bcSAyushi Smriti 19728afb49cSJunLin Chen std::string id; 1981bf712bcSAyushi Smriti 19928afb49cSJunLin Chen int retry = 3; 200e662eae8SEd Tanous while (retry != 0) 2011bf712bcSAyushi Smriti { 20228afb49cSJunLin Chen id = std::to_string(dist(gen)); 20328afb49cSJunLin Chen if (gen.error()) 2047d1cc387SAppaRao Puli { 20528afb49cSJunLin Chen retry = 0; 20628afb49cSJunLin Chen break; 20728afb49cSJunLin Chen } 2084b712a29SEd Tanous newSub.id = id; 20928afb49cSJunLin Chen auto inserted = 21028afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 2115fe4ef35SMyung Bae .subscriptionsConfigMap.insert(std::pair( 2125fe4ef35SMyung Bae id, std::make_shared< 2135fe4ef35SMyung Bae persistent_data::UserSubscription>( 2145fe4ef35SMyung Bae newSub))); 21528afb49cSJunLin Chen if (inserted.second) 21628afb49cSJunLin Chen { 21728afb49cSJunLin Chen break; 21828afb49cSJunLin Chen } 21928afb49cSJunLin Chen --retry; 2207d1cc387SAppaRao Puli } 2217d1cc387SAppaRao Puli 22228afb49cSJunLin Chen if (retry <= 0) 22328afb49cSJunLin Chen { 22462598e31SEd Tanous BMCWEB_LOG_ERROR( 22562598e31SEd Tanous "Failed to generate random number from old " 22662598e31SEd Tanous "persistent store"); 22728afb49cSJunLin Chen continue; 22828afb49cSJunLin Chen } 22928afb49cSJunLin Chen } 23028afb49cSJunLin Chen } 23128afb49cSJunLin Chen 23228afb49cSJunLin Chen persistent_data::getConfig().writeData(); 2334c521c3cSEd Tanous std::error_code ec; 2344c521c3cSEd Tanous std::filesystem::remove(eventServiceFile, ec); 2354c521c3cSEd Tanous if (ec) 2364c521c3cSEd Tanous { 2374c521c3cSEd Tanous BMCWEB_LOG_DEBUG( 2384c521c3cSEd Tanous "Failed to remove old event service file. Ignoring"); 2394c521c3cSEd Tanous } 2404c521c3cSEd Tanous else 2414c521c3cSEd Tanous { 24262598e31SEd Tanous BMCWEB_LOG_DEBUG("Remove old eventservice config"); 24328afb49cSJunLin Chen } 24428afb49cSJunLin Chen } 2454c521c3cSEd Tanous } 24628afb49cSJunLin Chen 2479eb808c1SEd Tanous void updateSubscriptionData() const 24828afb49cSJunLin Chen { 24928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25028afb49cSJunLin Chen .eventServiceConfig.enabled = serviceEnabled; 25128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25228afb49cSJunLin Chen .eventServiceConfig.retryAttempts = retryAttempts; 25328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 25428afb49cSJunLin Chen .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval; 25528afb49cSJunLin Chen 25628afb49cSJunLin Chen persistent_data::getConfig().writeData(); 25728afb49cSJunLin Chen } 25828afb49cSJunLin Chen 25928afb49cSJunLin Chen void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg) 2607d1cc387SAppaRao Puli { 2617d1cc387SAppaRao Puli bool updateConfig = false; 262fe44eb0bSAyushi Smriti bool updateRetryCfg = false; 2637d1cc387SAppaRao Puli 2642ac69850SEd Tanous if (serviceEnabled) 2657d1cc387SAppaRao Puli { 2667b669723SEd Tanous if (noOfEventLogSubscribers > 0U) 2677b669723SEd Tanous { 2686c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 2696c58a03eSAlexander Hansen { 2706c58a03eSAlexander Hansen if (!dbusEventLogMonitor) 2716c58a03eSAlexander Hansen { 2726c58a03eSAlexander Hansen if constexpr ( 2736c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 2746c58a03eSAlexander Hansen { 2756c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 2766c58a03eSAlexander Hansen } 2776c58a03eSAlexander Hansen } 2786c58a03eSAlexander Hansen } 2796c58a03eSAlexander Hansen else 2807b669723SEd Tanous { 2817b669723SEd Tanous if (!filesystemLogMonitor) 2827b669723SEd Tanous { 2839838eb20SEd Tanous filesystemLogMonitor.emplace(getIoContext()); 2847b669723SEd Tanous } 2857b669723SEd Tanous } 2867b669723SEd Tanous } 2877b669723SEd Tanous else 2887b669723SEd Tanous { 2896c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 2907b669723SEd Tanous filesystemLogMonitor.reset(); 2917b669723SEd Tanous } 2927b669723SEd Tanous 2932ac69850SEd Tanous if (noOfMetricReportSubscribers > 0U) 2947d1cc387SAppaRao Puli { 2952ac69850SEd Tanous if (!matchTelemetryMonitor) 2962ac69850SEd Tanous { 2972ac69850SEd Tanous matchTelemetryMonitor.emplace(); 2982ac69850SEd Tanous } 2997d1cc387SAppaRao Puli } 3007d1cc387SAppaRao Puli else 3017d1cc387SAppaRao Puli { 3022ac69850SEd Tanous matchTelemetryMonitor.reset(); 3037d1cc387SAppaRao Puli } 3042ac69850SEd Tanous } 3052ac69850SEd Tanous else 3062ac69850SEd Tanous { 3072ac69850SEd Tanous matchTelemetryMonitor.reset(); 3086c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3097b669723SEd Tanous filesystemLogMonitor.reset(); 3102ac69850SEd Tanous } 3112ac69850SEd Tanous 3122ac69850SEd Tanous if (serviceEnabled != cfg.enabled) 3132ac69850SEd Tanous { 3142ac69850SEd Tanous serviceEnabled = cfg.enabled; 3157d1cc387SAppaRao Puli updateConfig = true; 3167d1cc387SAppaRao Puli } 3177d1cc387SAppaRao Puli 31828afb49cSJunLin Chen if (retryAttempts != cfg.retryAttempts) 3197d1cc387SAppaRao Puli { 32028afb49cSJunLin Chen retryAttempts = cfg.retryAttempts; 3217d1cc387SAppaRao Puli updateConfig = true; 322fe44eb0bSAyushi Smriti updateRetryCfg = true; 3237d1cc387SAppaRao Puli } 3247d1cc387SAppaRao Puli 32528afb49cSJunLin Chen if (retryTimeoutInterval != cfg.retryTimeoutInterval) 3267d1cc387SAppaRao Puli { 32728afb49cSJunLin Chen retryTimeoutInterval = cfg.retryTimeoutInterval; 3287d1cc387SAppaRao Puli updateConfig = true; 329fe44eb0bSAyushi Smriti updateRetryCfg = true; 3307d1cc387SAppaRao Puli } 3317d1cc387SAppaRao Puli 3327d1cc387SAppaRao Puli if (updateConfig) 3337d1cc387SAppaRao Puli { 3347d1cc387SAppaRao Puli updateSubscriptionData(); 3357d1cc387SAppaRao Puli } 336fe44eb0bSAyushi Smriti 337fe44eb0bSAyushi Smriti if (updateRetryCfg) 338fe44eb0bSAyushi Smriti { 339fe44eb0bSAyushi Smriti // Update the changed retry config to all subscriptions 340fe44eb0bSAyushi Smriti for (const auto& it : 341fe44eb0bSAyushi Smriti EventServiceManager::getInstance().subscriptionsMap) 342fe44eb0bSAyushi Smriti { 3435e44e3d8SAppaRao Puli Subscription& entry = *it.second; 3445e44e3d8SAppaRao Puli entry.updateRetryConfig(retryAttempts, retryTimeoutInterval); 345fe44eb0bSAyushi Smriti } 346fe44eb0bSAyushi Smriti } 3477d1cc387SAppaRao Puli } 3487d1cc387SAppaRao Puli 3497d1cc387SAppaRao Puli void updateNoOfSubscribersCount() 3507d1cc387SAppaRao Puli { 3517d1cc387SAppaRao Puli size_t eventLogSubCount = 0; 3527d1cc387SAppaRao Puli size_t metricReportSubCount = 0; 3537d1cc387SAppaRao Puli for (const auto& it : subscriptionsMap) 3547d1cc387SAppaRao Puli { 3557d1cc387SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 3565fe4ef35SMyung Bae if (entry->userSub->eventFormatType == eventFormatType) 3577d1cc387SAppaRao Puli { 3587d1cc387SAppaRao Puli eventLogSubCount++; 3597d1cc387SAppaRao Puli } 3605fe4ef35SMyung Bae else if (entry->userSub->eventFormatType == metricReportFormatType) 3617d1cc387SAppaRao Puli { 3627d1cc387SAppaRao Puli metricReportSubCount++; 3637d1cc387SAppaRao Puli } 3647d1cc387SAppaRao Puli } 3657d1cc387SAppaRao Puli noOfEventLogSubscribers = eventLogSubCount; 3666c58a03eSAlexander Hansen if (eventLogSubCount > 0U) 3677d1cc387SAppaRao Puli { 3686c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 3696c58a03eSAlexander Hansen { 3706c58a03eSAlexander Hansen if (!dbusEventLogMonitor && 3716c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 3726c58a03eSAlexander Hansen { 3736c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 3746c58a03eSAlexander Hansen } 3756c58a03eSAlexander Hansen } 3766c58a03eSAlexander Hansen else 3776c58a03eSAlexander Hansen { 3786c58a03eSAlexander Hansen if (!filesystemLogMonitor) 3796c58a03eSAlexander Hansen { 3809838eb20SEd Tanous filesystemLogMonitor.emplace(getIoContext()); 3816c58a03eSAlexander Hansen } 3826c58a03eSAlexander Hansen } 3836c58a03eSAlexander Hansen } 3846c58a03eSAlexander Hansen else 3856c58a03eSAlexander Hansen { 3866c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3876c58a03eSAlexander Hansen filesystemLogMonitor.reset(); 3886c58a03eSAlexander Hansen } 3896c58a03eSAlexander Hansen 3907d1cc387SAppaRao Puli noOfMetricReportSubscribers = metricReportSubCount; 3916c58a03eSAlexander Hansen if (metricReportSubCount > 0U) 3927d1cc387SAppaRao Puli { 3932ac69850SEd Tanous if (!matchTelemetryMonitor) 3942ac69850SEd Tanous { 3952ac69850SEd Tanous matchTelemetryMonitor.emplace(); 3962ac69850SEd Tanous } 3977d1cc387SAppaRao Puli } 3987d1cc387SAppaRao Puli else 3997d1cc387SAppaRao Puli { 4002ac69850SEd Tanous matchTelemetryMonitor.reset(); 4017d1cc387SAppaRao Puli } 4027d1cc387SAppaRao Puli } 4037d1cc387SAppaRao Puli 404b52664e2SAppaRao Puli std::shared_ptr<Subscription> getSubscription(const std::string& id) 405b52664e2SAppaRao Puli { 406b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 407b52664e2SAppaRao Puli if (obj == subscriptionsMap.end()) 408b52664e2SAppaRao Puli { 40962598e31SEd Tanous BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id); 410b52664e2SAppaRao Puli return nullptr; 411b52664e2SAppaRao Puli } 412b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = obj->second; 413b52664e2SAppaRao Puli return subValue; 414b52664e2SAppaRao Puli } 415b52664e2SAppaRao Puli 416504af5a0SPatrick Williams std::string addSubscriptionInternal( 417504af5a0SPatrick Williams const std::shared_ptr<Subscription>& subValue) 418b52664e2SAppaRao Puli { 419fc76b8acSEd Tanous std::uniform_int_distribution<uint32_t> dist(0); 420fc76b8acSEd Tanous bmcweb::OpenSSLGenerator gen; 421fc76b8acSEd Tanous 422b52664e2SAppaRao Puli std::string id; 423b52664e2SAppaRao Puli 424b52664e2SAppaRao Puli int retry = 3; 425e662eae8SEd Tanous while (retry != 0) 426b52664e2SAppaRao Puli { 427fc76b8acSEd Tanous id = std::to_string(dist(gen)); 428fc76b8acSEd Tanous if (gen.error()) 429fc76b8acSEd Tanous { 430fc76b8acSEd Tanous retry = 0; 431fc76b8acSEd Tanous break; 432fc76b8acSEd Tanous } 433b52664e2SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 434b52664e2SAppaRao Puli if (inserted.second) 435b52664e2SAppaRao Puli { 436b52664e2SAppaRao Puli break; 437b52664e2SAppaRao Puli } 438b52664e2SAppaRao Puli --retry; 43923a21a1cSEd Tanous } 440b52664e2SAppaRao Puli 441b52664e2SAppaRao Puli if (retry <= 0) 442b52664e2SAppaRao Puli { 44362598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to generate random number"); 444abb93cddSEd Tanous return ""; 445b52664e2SAppaRao Puli } 446b52664e2SAppaRao Puli 44756ba386dSMyung Bae // Set Subscription ID for back trace 4485fe4ef35SMyung Bae subValue->userSub->id = id; 449a14c9113SEd Tanous 45028afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 4515fe4ef35SMyung Bae .subscriptionsConfigMap.emplace(id, subValue->userSub); 45228afb49cSJunLin Chen 4537d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 4541bf712bcSAyushi Smriti 455fe44eb0bSAyushi Smriti // Update retry configuration. 456fe44eb0bSAyushi Smriti subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 457fe44eb0bSAyushi Smriti 458f80a87f2SEd Tanous return id; 459f80a87f2SEd Tanous } 460f80a87f2SEd Tanous 461504af5a0SPatrick Williams std::string addSSESubscription( 462504af5a0SPatrick Williams const std::shared_ptr<Subscription>& subValue, 463f80a87f2SEd Tanous std::string_view lastEventId) 464f80a87f2SEd Tanous { 465f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 466f80a87f2SEd Tanous 467f80a87f2SEd Tanous if (!lastEventId.empty()) 468f80a87f2SEd Tanous { 469f80a87f2SEd Tanous BMCWEB_LOG_INFO("Attempting to find message for last id {}", 470f80a87f2SEd Tanous lastEventId); 471f80a87f2SEd Tanous boost::circular_buffer<Event>::iterator lastEvent = 4724a19a7b5SEd Tanous std::ranges::find_if( 4734a19a7b5SEd Tanous messages, [&lastEventId](const Event& event) { 4744a19a7b5SEd Tanous return std::to_string(event.id) == lastEventId; 475f80a87f2SEd Tanous }); 476f80a87f2SEd Tanous // Can't find a matching ID 477f80a87f2SEd Tanous if (lastEvent == messages.end()) 478f80a87f2SEd Tanous { 479f80a87f2SEd Tanous nlohmann::json msg = messages::eventBufferExceeded(); 4804a19a7b5SEd Tanous 4814a19a7b5SEd Tanous std::string strMsg = msg.dump( 4824a19a7b5SEd Tanous 2, ' ', true, nlohmann::json::error_handler_t::replace); 4834a19a7b5SEd Tanous eventId++; 4844a19a7b5SEd Tanous subValue->sendEventToSubscriber(eventId, std::move(strMsg)); 485f80a87f2SEd Tanous } 486f80a87f2SEd Tanous else 487f80a87f2SEd Tanous { 488f80a87f2SEd Tanous // Skip the last event the user already has 489f80a87f2SEd Tanous lastEvent++; 490f80a87f2SEd Tanous 491f80a87f2SEd Tanous for (boost::circular_buffer<Event>::const_iterator event = 492f80a87f2SEd Tanous lastEvent; 4934a19a7b5SEd Tanous event != messages.end(); event++) 494f80a87f2SEd Tanous { 4954a19a7b5SEd Tanous std::string strMsg = 4964a19a7b5SEd Tanous nlohmann::json(event->message) 4974a19a7b5SEd Tanous .dump(2, ' ', true, 4984a19a7b5SEd Tanous nlohmann::json::error_handler_t::replace); 4994a19a7b5SEd Tanous 5004a19a7b5SEd Tanous subValue->sendEventToSubscriber(event->id, 5014a19a7b5SEd Tanous std::move(strMsg)); 5024a19a7b5SEd Tanous } 503f80a87f2SEd Tanous } 504f80a87f2SEd Tanous } 505f80a87f2SEd Tanous return id; 506f80a87f2SEd Tanous } 507f80a87f2SEd Tanous 508504af5a0SPatrick Williams std::string addPushSubscription( 509504af5a0SPatrick Williams const std::shared_ptr<Subscription>& subValue) 510f80a87f2SEd Tanous { 511f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 512a0969c70SMyung Bae subValue->deleter = [id]() { 513a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 514a0969c70SMyung Bae }; 515f80a87f2SEd Tanous updateSubscriptionData(); 516b52664e2SAppaRao Puli return id; 517b52664e2SAppaRao Puli } 518b52664e2SAppaRao Puli 519b52664e2SAppaRao Puli bool isSubscriptionExist(const std::string& id) 520b52664e2SAppaRao Puli { 521b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 52255f79e6fSEd Tanous return obj != subscriptionsMap.end(); 523b52664e2SAppaRao Puli } 524b52664e2SAppaRao Puli 5254b712a29SEd Tanous bool deleteSubscription(const std::string& id) 526b52664e2SAppaRao Puli { 527b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 5284b712a29SEd Tanous if (obj == subscriptionsMap.end()) 529b52664e2SAppaRao Puli { 5304b712a29SEd Tanous BMCWEB_LOG_WARNING("Could not find subscription with id {}", id); 5314b712a29SEd Tanous return false; 5324b712a29SEd Tanous } 533b52664e2SAppaRao Puli subscriptionsMap.erase(obj); 5344b712a29SEd Tanous auto& event = persistent_data::EventServiceStore::getInstance(); 5354b712a29SEd Tanous auto persistentObj = event.subscriptionsConfigMap.find(id); 5364b712a29SEd Tanous if (persistentObj == event.subscriptionsConfigMap.end()) 5374b712a29SEd Tanous { 538*6136e852SMyung Bae BMCWEB_LOG_ERROR("Subscription {} wasn't in persistent data", id); 5394b712a29SEd Tanous return true; 5404b712a29SEd Tanous } 54128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 5424b712a29SEd Tanous .subscriptionsConfigMap.erase(persistentObj); 5437d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 544b52664e2SAppaRao Puli updateSubscriptionData(); 5454b712a29SEd Tanous 5464b712a29SEd Tanous return true; 547b52664e2SAppaRao Puli } 548b52664e2SAppaRao Puli 5495e44e3d8SAppaRao Puli void deleteSseSubscription(const crow::sse_socket::Connection& thisConn) 5505e44e3d8SAppaRao Puli { 551bdbfae2aSEd Tanous for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();) 5525e44e3d8SAppaRao Puli { 553bdbfae2aSEd Tanous std::shared_ptr<Subscription> entry = it->second; 5545e44e3d8SAppaRao Puli bool entryIsThisConn = entry->matchSseId(thisConn); 5555e44e3d8SAppaRao Puli if (entryIsThisConn) 5565e44e3d8SAppaRao Puli { 5575e44e3d8SAppaRao Puli persistent_data::EventServiceStore::getInstance() 5585fe4ef35SMyung Bae .subscriptionsConfigMap.erase(entry->userSub->id); 559bdbfae2aSEd Tanous it = subscriptionsMap.erase(it); 5605e44e3d8SAppaRao Puli return; 5615e44e3d8SAppaRao Puli } 562bdbfae2aSEd Tanous it++; 5635e44e3d8SAppaRao Puli } 5645e44e3d8SAppaRao Puli } 5655e44e3d8SAppaRao Puli 5665e44e3d8SAppaRao Puli size_t getNumberOfSubscriptions() const 567b52664e2SAppaRao Puli { 568b52664e2SAppaRao Puli return subscriptionsMap.size(); 569b52664e2SAppaRao Puli } 570b52664e2SAppaRao Puli 5715e44e3d8SAppaRao Puli size_t getNumberOfSSESubscriptions() const 5725e44e3d8SAppaRao Puli { 5733544d2a7SEd Tanous auto size = std::ranges::count_if( 5743544d2a7SEd Tanous subscriptionsMap, 5755e44e3d8SAppaRao Puli [](const std::pair<std::string, std::shared_ptr<Subscription>>& 5765e44e3d8SAppaRao Puli entry) { 5775fe4ef35SMyung Bae return (entry.second->userSub->subscriptionType == 5784b712a29SEd Tanous subscriptionTypeSSE); 5795e44e3d8SAppaRao Puli }); 5805e44e3d8SAppaRao Puli return static_cast<size_t>(size); 5815e44e3d8SAppaRao Puli } 5825e44e3d8SAppaRao Puli 583b52664e2SAppaRao Puli std::vector<std::string> getAllIDs() 584b52664e2SAppaRao Puli { 585b52664e2SAppaRao Puli std::vector<std::string> idList; 586b52664e2SAppaRao Puli for (const auto& it : subscriptionsMap) 587b52664e2SAppaRao Puli { 588b52664e2SAppaRao Puli idList.emplace_back(it.first); 589b52664e2SAppaRao Puli } 590b52664e2SAppaRao Puli return idList; 591b52664e2SAppaRao Puli } 592b52664e2SAppaRao Puli 59381ee0e74SChandramohan Harkude bool sendTestEventLog(TestEvent& testEvent) 5940b4bdd93SAppaRao Puli { 5954a19a7b5SEd Tanous eventId++; 5964a19a7b5SEd Tanous nlohmann::json::array_t logEntryArray; 5974a19a7b5SEd Tanous nlohmann::json& logEntryJson = logEntryArray.emplace_back(); 5984a19a7b5SEd Tanous 5994a19a7b5SEd Tanous if (testEvent.eventGroupId) 6004a19a7b5SEd Tanous { 6014a19a7b5SEd Tanous logEntryJson["EventGroupId"] = *testEvent.eventGroupId; 6024a19a7b5SEd Tanous } 6034a19a7b5SEd Tanous 6044a19a7b5SEd Tanous if (testEvent.eventTimestamp) 6054a19a7b5SEd Tanous { 6064a19a7b5SEd Tanous logEntryJson["EventTimestamp"] = *testEvent.eventTimestamp; 6074a19a7b5SEd Tanous } 6084a19a7b5SEd Tanous 6094a19a7b5SEd Tanous if (testEvent.originOfCondition) 6104a19a7b5SEd Tanous { 6114a19a7b5SEd Tanous logEntryJson["OriginOfCondition"]["@odata.id"] = 6124a19a7b5SEd Tanous *testEvent.originOfCondition; 6134a19a7b5SEd Tanous } 6144a19a7b5SEd Tanous if (testEvent.severity) 6154a19a7b5SEd Tanous { 6164a19a7b5SEd Tanous logEntryJson["Severity"] = *testEvent.severity; 6174a19a7b5SEd Tanous } 6184a19a7b5SEd Tanous 6194a19a7b5SEd Tanous if (testEvent.message) 6204a19a7b5SEd Tanous { 6214a19a7b5SEd Tanous logEntryJson["Message"] = *testEvent.message; 6224a19a7b5SEd Tanous } 6234a19a7b5SEd Tanous 6244a19a7b5SEd Tanous if (testEvent.resolution) 6254a19a7b5SEd Tanous { 6264a19a7b5SEd Tanous logEntryJson["Resolution"] = *testEvent.resolution; 6274a19a7b5SEd Tanous } 6284a19a7b5SEd Tanous 6294a19a7b5SEd Tanous if (testEvent.messageId) 6304a19a7b5SEd Tanous { 6314a19a7b5SEd Tanous logEntryJson["MessageId"] = *testEvent.messageId; 6324a19a7b5SEd Tanous } 6334a19a7b5SEd Tanous 6344a19a7b5SEd Tanous if (testEvent.messageArgs) 6354a19a7b5SEd Tanous { 6364a19a7b5SEd Tanous logEntryJson["MessageArgs"] = *testEvent.messageArgs; 6374a19a7b5SEd Tanous } 6384a19a7b5SEd Tanous // MemberId is 0 : since we are sending one event record. 6394a19a7b5SEd Tanous logEntryJson["MemberId"] = "0"; 6404a19a7b5SEd Tanous 6414a19a7b5SEd Tanous nlohmann::json msg; 6424a19a7b5SEd Tanous msg["@odata.type"] = "#Event.v1_4_0.Event"; 6434a19a7b5SEd Tanous msg["Id"] = std::to_string(eventId); 6444a19a7b5SEd Tanous msg["Name"] = "Event Log"; 6454a19a7b5SEd Tanous msg["Events"] = logEntryArray; 6464a19a7b5SEd Tanous 6474a19a7b5SEd Tanous std::string strMsg = 6484a19a7b5SEd Tanous msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace); 6494a19a7b5SEd Tanous 6504a19a7b5SEd Tanous messages.push_back(Event(eventId, msg)); 6515e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 6520b4bdd93SAppaRao Puli { 6530b4bdd93SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 6544a19a7b5SEd Tanous if (!entry->sendEventToSubscriber(eventId, std::string(strMsg))) 6556ba8c82eSsunharis_in { 6566ba8c82eSsunharis_in return false; 6570b4bdd93SAppaRao Puli } 6580b4bdd93SAppaRao Puli } 6596ba8c82eSsunharis_in return true; 6606ba8c82eSsunharis_in } 661e9a14131SAppaRao Puli 662504af5a0SPatrick Williams static void sendEventsToSubs( 663504af5a0SPatrick Williams const std::vector<EventLogObjectsType>& eventRecords) 6643433b03aSEd Tanous { 6654a19a7b5SEd Tanous EventServiceManager& mgr = EventServiceManager::getInstance(); 6664a19a7b5SEd Tanous mgr.eventId++; 6674a19a7b5SEd Tanous for (const auto& it : mgr.subscriptionsMap) 6683433b03aSEd Tanous { 6693433b03aSEd Tanous Subscription& entry = *it.second; 6704a19a7b5SEd Tanous entry.filterAndSendEventLogs(mgr.eventId, eventRecords); 6713433b03aSEd Tanous } 6723433b03aSEd Tanous } 6733433b03aSEd Tanous 674b26ff34dSEd Tanous static void sendTelemetryReportToSubs( 675b26ff34dSEd Tanous const std::string& reportId, const telemetry::TimestampReadings& var) 676b26ff34dSEd Tanous { 6774a19a7b5SEd Tanous EventServiceManager& mgr = EventServiceManager::getInstance(); 6784a19a7b5SEd Tanous mgr.eventId++; 6794a19a7b5SEd Tanous 6804a19a7b5SEd Tanous for (const auto& it : mgr.subscriptionsMap) 681b26ff34dSEd Tanous { 682b26ff34dSEd Tanous Subscription& entry = *it.second; 6834a19a7b5SEd Tanous entry.filterAndSendReports(mgr.eventId, reportId, var); 684b26ff34dSEd Tanous } 685b26ff34dSEd Tanous } 686b26ff34dSEd Tanous 687f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 688f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 68996330b99SSunitha Harish { 6904a19a7b5SEd Tanous eventId++; 691613dabeaSEd Tanous eventMessage["EventId"] = eventId; 692f80a87f2SEd Tanous 693613dabeaSEd Tanous eventMessage["EventTimestamp"] = 694613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 6954a19a7b5SEd Tanous 6964a19a7b5SEd Tanous if (!origin.empty()) 6974a19a7b5SEd Tanous { 698613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 6994a19a7b5SEd Tanous } 700613dabeaSEd Tanous 701f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 702788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 70396330b99SSunitha Harish 7044a19a7b5SEd Tanous messages.push_back(Event(eventId, eventMessage)); 705f80a87f2SEd Tanous 706f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 70796330b99SSunitha Harish { 708f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 7095fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 7105fe4ef35SMyung Bae resourceType)) 71196330b99SSunitha Harish { 712f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 713f80a87f2SEd Tanous continue; 71496330b99SSunitha Harish } 715f80a87f2SEd Tanous 716f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 717f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 718f80a87f2SEd Tanous 719613dabeaSEd Tanous nlohmann::json msgJson; 720613dabeaSEd Tanous 721613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 722613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 723613dabeaSEd Tanous msgJson["Id"] = eventId; 724f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 725f52c03c1SCarson Labrado 726f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 727f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 7284a19a7b5SEd Tanous entry->sendEventToSubscriber(eventId, std::move(strMsg)); 72996330b99SSunitha Harish } 73096330b99SSunitha Harish } 73123a21a1cSEd Tanous }; 732b52664e2SAppaRao Puli 733b52664e2SAppaRao Puli } // namespace redfish 734