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" 152c6ffdb0SEd Tanous #include "ossl_random.hpp" 163ccb3adbSEd Tanous #include "persistent_data.hpp" 17d7857201SEd Tanous #include "server_sent_event.hpp" 1802c1e29fSAlexander Hansen #include "subscription.hpp" 19*f86cdd7dSEd Tanous #include "telemetry_readings.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> 33a14c9113SEd Tanous #include <format> 34b52664e2SAppaRao Puli #include <memory> 35d7857201SEd Tanous #include <optional> 36d7857201SEd Tanous #include <random> 37a14c9113SEd Tanous #include <string> 3856ba386dSMyung Bae #include <string_view> 395fe4ef35SMyung Bae #include <utility> 40d7857201SEd Tanous #include <vector> 41b52664e2SAppaRao Puli 42b52664e2SAppaRao Puli namespace redfish 43b52664e2SAppaRao Puli { 44156d6b00SAppaRao Puli 45156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event"; 46156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport"; 47156d6b00SAppaRao Puli 48b52664e2SAppaRao Puli class EventServiceManager 49b52664e2SAppaRao Puli { 50b52664e2SAppaRao Puli private: 51d3a9e084SEd Tanous bool serviceEnabled = false; 52d3a9e084SEd Tanous uint32_t retryAttempts = 0; 53d3a9e084SEd Tanous uint32_t retryTimeoutInterval = 0; 547d1cc387SAppaRao Puli 559f616dd1SEd Tanous size_t noOfEventLogSubscribers{0}; 569f616dd1SEd Tanous size_t noOfMetricReportSubscribers{0}; 576c58a03eSAlexander Hansen std::optional<DbusEventLogMonitor> dbusEventLogMonitor; 582ac69850SEd Tanous std::optional<DbusTelemetryMonitor> matchTelemetryMonitor; 597b669723SEd Tanous std::optional<FilesystemLogWatcher> filesystemLogMonitor; 60b52664e2SAppaRao Puli boost::container::flat_map<std::string, std::shared_ptr<Subscription>> 61b52664e2SAppaRao Puli subscriptionsMap; 62b52664e2SAppaRao Puli 639f616dd1SEd Tanous uint64_t eventId{1}; 6496330b99SSunitha Harish 65f80a87f2SEd Tanous struct Event 66f80a87f2SEd Tanous { 674a19a7b5SEd Tanous uint64_t id; 684a19a7b5SEd Tanous nlohmann::json::object_t message; 69f80a87f2SEd Tanous }; 70f80a87f2SEd Tanous 71f80a87f2SEd Tanous constexpr static size_t maxMessages = 200; 72f80a87f2SEd Tanous boost::circular_buffer<Event> messages{maxMessages}; 73f80a87f2SEd Tanous 74b52664e2SAppaRao Puli public: 759f616dd1SEd Tanous EventServiceManager(const EventServiceManager&) = delete; 769f616dd1SEd Tanous EventServiceManager& operator=(const EventServiceManager&) = delete; 779f616dd1SEd Tanous EventServiceManager(EventServiceManager&&) = delete; 789f616dd1SEd Tanous EventServiceManager& operator=(EventServiceManager&&) = delete; 79ecd6a3a2SEd Tanous ~EventServiceManager() = default; 809f616dd1SEd Tanous 819838eb20SEd Tanous explicit EventServiceManager() 82b52664e2SAppaRao Puli { 83f8ca6d79SEd Tanous // Load config from persist store. 84f8ca6d79SEd Tanous initConfig(); 85f8ca6d79SEd Tanous } 86f8ca6d79SEd Tanous 879838eb20SEd Tanous static EventServiceManager& getInstance() 88f8ca6d79SEd Tanous { 899838eb20SEd Tanous static EventServiceManager handler; 90b52664e2SAppaRao Puli return handler; 91b52664e2SAppaRao Puli } 92b52664e2SAppaRao Puli 931bf712bcSAyushi Smriti void initConfig() 941bf712bcSAyushi Smriti { 9528afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 9628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 9728afb49cSJunLin Chen .getEventServiceConfig(); 981bf712bcSAyushi Smriti 9928afb49cSJunLin Chen serviceEnabled = eventServiceConfig.enabled; 10028afb49cSJunLin Chen retryAttempts = eventServiceConfig.retryAttempts; 10128afb49cSJunLin Chen retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval; 1021bf712bcSAyushi Smriti 10328afb49cSJunLin Chen for (const auto& it : persistent_data::EventServiceStore::getInstance() 10428afb49cSJunLin Chen .subscriptionsConfigMap) 1051bf712bcSAyushi Smriti { 1065fe4ef35SMyung Bae std::shared_ptr<persistent_data::UserSubscription> newSub = 1075fe4ef35SMyung Bae it.second; 1084bbf237fSAppaRao Puli 1096fd29553SEd Tanous boost::system::result<boost::urls::url> url = 1105fe4ef35SMyung Bae boost::urls::parse_absolute_uri(newSub->destinationUrl); 1111bf712bcSAyushi Smriti 112a716aa74SEd Tanous if (!url) 1131bf712bcSAyushi Smriti { 11462598e31SEd Tanous BMCWEB_LOG_ERROR( 11562598e31SEd Tanous "Failed to validate and split destination url"); 1161bf712bcSAyushi Smriti continue; 1171bf712bcSAyushi Smriti } 1181bf712bcSAyushi Smriti std::shared_ptr<Subscription> subValue = 1199838eb20SEd Tanous std::make_shared<Subscription>(newSub, *url, getIoContext()); 1205fe4ef35SMyung Bae std::string id = subValue->userSub->id; 121a0969c70SMyung Bae subValue->deleter = [id]() { 122a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 123a0969c70SMyung Bae }; 1241bf712bcSAyushi Smriti 125a0969c70SMyung Bae subscriptionsMap.emplace(id, subValue); 12628afb49cSJunLin Chen 12728afb49cSJunLin Chen updateNoOfSubscribersCount(); 12828afb49cSJunLin Chen 12928afb49cSJunLin Chen // Update retry configuration. 13028afb49cSJunLin Chen subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 131fb546105SMyung Bae 132fb546105SMyung Bae // schedule a heartbeat if sendHeartbeat was set to true 133fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 134fb546105SMyung Bae { 135fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 136fb546105SMyung Bae } 1371bf712bcSAyushi Smriti } 1381bf712bcSAyushi Smriti } 1391bf712bcSAyushi Smriti 1409eb808c1SEd Tanous void updateSubscriptionData() const 14128afb49cSJunLin Chen { 14228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 14328afb49cSJunLin Chen .eventServiceConfig.enabled = serviceEnabled; 14428afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 14528afb49cSJunLin Chen .eventServiceConfig.retryAttempts = retryAttempts; 14628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 14728afb49cSJunLin Chen .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval; 14828afb49cSJunLin Chen 14928afb49cSJunLin Chen persistent_data::getConfig().writeData(); 15028afb49cSJunLin Chen } 15128afb49cSJunLin Chen 15228afb49cSJunLin Chen void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg) 1537d1cc387SAppaRao Puli { 1547d1cc387SAppaRao Puli bool updateConfig = false; 155fe44eb0bSAyushi Smriti bool updateRetryCfg = false; 1567d1cc387SAppaRao Puli 1572ac69850SEd Tanous if (serviceEnabled) 1587d1cc387SAppaRao Puli { 1597b669723SEd Tanous if (noOfEventLogSubscribers > 0U) 1607b669723SEd Tanous { 1616c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 1626c58a03eSAlexander Hansen { 1636c58a03eSAlexander Hansen if (!dbusEventLogMonitor) 1646c58a03eSAlexander Hansen { 1656c58a03eSAlexander Hansen if constexpr ( 1666c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 1676c58a03eSAlexander Hansen { 1686c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 1696c58a03eSAlexander Hansen } 1706c58a03eSAlexander Hansen } 1716c58a03eSAlexander Hansen } 1726c58a03eSAlexander Hansen else 1737b669723SEd Tanous { 1747b669723SEd Tanous if (!filesystemLogMonitor) 1757b669723SEd Tanous { 1769838eb20SEd Tanous filesystemLogMonitor.emplace(getIoContext()); 1777b669723SEd Tanous } 1787b669723SEd Tanous } 1797b669723SEd Tanous } 1807b669723SEd Tanous else 1817b669723SEd Tanous { 1826c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 1837b669723SEd Tanous filesystemLogMonitor.reset(); 1847b669723SEd Tanous } 1857b669723SEd Tanous 1862ac69850SEd Tanous if (noOfMetricReportSubscribers > 0U) 1877d1cc387SAppaRao Puli { 1882ac69850SEd Tanous if (!matchTelemetryMonitor) 1892ac69850SEd Tanous { 1902ac69850SEd Tanous matchTelemetryMonitor.emplace(); 1912ac69850SEd Tanous } 1927d1cc387SAppaRao Puli } 1937d1cc387SAppaRao Puli else 1947d1cc387SAppaRao Puli { 1952ac69850SEd Tanous matchTelemetryMonitor.reset(); 1967d1cc387SAppaRao Puli } 1972ac69850SEd Tanous } 1982ac69850SEd Tanous else 1992ac69850SEd Tanous { 2002ac69850SEd Tanous matchTelemetryMonitor.reset(); 2016c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 2027b669723SEd Tanous filesystemLogMonitor.reset(); 2032ac69850SEd Tanous } 2042ac69850SEd Tanous 2052ac69850SEd Tanous if (serviceEnabled != cfg.enabled) 2062ac69850SEd Tanous { 2072ac69850SEd Tanous serviceEnabled = cfg.enabled; 2087d1cc387SAppaRao Puli updateConfig = true; 2097d1cc387SAppaRao Puli } 2107d1cc387SAppaRao Puli 21128afb49cSJunLin Chen if (retryAttempts != cfg.retryAttempts) 2127d1cc387SAppaRao Puli { 21328afb49cSJunLin Chen retryAttempts = cfg.retryAttempts; 2147d1cc387SAppaRao Puli updateConfig = true; 215fe44eb0bSAyushi Smriti updateRetryCfg = true; 2167d1cc387SAppaRao Puli } 2177d1cc387SAppaRao Puli 21828afb49cSJunLin Chen if (retryTimeoutInterval != cfg.retryTimeoutInterval) 2197d1cc387SAppaRao Puli { 22028afb49cSJunLin Chen retryTimeoutInterval = cfg.retryTimeoutInterval; 2217d1cc387SAppaRao Puli updateConfig = true; 222fe44eb0bSAyushi Smriti updateRetryCfg = true; 2237d1cc387SAppaRao Puli } 2247d1cc387SAppaRao Puli 2257d1cc387SAppaRao Puli if (updateConfig) 2267d1cc387SAppaRao Puli { 2277d1cc387SAppaRao Puli updateSubscriptionData(); 2287d1cc387SAppaRao Puli } 229fe44eb0bSAyushi Smriti 230fe44eb0bSAyushi Smriti if (updateRetryCfg) 231fe44eb0bSAyushi Smriti { 232fe44eb0bSAyushi Smriti // Update the changed retry config to all subscriptions 233fe44eb0bSAyushi Smriti for (const auto& it : 234fe44eb0bSAyushi Smriti EventServiceManager::getInstance().subscriptionsMap) 235fe44eb0bSAyushi Smriti { 2365e44e3d8SAppaRao Puli Subscription& entry = *it.second; 2375e44e3d8SAppaRao Puli entry.updateRetryConfig(retryAttempts, retryTimeoutInterval); 238fe44eb0bSAyushi Smriti } 239fe44eb0bSAyushi Smriti } 2407d1cc387SAppaRao Puli } 2417d1cc387SAppaRao Puli 2427d1cc387SAppaRao Puli void updateNoOfSubscribersCount() 2437d1cc387SAppaRao Puli { 2447d1cc387SAppaRao Puli size_t eventLogSubCount = 0; 2457d1cc387SAppaRao Puli size_t metricReportSubCount = 0; 2467d1cc387SAppaRao Puli for (const auto& it : subscriptionsMap) 2477d1cc387SAppaRao Puli { 2487d1cc387SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 2495fe4ef35SMyung Bae if (entry->userSub->eventFormatType == eventFormatType) 2507d1cc387SAppaRao Puli { 2517d1cc387SAppaRao Puli eventLogSubCount++; 2527d1cc387SAppaRao Puli } 2535fe4ef35SMyung Bae else if (entry->userSub->eventFormatType == metricReportFormatType) 2547d1cc387SAppaRao Puli { 2557d1cc387SAppaRao Puli metricReportSubCount++; 2567d1cc387SAppaRao Puli } 2577d1cc387SAppaRao Puli } 2587d1cc387SAppaRao Puli noOfEventLogSubscribers = eventLogSubCount; 2596c58a03eSAlexander Hansen if (eventLogSubCount > 0U) 2607d1cc387SAppaRao Puli { 2616c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 2626c58a03eSAlexander Hansen { 2636c58a03eSAlexander Hansen if (!dbusEventLogMonitor && 2646c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 2656c58a03eSAlexander Hansen { 2666c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 2676c58a03eSAlexander Hansen } 2686c58a03eSAlexander Hansen } 2696c58a03eSAlexander Hansen else 2706c58a03eSAlexander Hansen { 2716c58a03eSAlexander Hansen if (!filesystemLogMonitor) 2726c58a03eSAlexander Hansen { 2739838eb20SEd Tanous filesystemLogMonitor.emplace(getIoContext()); 2746c58a03eSAlexander Hansen } 2756c58a03eSAlexander Hansen } 2766c58a03eSAlexander Hansen } 2776c58a03eSAlexander Hansen else 2786c58a03eSAlexander Hansen { 2796c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 2806c58a03eSAlexander Hansen filesystemLogMonitor.reset(); 2816c58a03eSAlexander Hansen } 2826c58a03eSAlexander Hansen 2837d1cc387SAppaRao Puli noOfMetricReportSubscribers = metricReportSubCount; 2846c58a03eSAlexander Hansen if (metricReportSubCount > 0U) 2857d1cc387SAppaRao Puli { 2862ac69850SEd Tanous if (!matchTelemetryMonitor) 2872ac69850SEd Tanous { 2882ac69850SEd Tanous matchTelemetryMonitor.emplace(); 2892ac69850SEd Tanous } 2907d1cc387SAppaRao Puli } 2917d1cc387SAppaRao Puli else 2927d1cc387SAppaRao Puli { 2932ac69850SEd Tanous matchTelemetryMonitor.reset(); 2947d1cc387SAppaRao Puli } 2957d1cc387SAppaRao Puli } 2967d1cc387SAppaRao Puli 297b52664e2SAppaRao Puli std::shared_ptr<Subscription> getSubscription(const std::string& id) 298b52664e2SAppaRao Puli { 299b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 300b52664e2SAppaRao Puli if (obj == subscriptionsMap.end()) 301b52664e2SAppaRao Puli { 30262598e31SEd Tanous BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id); 303b52664e2SAppaRao Puli return nullptr; 304b52664e2SAppaRao Puli } 305b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = obj->second; 306b52664e2SAppaRao Puli return subValue; 307b52664e2SAppaRao Puli } 308b52664e2SAppaRao Puli 309504af5a0SPatrick Williams std::string addSubscriptionInternal( 310504af5a0SPatrick Williams const std::shared_ptr<Subscription>& subValue) 311b52664e2SAppaRao Puli { 312fc76b8acSEd Tanous std::uniform_int_distribution<uint32_t> dist(0); 313fc76b8acSEd Tanous bmcweb::OpenSSLGenerator gen; 314fc76b8acSEd Tanous 315b52664e2SAppaRao Puli std::string id; 316b52664e2SAppaRao Puli 317b52664e2SAppaRao Puli int retry = 3; 318e662eae8SEd Tanous while (retry != 0) 319b52664e2SAppaRao Puli { 320fc76b8acSEd Tanous id = std::to_string(dist(gen)); 321fc76b8acSEd Tanous if (gen.error()) 322fc76b8acSEd Tanous { 323fc76b8acSEd Tanous retry = 0; 324fc76b8acSEd Tanous break; 325fc76b8acSEd Tanous } 326b52664e2SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 327b52664e2SAppaRao Puli if (inserted.second) 328b52664e2SAppaRao Puli { 329b52664e2SAppaRao Puli break; 330b52664e2SAppaRao Puli } 331b52664e2SAppaRao Puli --retry; 33223a21a1cSEd Tanous } 333b52664e2SAppaRao Puli 334b52664e2SAppaRao Puli if (retry <= 0) 335b52664e2SAppaRao Puli { 33662598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to generate random number"); 337abb93cddSEd Tanous return ""; 338b52664e2SAppaRao Puli } 339b52664e2SAppaRao Puli 34056ba386dSMyung Bae // Set Subscription ID for back trace 3415fe4ef35SMyung Bae subValue->userSub->id = id; 342a14c9113SEd Tanous 34328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 3445fe4ef35SMyung Bae .subscriptionsConfigMap.emplace(id, subValue->userSub); 34528afb49cSJunLin Chen 3467d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 3471bf712bcSAyushi Smriti 348fe44eb0bSAyushi Smriti // Update retry configuration. 349fe44eb0bSAyushi Smriti subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 350fe44eb0bSAyushi Smriti 351f80a87f2SEd Tanous return id; 352f80a87f2SEd Tanous } 353f80a87f2SEd Tanous 354504af5a0SPatrick Williams std::string addSSESubscription( 355504af5a0SPatrick Williams const std::shared_ptr<Subscription>& subValue, 356f80a87f2SEd Tanous std::string_view lastEventId) 357f80a87f2SEd Tanous { 358f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 359f80a87f2SEd Tanous 360f80a87f2SEd Tanous if (!lastEventId.empty()) 361f80a87f2SEd Tanous { 362f80a87f2SEd Tanous BMCWEB_LOG_INFO("Attempting to find message for last id {}", 363f80a87f2SEd Tanous lastEventId); 364f80a87f2SEd Tanous boost::circular_buffer<Event>::iterator lastEvent = 3654a19a7b5SEd Tanous std::ranges::find_if( 3664a19a7b5SEd Tanous messages, [&lastEventId](const Event& event) { 3674a19a7b5SEd Tanous return std::to_string(event.id) == lastEventId; 368f80a87f2SEd Tanous }); 369f80a87f2SEd Tanous // Can't find a matching ID 370f80a87f2SEd Tanous if (lastEvent == messages.end()) 371f80a87f2SEd Tanous { 372f80a87f2SEd Tanous nlohmann::json msg = messages::eventBufferExceeded(); 3734a19a7b5SEd Tanous 3744a19a7b5SEd Tanous std::string strMsg = msg.dump( 3754a19a7b5SEd Tanous 2, ' ', true, nlohmann::json::error_handler_t::replace); 3764a19a7b5SEd Tanous eventId++; 3774a19a7b5SEd Tanous subValue->sendEventToSubscriber(eventId, std::move(strMsg)); 378f80a87f2SEd Tanous } 379f80a87f2SEd Tanous else 380f80a87f2SEd Tanous { 381f80a87f2SEd Tanous // Skip the last event the user already has 382f80a87f2SEd Tanous lastEvent++; 383f80a87f2SEd Tanous 384f80a87f2SEd Tanous for (boost::circular_buffer<Event>::const_iterator event = 385f80a87f2SEd Tanous lastEvent; 3864a19a7b5SEd Tanous event != messages.end(); event++) 387f80a87f2SEd Tanous { 3884a19a7b5SEd Tanous std::string strMsg = 3894a19a7b5SEd Tanous nlohmann::json(event->message) 3904a19a7b5SEd Tanous .dump(2, ' ', true, 3914a19a7b5SEd Tanous nlohmann::json::error_handler_t::replace); 3924a19a7b5SEd Tanous 3934a19a7b5SEd Tanous subValue->sendEventToSubscriber(event->id, 3944a19a7b5SEd Tanous std::move(strMsg)); 3954a19a7b5SEd Tanous } 396f80a87f2SEd Tanous } 397f80a87f2SEd Tanous } 398f80a87f2SEd Tanous return id; 399f80a87f2SEd Tanous } 400f80a87f2SEd Tanous 401504af5a0SPatrick Williams std::string addPushSubscription( 402504af5a0SPatrick Williams const std::shared_ptr<Subscription>& subValue) 403f80a87f2SEd Tanous { 404f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 405a0969c70SMyung Bae subValue->deleter = [id]() { 406a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 407a0969c70SMyung Bae }; 408f80a87f2SEd Tanous updateSubscriptionData(); 409b52664e2SAppaRao Puli return id; 410b52664e2SAppaRao Puli } 411b52664e2SAppaRao Puli 412b52664e2SAppaRao Puli bool isSubscriptionExist(const std::string& id) 413b52664e2SAppaRao Puli { 414b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 41555f79e6fSEd Tanous return obj != subscriptionsMap.end(); 416b52664e2SAppaRao Puli } 417b52664e2SAppaRao Puli 4184b712a29SEd Tanous bool deleteSubscription(const std::string& id) 419b52664e2SAppaRao Puli { 420b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 4214b712a29SEd Tanous if (obj == subscriptionsMap.end()) 422b52664e2SAppaRao Puli { 4234b712a29SEd Tanous BMCWEB_LOG_WARNING("Could not find subscription with id {}", id); 4244b712a29SEd Tanous return false; 4254b712a29SEd Tanous } 426b52664e2SAppaRao Puli subscriptionsMap.erase(obj); 4274b712a29SEd Tanous auto& event = persistent_data::EventServiceStore::getInstance(); 4284b712a29SEd Tanous auto persistentObj = event.subscriptionsConfigMap.find(id); 4294b712a29SEd Tanous if (persistentObj == event.subscriptionsConfigMap.end()) 4304b712a29SEd Tanous { 4316136e852SMyung Bae BMCWEB_LOG_ERROR("Subscription {} wasn't in persistent data", id); 4324b712a29SEd Tanous return true; 4334b712a29SEd Tanous } 43428afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 4354b712a29SEd Tanous .subscriptionsConfigMap.erase(persistentObj); 4367d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 437b52664e2SAppaRao Puli updateSubscriptionData(); 4384b712a29SEd Tanous 4394b712a29SEd Tanous return true; 440b52664e2SAppaRao Puli } 441b52664e2SAppaRao Puli 4425e44e3d8SAppaRao Puli void deleteSseSubscription(const crow::sse_socket::Connection& thisConn) 4435e44e3d8SAppaRao Puli { 444bdbfae2aSEd Tanous for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();) 4455e44e3d8SAppaRao Puli { 446bdbfae2aSEd Tanous std::shared_ptr<Subscription> entry = it->second; 4475e44e3d8SAppaRao Puli bool entryIsThisConn = entry->matchSseId(thisConn); 4485e44e3d8SAppaRao Puli if (entryIsThisConn) 4495e44e3d8SAppaRao Puli { 4505e44e3d8SAppaRao Puli persistent_data::EventServiceStore::getInstance() 4515fe4ef35SMyung Bae .subscriptionsConfigMap.erase(entry->userSub->id); 452bdbfae2aSEd Tanous it = subscriptionsMap.erase(it); 4535e44e3d8SAppaRao Puli return; 4545e44e3d8SAppaRao Puli } 455bdbfae2aSEd Tanous it++; 4565e44e3d8SAppaRao Puli } 4575e44e3d8SAppaRao Puli } 4585e44e3d8SAppaRao Puli 4595e44e3d8SAppaRao Puli size_t getNumberOfSubscriptions() const 460b52664e2SAppaRao Puli { 461b52664e2SAppaRao Puli return subscriptionsMap.size(); 462b52664e2SAppaRao Puli } 463b52664e2SAppaRao Puli 4645e44e3d8SAppaRao Puli size_t getNumberOfSSESubscriptions() const 4655e44e3d8SAppaRao Puli { 4663544d2a7SEd Tanous auto size = std::ranges::count_if( 4673544d2a7SEd Tanous subscriptionsMap, 4685e44e3d8SAppaRao Puli [](const std::pair<std::string, std::shared_ptr<Subscription>>& 4695e44e3d8SAppaRao Puli entry) { 4705fe4ef35SMyung Bae return (entry.second->userSub->subscriptionType == 4714b712a29SEd Tanous subscriptionTypeSSE); 4725e44e3d8SAppaRao Puli }); 4735e44e3d8SAppaRao Puli return static_cast<size_t>(size); 4745e44e3d8SAppaRao Puli } 4755e44e3d8SAppaRao Puli 476b52664e2SAppaRao Puli std::vector<std::string> getAllIDs() 477b52664e2SAppaRao Puli { 478b52664e2SAppaRao Puli std::vector<std::string> idList; 479b52664e2SAppaRao Puli for (const auto& it : subscriptionsMap) 480b52664e2SAppaRao Puli { 481b52664e2SAppaRao Puli idList.emplace_back(it.first); 482b52664e2SAppaRao Puli } 483b52664e2SAppaRao Puli return idList; 484b52664e2SAppaRao Puli } 485b52664e2SAppaRao Puli 48681ee0e74SChandramohan Harkude bool sendTestEventLog(TestEvent& testEvent) 4870b4bdd93SAppaRao Puli { 4884a19a7b5SEd Tanous eventId++; 4894a19a7b5SEd Tanous nlohmann::json::array_t logEntryArray; 4904a19a7b5SEd Tanous nlohmann::json& logEntryJson = logEntryArray.emplace_back(); 4914a19a7b5SEd Tanous 4924a19a7b5SEd Tanous if (testEvent.eventGroupId) 4934a19a7b5SEd Tanous { 4944a19a7b5SEd Tanous logEntryJson["EventGroupId"] = *testEvent.eventGroupId; 4954a19a7b5SEd Tanous } 4964a19a7b5SEd Tanous 4974a19a7b5SEd Tanous if (testEvent.eventTimestamp) 4984a19a7b5SEd Tanous { 4994a19a7b5SEd Tanous logEntryJson["EventTimestamp"] = *testEvent.eventTimestamp; 5004a19a7b5SEd Tanous } 5014a19a7b5SEd Tanous 5024a19a7b5SEd Tanous if (testEvent.originOfCondition) 5034a19a7b5SEd Tanous { 5044a19a7b5SEd Tanous logEntryJson["OriginOfCondition"]["@odata.id"] = 5054a19a7b5SEd Tanous *testEvent.originOfCondition; 5064a19a7b5SEd Tanous } 5074a19a7b5SEd Tanous if (testEvent.severity) 5084a19a7b5SEd Tanous { 5094a19a7b5SEd Tanous logEntryJson["Severity"] = *testEvent.severity; 5104a19a7b5SEd Tanous } 5114a19a7b5SEd Tanous 5124a19a7b5SEd Tanous if (testEvent.message) 5134a19a7b5SEd Tanous { 5144a19a7b5SEd Tanous logEntryJson["Message"] = *testEvent.message; 5154a19a7b5SEd Tanous } 5164a19a7b5SEd Tanous 5174a19a7b5SEd Tanous if (testEvent.resolution) 5184a19a7b5SEd Tanous { 5194a19a7b5SEd Tanous logEntryJson["Resolution"] = *testEvent.resolution; 5204a19a7b5SEd Tanous } 5214a19a7b5SEd Tanous 5224a19a7b5SEd Tanous if (testEvent.messageId) 5234a19a7b5SEd Tanous { 5244a19a7b5SEd Tanous logEntryJson["MessageId"] = *testEvent.messageId; 5254a19a7b5SEd Tanous } 5264a19a7b5SEd Tanous 5274a19a7b5SEd Tanous if (testEvent.messageArgs) 5284a19a7b5SEd Tanous { 5294a19a7b5SEd Tanous logEntryJson["MessageArgs"] = *testEvent.messageArgs; 5304a19a7b5SEd Tanous } 5314a19a7b5SEd Tanous // MemberId is 0 : since we are sending one event record. 5324a19a7b5SEd Tanous logEntryJson["MemberId"] = "0"; 5334a19a7b5SEd Tanous 53482b286fbSEd Tanous nlohmann::json::object_t msg; 5354a19a7b5SEd Tanous msg["@odata.type"] = "#Event.v1_4_0.Event"; 5364a19a7b5SEd Tanous msg["Id"] = std::to_string(eventId); 5374a19a7b5SEd Tanous msg["Name"] = "Event Log"; 5384a19a7b5SEd Tanous msg["Events"] = logEntryArray; 5394a19a7b5SEd Tanous 54082b286fbSEd Tanous std::string strMsg = nlohmann::json(msg).dump( 54182b286fbSEd Tanous 2, ' ', true, nlohmann::json::error_handler_t::replace); 5424a19a7b5SEd Tanous 5434a19a7b5SEd Tanous messages.push_back(Event(eventId, msg)); 5445e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 5450b4bdd93SAppaRao Puli { 5460b4bdd93SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 5474a19a7b5SEd Tanous if (!entry->sendEventToSubscriber(eventId, std::string(strMsg))) 5486ba8c82eSsunharis_in { 5496ba8c82eSsunharis_in return false; 5500b4bdd93SAppaRao Puli } 5510b4bdd93SAppaRao Puli } 5526ba8c82eSsunharis_in return true; 5536ba8c82eSsunharis_in } 554e9a14131SAppaRao Puli 555504af5a0SPatrick Williams static void sendEventsToSubs( 556504af5a0SPatrick Williams const std::vector<EventLogObjectsType>& eventRecords) 5573433b03aSEd Tanous { 5584a19a7b5SEd Tanous EventServiceManager& mgr = EventServiceManager::getInstance(); 5594a19a7b5SEd Tanous mgr.eventId++; 5604a19a7b5SEd Tanous for (const auto& it : mgr.subscriptionsMap) 5613433b03aSEd Tanous { 5623433b03aSEd Tanous Subscription& entry = *it.second; 5634a19a7b5SEd Tanous entry.filterAndSendEventLogs(mgr.eventId, eventRecords); 5643433b03aSEd Tanous } 5653433b03aSEd Tanous } 5663433b03aSEd Tanous 567b26ff34dSEd Tanous static void sendTelemetryReportToSubs( 568b26ff34dSEd Tanous const std::string& reportId, const telemetry::TimestampReadings& var) 569b26ff34dSEd Tanous { 5704a19a7b5SEd Tanous EventServiceManager& mgr = EventServiceManager::getInstance(); 5714a19a7b5SEd Tanous mgr.eventId++; 5724a19a7b5SEd Tanous 5734a19a7b5SEd Tanous for (const auto& it : mgr.subscriptionsMap) 574b26ff34dSEd Tanous { 575b26ff34dSEd Tanous Subscription& entry = *it.second; 5764a19a7b5SEd Tanous entry.filterAndSendReports(mgr.eventId, reportId, var); 577b26ff34dSEd Tanous } 578b26ff34dSEd Tanous } 579b26ff34dSEd Tanous 580f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 581f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 58296330b99SSunitha Harish { 5834a19a7b5SEd Tanous eventId++; 584613dabeaSEd Tanous eventMessage["EventId"] = eventId; 585f80a87f2SEd Tanous 586613dabeaSEd Tanous eventMessage["EventTimestamp"] = 587613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 5884a19a7b5SEd Tanous 5894a19a7b5SEd Tanous if (!origin.empty()) 5904a19a7b5SEd Tanous { 591613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 5924a19a7b5SEd Tanous } 593613dabeaSEd Tanous 594f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 595788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 59696330b99SSunitha Harish 5974a19a7b5SEd Tanous messages.push_back(Event(eventId, eventMessage)); 598f80a87f2SEd Tanous 599f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 60096330b99SSunitha Harish { 601f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 6025fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 6035fe4ef35SMyung Bae resourceType)) 60496330b99SSunitha Harish { 605f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 606f80a87f2SEd Tanous continue; 60796330b99SSunitha Harish } 608f80a87f2SEd Tanous 609f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 610f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 611f80a87f2SEd Tanous 612613dabeaSEd Tanous nlohmann::json msgJson; 613613dabeaSEd Tanous 614613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 615613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 616613dabeaSEd Tanous msgJson["Id"] = eventId; 617f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 618f52c03c1SCarson Labrado 619f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 620f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 6214a19a7b5SEd Tanous entry->sendEventToSubscriber(eventId, std::move(strMsg)); 62296330b99SSunitha Harish } 62396330b99SSunitha Harish } 62423a21a1cSEd Tanous }; 625b52664e2SAppaRao Puli 626b52664e2SAppaRao Puli } // namespace redfish 627