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 51b52664e2SAppaRao Puli class EventServiceManager 52b52664e2SAppaRao Puli { 53b52664e2SAppaRao Puli private: 54d3a9e084SEd Tanous bool serviceEnabled = false; 55d3a9e084SEd Tanous uint32_t retryAttempts = 0; 56d3a9e084SEd Tanous uint32_t retryTimeoutInterval = 0; 577d1cc387SAppaRao Puli 589f616dd1SEd Tanous size_t noOfEventLogSubscribers{0}; 599f616dd1SEd Tanous size_t noOfMetricReportSubscribers{0}; 606c58a03eSAlexander Hansen std::optional<DbusEventLogMonitor> dbusEventLogMonitor; 612ac69850SEd Tanous std::optional<DbusTelemetryMonitor> matchTelemetryMonitor; 627b669723SEd Tanous std::optional<FilesystemLogWatcher> filesystemLogMonitor; 63b52664e2SAppaRao Puli boost::container::flat_map<std::string, std::shared_ptr<Subscription>> 64b52664e2SAppaRao Puli subscriptionsMap; 65b52664e2SAppaRao Puli 669f616dd1SEd Tanous uint64_t eventId{1}; 6796330b99SSunitha Harish 68f80a87f2SEd Tanous struct Event 69f80a87f2SEd Tanous { 704a19a7b5SEd Tanous uint64_t id; 714a19a7b5SEd Tanous nlohmann::json::object_t message; 72f80a87f2SEd Tanous }; 73f80a87f2SEd Tanous 74f80a87f2SEd Tanous constexpr static size_t maxMessages = 200; 75f80a87f2SEd Tanous boost::circular_buffer<Event> messages{maxMessages}; 76f80a87f2SEd 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 849838eb20SEd Tanous explicit EventServiceManager() 85b52664e2SAppaRao Puli { 86f8ca6d79SEd Tanous // Load config from persist store. 87f8ca6d79SEd Tanous initConfig(); 88f8ca6d79SEd Tanous } 89f8ca6d79SEd Tanous 909838eb20SEd Tanous static EventServiceManager& getInstance() 91f8ca6d79SEd Tanous { 929838eb20SEd Tanous static EventServiceManager handler; 93b52664e2SAppaRao Puli return handler; 94b52664e2SAppaRao Puli } 95b52664e2SAppaRao Puli 961bf712bcSAyushi Smriti void initConfig() 971bf712bcSAyushi Smriti { 9828afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 9928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 10028afb49cSJunLin Chen .getEventServiceConfig(); 1011bf712bcSAyushi Smriti 10228afb49cSJunLin Chen serviceEnabled = eventServiceConfig.enabled; 10328afb49cSJunLin Chen retryAttempts = eventServiceConfig.retryAttempts; 10428afb49cSJunLin Chen retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval; 1051bf712bcSAyushi Smriti 10628afb49cSJunLin Chen for (const auto& it : persistent_data::EventServiceStore::getInstance() 10728afb49cSJunLin Chen .subscriptionsConfigMap) 1081bf712bcSAyushi Smriti { 1095fe4ef35SMyung Bae std::shared_ptr<persistent_data::UserSubscription> newSub = 1105fe4ef35SMyung Bae it.second; 1114bbf237fSAppaRao Puli 1126fd29553SEd Tanous boost::system::result<boost::urls::url> url = 1135fe4ef35SMyung Bae boost::urls::parse_absolute_uri(newSub->destinationUrl); 1141bf712bcSAyushi Smriti 115a716aa74SEd Tanous if (!url) 1161bf712bcSAyushi Smriti { 11762598e31SEd Tanous BMCWEB_LOG_ERROR( 11862598e31SEd Tanous "Failed to validate and split destination url"); 1191bf712bcSAyushi Smriti continue; 1201bf712bcSAyushi Smriti } 1211bf712bcSAyushi Smriti std::shared_ptr<Subscription> subValue = 1229838eb20SEd Tanous std::make_shared<Subscription>(newSub, *url, getIoContext()); 1235fe4ef35SMyung Bae std::string id = subValue->userSub->id; 124a0969c70SMyung Bae subValue->deleter = [id]() { 125a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 126a0969c70SMyung Bae }; 1271bf712bcSAyushi Smriti 128a0969c70SMyung Bae subscriptionsMap.emplace(id, subValue); 12928afb49cSJunLin Chen 13028afb49cSJunLin Chen updateNoOfSubscribersCount(); 13128afb49cSJunLin Chen 13228afb49cSJunLin Chen // Update retry configuration. 13328afb49cSJunLin Chen subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 134fb546105SMyung Bae 135fb546105SMyung Bae // schedule a heartbeat if sendHeartbeat was set to true 136fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 137fb546105SMyung Bae { 138fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 139fb546105SMyung Bae } 1401bf712bcSAyushi Smriti } 1411bf712bcSAyushi Smriti } 1421bf712bcSAyushi Smriti 1439eb808c1SEd Tanous void updateSubscriptionData() const 14428afb49cSJunLin Chen { 14528afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 14628afb49cSJunLin Chen .eventServiceConfig.enabled = serviceEnabled; 14728afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 14828afb49cSJunLin Chen .eventServiceConfig.retryAttempts = retryAttempts; 14928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 15028afb49cSJunLin Chen .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval; 15128afb49cSJunLin Chen 15228afb49cSJunLin Chen persistent_data::getConfig().writeData(); 15328afb49cSJunLin Chen } 15428afb49cSJunLin Chen 15528afb49cSJunLin Chen void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg) 1567d1cc387SAppaRao Puli { 1577d1cc387SAppaRao Puli bool updateConfig = false; 158fe44eb0bSAyushi Smriti bool updateRetryCfg = false; 1597d1cc387SAppaRao Puli 1602ac69850SEd Tanous if (serviceEnabled) 1617d1cc387SAppaRao Puli { 1627b669723SEd Tanous if (noOfEventLogSubscribers > 0U) 1637b669723SEd Tanous { 1646c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 1656c58a03eSAlexander Hansen { 1666c58a03eSAlexander Hansen if (!dbusEventLogMonitor) 1676c58a03eSAlexander Hansen { 1686c58a03eSAlexander Hansen if constexpr ( 1696c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 1706c58a03eSAlexander Hansen { 1716c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 1726c58a03eSAlexander Hansen } 1736c58a03eSAlexander Hansen } 1746c58a03eSAlexander Hansen } 1756c58a03eSAlexander Hansen else 1767b669723SEd Tanous { 1777b669723SEd Tanous if (!filesystemLogMonitor) 1787b669723SEd Tanous { 1799838eb20SEd Tanous filesystemLogMonitor.emplace(getIoContext()); 1807b669723SEd Tanous } 1817b669723SEd Tanous } 1827b669723SEd Tanous } 1837b669723SEd Tanous else 1847b669723SEd Tanous { 1856c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 1867b669723SEd Tanous filesystemLogMonitor.reset(); 1877b669723SEd Tanous } 1887b669723SEd Tanous 1892ac69850SEd Tanous if (noOfMetricReportSubscribers > 0U) 1907d1cc387SAppaRao Puli { 1912ac69850SEd Tanous if (!matchTelemetryMonitor) 1922ac69850SEd Tanous { 1932ac69850SEd Tanous matchTelemetryMonitor.emplace(); 1942ac69850SEd Tanous } 1957d1cc387SAppaRao Puli } 1967d1cc387SAppaRao Puli else 1977d1cc387SAppaRao Puli { 1982ac69850SEd Tanous matchTelemetryMonitor.reset(); 1997d1cc387SAppaRao Puli } 2002ac69850SEd Tanous } 2012ac69850SEd Tanous else 2022ac69850SEd Tanous { 2032ac69850SEd Tanous matchTelemetryMonitor.reset(); 2046c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 2057b669723SEd Tanous filesystemLogMonitor.reset(); 2062ac69850SEd Tanous } 2072ac69850SEd Tanous 2082ac69850SEd Tanous if (serviceEnabled != cfg.enabled) 2092ac69850SEd Tanous { 2102ac69850SEd Tanous serviceEnabled = cfg.enabled; 2117d1cc387SAppaRao Puli updateConfig = true; 2127d1cc387SAppaRao Puli } 2137d1cc387SAppaRao Puli 21428afb49cSJunLin Chen if (retryAttempts != cfg.retryAttempts) 2157d1cc387SAppaRao Puli { 21628afb49cSJunLin Chen retryAttempts = cfg.retryAttempts; 2177d1cc387SAppaRao Puli updateConfig = true; 218fe44eb0bSAyushi Smriti updateRetryCfg = true; 2197d1cc387SAppaRao Puli } 2207d1cc387SAppaRao Puli 22128afb49cSJunLin Chen if (retryTimeoutInterval != cfg.retryTimeoutInterval) 2227d1cc387SAppaRao Puli { 22328afb49cSJunLin Chen retryTimeoutInterval = cfg.retryTimeoutInterval; 2247d1cc387SAppaRao Puli updateConfig = true; 225fe44eb0bSAyushi Smriti updateRetryCfg = true; 2267d1cc387SAppaRao Puli } 2277d1cc387SAppaRao Puli 2287d1cc387SAppaRao Puli if (updateConfig) 2297d1cc387SAppaRao Puli { 2307d1cc387SAppaRao Puli updateSubscriptionData(); 2317d1cc387SAppaRao Puli } 232fe44eb0bSAyushi Smriti 233fe44eb0bSAyushi Smriti if (updateRetryCfg) 234fe44eb0bSAyushi Smriti { 235fe44eb0bSAyushi Smriti // Update the changed retry config to all subscriptions 236fe44eb0bSAyushi Smriti for (const auto& it : 237fe44eb0bSAyushi Smriti EventServiceManager::getInstance().subscriptionsMap) 238fe44eb0bSAyushi Smriti { 2395e44e3d8SAppaRao Puli Subscription& entry = *it.second; 2405e44e3d8SAppaRao Puli entry.updateRetryConfig(retryAttempts, retryTimeoutInterval); 241fe44eb0bSAyushi Smriti } 242fe44eb0bSAyushi Smriti } 2437d1cc387SAppaRao Puli } 2447d1cc387SAppaRao Puli 2457d1cc387SAppaRao Puli void updateNoOfSubscribersCount() 2467d1cc387SAppaRao Puli { 2477d1cc387SAppaRao Puli size_t eventLogSubCount = 0; 2487d1cc387SAppaRao Puli size_t metricReportSubCount = 0; 2497d1cc387SAppaRao Puli for (const auto& it : subscriptionsMap) 2507d1cc387SAppaRao Puli { 2517d1cc387SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 2525fe4ef35SMyung Bae if (entry->userSub->eventFormatType == eventFormatType) 2537d1cc387SAppaRao Puli { 2547d1cc387SAppaRao Puli eventLogSubCount++; 2557d1cc387SAppaRao Puli } 2565fe4ef35SMyung Bae else if (entry->userSub->eventFormatType == metricReportFormatType) 2577d1cc387SAppaRao Puli { 2587d1cc387SAppaRao Puli metricReportSubCount++; 2597d1cc387SAppaRao Puli } 2607d1cc387SAppaRao Puli } 2617d1cc387SAppaRao Puli noOfEventLogSubscribers = eventLogSubCount; 2626c58a03eSAlexander Hansen if (eventLogSubCount > 0U) 2637d1cc387SAppaRao Puli { 2646c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 2656c58a03eSAlexander Hansen { 2666c58a03eSAlexander Hansen if (!dbusEventLogMonitor && 2676c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 2686c58a03eSAlexander Hansen { 2696c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 2706c58a03eSAlexander Hansen } 2716c58a03eSAlexander Hansen } 2726c58a03eSAlexander Hansen else 2736c58a03eSAlexander Hansen { 2746c58a03eSAlexander Hansen if (!filesystemLogMonitor) 2756c58a03eSAlexander Hansen { 2769838eb20SEd Tanous filesystemLogMonitor.emplace(getIoContext()); 2776c58a03eSAlexander Hansen } 2786c58a03eSAlexander Hansen } 2796c58a03eSAlexander Hansen } 2806c58a03eSAlexander Hansen else 2816c58a03eSAlexander Hansen { 2826c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 2836c58a03eSAlexander Hansen filesystemLogMonitor.reset(); 2846c58a03eSAlexander Hansen } 2856c58a03eSAlexander Hansen 2867d1cc387SAppaRao Puli noOfMetricReportSubscribers = metricReportSubCount; 2876c58a03eSAlexander Hansen if (metricReportSubCount > 0U) 2887d1cc387SAppaRao Puli { 2892ac69850SEd Tanous if (!matchTelemetryMonitor) 2902ac69850SEd Tanous { 2912ac69850SEd Tanous matchTelemetryMonitor.emplace(); 2922ac69850SEd Tanous } 2937d1cc387SAppaRao Puli } 2947d1cc387SAppaRao Puli else 2957d1cc387SAppaRao Puli { 2962ac69850SEd Tanous matchTelemetryMonitor.reset(); 2977d1cc387SAppaRao Puli } 2987d1cc387SAppaRao Puli } 2997d1cc387SAppaRao Puli 300b52664e2SAppaRao Puli std::shared_ptr<Subscription> getSubscription(const std::string& id) 301b52664e2SAppaRao Puli { 302b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 303b52664e2SAppaRao Puli if (obj == subscriptionsMap.end()) 304b52664e2SAppaRao Puli { 30562598e31SEd Tanous BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id); 306b52664e2SAppaRao Puli return nullptr; 307b52664e2SAppaRao Puli } 308b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = obj->second; 309b52664e2SAppaRao Puli return subValue; 310b52664e2SAppaRao Puli } 311b52664e2SAppaRao Puli 312504af5a0SPatrick Williams std::string addSubscriptionInternal( 313504af5a0SPatrick Williams const std::shared_ptr<Subscription>& subValue) 314b52664e2SAppaRao Puli { 315fc76b8acSEd Tanous std::uniform_int_distribution<uint32_t> dist(0); 316fc76b8acSEd Tanous bmcweb::OpenSSLGenerator gen; 317fc76b8acSEd Tanous 318b52664e2SAppaRao Puli std::string id; 319b52664e2SAppaRao Puli 320b52664e2SAppaRao Puli int retry = 3; 321e662eae8SEd Tanous while (retry != 0) 322b52664e2SAppaRao Puli { 323fc76b8acSEd Tanous id = std::to_string(dist(gen)); 324fc76b8acSEd Tanous if (gen.error()) 325fc76b8acSEd Tanous { 326fc76b8acSEd Tanous retry = 0; 327fc76b8acSEd Tanous break; 328fc76b8acSEd Tanous } 329b52664e2SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 330b52664e2SAppaRao Puli if (inserted.second) 331b52664e2SAppaRao Puli { 332b52664e2SAppaRao Puli break; 333b52664e2SAppaRao Puli } 334b52664e2SAppaRao Puli --retry; 33523a21a1cSEd Tanous } 336b52664e2SAppaRao Puli 337b52664e2SAppaRao Puli if (retry <= 0) 338b52664e2SAppaRao Puli { 33962598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to generate random number"); 340abb93cddSEd Tanous return ""; 341b52664e2SAppaRao Puli } 342b52664e2SAppaRao Puli 34356ba386dSMyung Bae // Set Subscription ID for back trace 3445fe4ef35SMyung Bae subValue->userSub->id = id; 345a14c9113SEd Tanous 34628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 3475fe4ef35SMyung Bae .subscriptionsConfigMap.emplace(id, subValue->userSub); 34828afb49cSJunLin Chen 3497d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 3501bf712bcSAyushi Smriti 351fe44eb0bSAyushi Smriti // Update retry configuration. 352fe44eb0bSAyushi Smriti subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 353fe44eb0bSAyushi Smriti 354f80a87f2SEd Tanous return id; 355f80a87f2SEd Tanous } 356f80a87f2SEd Tanous 357504af5a0SPatrick Williams std::string addSSESubscription( 358504af5a0SPatrick Williams const std::shared_ptr<Subscription>& subValue, 359f80a87f2SEd Tanous std::string_view lastEventId) 360f80a87f2SEd Tanous { 361f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 362f80a87f2SEd Tanous 363f80a87f2SEd Tanous if (!lastEventId.empty()) 364f80a87f2SEd Tanous { 365f80a87f2SEd Tanous BMCWEB_LOG_INFO("Attempting to find message for last id {}", 366f80a87f2SEd Tanous lastEventId); 367f80a87f2SEd Tanous boost::circular_buffer<Event>::iterator lastEvent = 3684a19a7b5SEd Tanous std::ranges::find_if( 3694a19a7b5SEd Tanous messages, [&lastEventId](const Event& event) { 3704a19a7b5SEd Tanous return std::to_string(event.id) == lastEventId; 371f80a87f2SEd Tanous }); 372f80a87f2SEd Tanous // Can't find a matching ID 373f80a87f2SEd Tanous if (lastEvent == messages.end()) 374f80a87f2SEd Tanous { 375f80a87f2SEd Tanous nlohmann::json msg = messages::eventBufferExceeded(); 3764a19a7b5SEd Tanous 3774a19a7b5SEd Tanous std::string strMsg = msg.dump( 3784a19a7b5SEd Tanous 2, ' ', true, nlohmann::json::error_handler_t::replace); 3794a19a7b5SEd Tanous eventId++; 3804a19a7b5SEd Tanous subValue->sendEventToSubscriber(eventId, std::move(strMsg)); 381f80a87f2SEd Tanous } 382f80a87f2SEd Tanous else 383f80a87f2SEd Tanous { 384f80a87f2SEd Tanous // Skip the last event the user already has 385f80a87f2SEd Tanous lastEvent++; 386f80a87f2SEd Tanous 387f80a87f2SEd Tanous for (boost::circular_buffer<Event>::const_iterator event = 388f80a87f2SEd Tanous lastEvent; 3894a19a7b5SEd Tanous event != messages.end(); event++) 390f80a87f2SEd Tanous { 3914a19a7b5SEd Tanous std::string strMsg = 3924a19a7b5SEd Tanous nlohmann::json(event->message) 3934a19a7b5SEd Tanous .dump(2, ' ', true, 3944a19a7b5SEd Tanous nlohmann::json::error_handler_t::replace); 3954a19a7b5SEd Tanous 3964a19a7b5SEd Tanous subValue->sendEventToSubscriber(event->id, 3974a19a7b5SEd Tanous std::move(strMsg)); 3984a19a7b5SEd Tanous } 399f80a87f2SEd Tanous } 400f80a87f2SEd Tanous } 401f80a87f2SEd Tanous return id; 402f80a87f2SEd Tanous } 403f80a87f2SEd Tanous 404504af5a0SPatrick Williams std::string addPushSubscription( 405504af5a0SPatrick Williams const std::shared_ptr<Subscription>& subValue) 406f80a87f2SEd Tanous { 407f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 408a0969c70SMyung Bae subValue->deleter = [id]() { 409a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 410a0969c70SMyung Bae }; 411f80a87f2SEd Tanous updateSubscriptionData(); 412b52664e2SAppaRao Puli return id; 413b52664e2SAppaRao Puli } 414b52664e2SAppaRao Puli 415b52664e2SAppaRao Puli bool isSubscriptionExist(const std::string& id) 416b52664e2SAppaRao Puli { 417b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 41855f79e6fSEd Tanous return obj != subscriptionsMap.end(); 419b52664e2SAppaRao Puli } 420b52664e2SAppaRao Puli 4214b712a29SEd Tanous bool deleteSubscription(const std::string& id) 422b52664e2SAppaRao Puli { 423b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 4244b712a29SEd Tanous if (obj == subscriptionsMap.end()) 425b52664e2SAppaRao Puli { 4264b712a29SEd Tanous BMCWEB_LOG_WARNING("Could not find subscription with id {}", id); 4274b712a29SEd Tanous return false; 4284b712a29SEd Tanous } 429b52664e2SAppaRao Puli subscriptionsMap.erase(obj); 4304b712a29SEd Tanous auto& event = persistent_data::EventServiceStore::getInstance(); 4314b712a29SEd Tanous auto persistentObj = event.subscriptionsConfigMap.find(id); 4324b712a29SEd Tanous if (persistentObj == event.subscriptionsConfigMap.end()) 4334b712a29SEd Tanous { 4346136e852SMyung Bae BMCWEB_LOG_ERROR("Subscription {} wasn't in persistent data", id); 4354b712a29SEd Tanous return true; 4364b712a29SEd Tanous } 43728afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 4384b712a29SEd Tanous .subscriptionsConfigMap.erase(persistentObj); 4397d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 440b52664e2SAppaRao Puli updateSubscriptionData(); 4414b712a29SEd Tanous 4424b712a29SEd Tanous return true; 443b52664e2SAppaRao Puli } 444b52664e2SAppaRao Puli 4455e44e3d8SAppaRao Puli void deleteSseSubscription(const crow::sse_socket::Connection& thisConn) 4465e44e3d8SAppaRao Puli { 447bdbfae2aSEd Tanous for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();) 4485e44e3d8SAppaRao Puli { 449bdbfae2aSEd Tanous std::shared_ptr<Subscription> entry = it->second; 4505e44e3d8SAppaRao Puli bool entryIsThisConn = entry->matchSseId(thisConn); 4515e44e3d8SAppaRao Puli if (entryIsThisConn) 4525e44e3d8SAppaRao Puli { 4535e44e3d8SAppaRao Puli persistent_data::EventServiceStore::getInstance() 4545fe4ef35SMyung Bae .subscriptionsConfigMap.erase(entry->userSub->id); 455bdbfae2aSEd Tanous it = subscriptionsMap.erase(it); 4565e44e3d8SAppaRao Puli return; 4575e44e3d8SAppaRao Puli } 458bdbfae2aSEd Tanous it++; 4595e44e3d8SAppaRao Puli } 4605e44e3d8SAppaRao Puli } 4615e44e3d8SAppaRao Puli 4625e44e3d8SAppaRao Puli size_t getNumberOfSubscriptions() const 463b52664e2SAppaRao Puli { 464b52664e2SAppaRao Puli return subscriptionsMap.size(); 465b52664e2SAppaRao Puli } 466b52664e2SAppaRao Puli 4675e44e3d8SAppaRao Puli size_t getNumberOfSSESubscriptions() const 4685e44e3d8SAppaRao Puli { 4693544d2a7SEd Tanous auto size = std::ranges::count_if( 4703544d2a7SEd Tanous subscriptionsMap, 4715e44e3d8SAppaRao Puli [](const std::pair<std::string, std::shared_ptr<Subscription>>& 4725e44e3d8SAppaRao Puli entry) { 4735fe4ef35SMyung Bae return (entry.second->userSub->subscriptionType == 4744b712a29SEd Tanous subscriptionTypeSSE); 4755e44e3d8SAppaRao Puli }); 4765e44e3d8SAppaRao Puli return static_cast<size_t>(size); 4775e44e3d8SAppaRao Puli } 4785e44e3d8SAppaRao Puli 479b52664e2SAppaRao Puli std::vector<std::string> getAllIDs() 480b52664e2SAppaRao Puli { 481b52664e2SAppaRao Puli std::vector<std::string> idList; 482b52664e2SAppaRao Puli for (const auto& it : subscriptionsMap) 483b52664e2SAppaRao Puli { 484b52664e2SAppaRao Puli idList.emplace_back(it.first); 485b52664e2SAppaRao Puli } 486b52664e2SAppaRao Puli return idList; 487b52664e2SAppaRao Puli } 488b52664e2SAppaRao Puli 48981ee0e74SChandramohan Harkude bool sendTestEventLog(TestEvent& testEvent) 4900b4bdd93SAppaRao Puli { 4914a19a7b5SEd Tanous eventId++; 4924a19a7b5SEd Tanous nlohmann::json::array_t logEntryArray; 4934a19a7b5SEd Tanous nlohmann::json& logEntryJson = logEntryArray.emplace_back(); 4944a19a7b5SEd Tanous 4954a19a7b5SEd Tanous if (testEvent.eventGroupId) 4964a19a7b5SEd Tanous { 4974a19a7b5SEd Tanous logEntryJson["EventGroupId"] = *testEvent.eventGroupId; 4984a19a7b5SEd Tanous } 4994a19a7b5SEd Tanous 5004a19a7b5SEd Tanous if (testEvent.eventTimestamp) 5014a19a7b5SEd Tanous { 5024a19a7b5SEd Tanous logEntryJson["EventTimestamp"] = *testEvent.eventTimestamp; 5034a19a7b5SEd Tanous } 5044a19a7b5SEd Tanous 5054a19a7b5SEd Tanous if (testEvent.originOfCondition) 5064a19a7b5SEd Tanous { 5074a19a7b5SEd Tanous logEntryJson["OriginOfCondition"]["@odata.id"] = 5084a19a7b5SEd Tanous *testEvent.originOfCondition; 5094a19a7b5SEd Tanous } 5104a19a7b5SEd Tanous if (testEvent.severity) 5114a19a7b5SEd Tanous { 5124a19a7b5SEd Tanous logEntryJson["Severity"] = *testEvent.severity; 5134a19a7b5SEd Tanous } 5144a19a7b5SEd Tanous 5154a19a7b5SEd Tanous if (testEvent.message) 5164a19a7b5SEd Tanous { 5174a19a7b5SEd Tanous logEntryJson["Message"] = *testEvent.message; 5184a19a7b5SEd Tanous } 5194a19a7b5SEd Tanous 5204a19a7b5SEd Tanous if (testEvent.resolution) 5214a19a7b5SEd Tanous { 5224a19a7b5SEd Tanous logEntryJson["Resolution"] = *testEvent.resolution; 5234a19a7b5SEd Tanous } 5244a19a7b5SEd Tanous 5254a19a7b5SEd Tanous if (testEvent.messageId) 5264a19a7b5SEd Tanous { 5274a19a7b5SEd Tanous logEntryJson["MessageId"] = *testEvent.messageId; 5284a19a7b5SEd Tanous } 5294a19a7b5SEd Tanous 5304a19a7b5SEd Tanous if (testEvent.messageArgs) 5314a19a7b5SEd Tanous { 5324a19a7b5SEd Tanous logEntryJson["MessageArgs"] = *testEvent.messageArgs; 5334a19a7b5SEd Tanous } 5344a19a7b5SEd Tanous // MemberId is 0 : since we are sending one event record. 5354a19a7b5SEd Tanous logEntryJson["MemberId"] = "0"; 5364a19a7b5SEd Tanous 537*82b286fbSEd Tanous nlohmann::json::object_t msg; 5384a19a7b5SEd Tanous msg["@odata.type"] = "#Event.v1_4_0.Event"; 5394a19a7b5SEd Tanous msg["Id"] = std::to_string(eventId); 5404a19a7b5SEd Tanous msg["Name"] = "Event Log"; 5414a19a7b5SEd Tanous msg["Events"] = logEntryArray; 5424a19a7b5SEd Tanous 543*82b286fbSEd Tanous std::string strMsg = nlohmann::json(msg).dump( 544*82b286fbSEd Tanous 2, ' ', true, nlohmann::json::error_handler_t::replace); 5454a19a7b5SEd Tanous 5464a19a7b5SEd Tanous messages.push_back(Event(eventId, msg)); 5475e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 5480b4bdd93SAppaRao Puli { 5490b4bdd93SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 5504a19a7b5SEd Tanous if (!entry->sendEventToSubscriber(eventId, std::string(strMsg))) 5516ba8c82eSsunharis_in { 5526ba8c82eSsunharis_in return false; 5530b4bdd93SAppaRao Puli } 5540b4bdd93SAppaRao Puli } 5556ba8c82eSsunharis_in return true; 5566ba8c82eSsunharis_in } 557e9a14131SAppaRao Puli 558504af5a0SPatrick Williams static void sendEventsToSubs( 559504af5a0SPatrick Williams const std::vector<EventLogObjectsType>& eventRecords) 5603433b03aSEd Tanous { 5614a19a7b5SEd Tanous EventServiceManager& mgr = EventServiceManager::getInstance(); 5624a19a7b5SEd Tanous mgr.eventId++; 5634a19a7b5SEd Tanous for (const auto& it : mgr.subscriptionsMap) 5643433b03aSEd Tanous { 5653433b03aSEd Tanous Subscription& entry = *it.second; 5664a19a7b5SEd Tanous entry.filterAndSendEventLogs(mgr.eventId, eventRecords); 5673433b03aSEd Tanous } 5683433b03aSEd Tanous } 5693433b03aSEd Tanous 570b26ff34dSEd Tanous static void sendTelemetryReportToSubs( 571b26ff34dSEd Tanous const std::string& reportId, const telemetry::TimestampReadings& var) 572b26ff34dSEd Tanous { 5734a19a7b5SEd Tanous EventServiceManager& mgr = EventServiceManager::getInstance(); 5744a19a7b5SEd Tanous mgr.eventId++; 5754a19a7b5SEd Tanous 5764a19a7b5SEd Tanous for (const auto& it : mgr.subscriptionsMap) 577b26ff34dSEd Tanous { 578b26ff34dSEd Tanous Subscription& entry = *it.second; 5794a19a7b5SEd Tanous entry.filterAndSendReports(mgr.eventId, reportId, var); 580b26ff34dSEd Tanous } 581b26ff34dSEd Tanous } 582b26ff34dSEd Tanous 583f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 584f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 58596330b99SSunitha Harish { 5864a19a7b5SEd Tanous eventId++; 587613dabeaSEd Tanous eventMessage["EventId"] = eventId; 588f80a87f2SEd Tanous 589613dabeaSEd Tanous eventMessage["EventTimestamp"] = 590613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 5914a19a7b5SEd Tanous 5924a19a7b5SEd Tanous if (!origin.empty()) 5934a19a7b5SEd Tanous { 594613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 5954a19a7b5SEd Tanous } 596613dabeaSEd Tanous 597f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 598788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 59996330b99SSunitha Harish 6004a19a7b5SEd Tanous messages.push_back(Event(eventId, eventMessage)); 601f80a87f2SEd Tanous 602f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 60396330b99SSunitha Harish { 604f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 6055fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 6065fe4ef35SMyung Bae resourceType)) 60796330b99SSunitha Harish { 608f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 609f80a87f2SEd Tanous continue; 61096330b99SSunitha Harish } 611f80a87f2SEd Tanous 612f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 613f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 614f80a87f2SEd Tanous 615613dabeaSEd Tanous nlohmann::json msgJson; 616613dabeaSEd Tanous 617613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 618613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 619613dabeaSEd Tanous msgJson["Id"] = eventId; 620f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 621f52c03c1SCarson Labrado 622f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 623f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 6244a19a7b5SEd Tanous entry->sendEventToSubscriber(eventId, std::move(strMsg)); 62596330b99SSunitha Harish } 62696330b99SSunitha Harish } 62723a21a1cSEd Tanous }; 628b52664e2SAppaRao Puli 629b52664e2SAppaRao Puli } // namespace redfish 630