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