xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 6c58a03e1f6818c3cd0a521466f69ef9e869bf25)
1b52664e2SAppaRao Puli /*
26be832e2SEd Tanous Copyright (c) 2020 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
15b52664e2SAppaRao Puli */
16b52664e2SAppaRao Puli #pragma once
17b26ff34dSEd Tanous #include "dbus_log_watcher.hpp"
183ccb3adbSEd Tanous #include "dbus_utility.hpp"
193ccb3adbSEd Tanous #include "error_messages.hpp"
20b80ba2e4SAlexander Hansen #include "event_log.hpp"
21d3a48a14SEd Tanous #include "event_matches_filter.hpp"
223ccb3adbSEd Tanous #include "event_service_store.hpp"
232185ddeaSEd Tanous #include "filesystem_log_watcher.hpp"
24c0353249SWludzik, Jozef #include "metric_report.hpp"
252c6ffdb0SEd Tanous #include "ossl_random.hpp"
263ccb3adbSEd Tanous #include "persistent_data.hpp"
2702c1e29fSAlexander Hansen #include "subscription.hpp"
282ac69850SEd Tanous #include "utility.hpp"
292ac69850SEd Tanous #include "utils/dbus_event_log_entry.hpp"
302ac69850SEd Tanous #include "utils/json_utils.hpp"
315b90429aSEd Tanous #include "utils/time_utils.hpp"
327f4eb588SAppaRao Puli 
33fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
34f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
35b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
36ef4c65b7SEd Tanous #include <boost/url/format.hpp>
374a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
381214b7e7SGunnar Mills 
395e44e3d8SAppaRao Puli #include <algorithm>
40b52664e2SAppaRao Puli #include <cstdlib>
41b52664e2SAppaRao Puli #include <ctime>
42a14c9113SEd Tanous #include <format>
431bf712bcSAyushi Smriti #include <fstream>
44b52664e2SAppaRao Puli #include <memory>
45a14c9113SEd Tanous #include <string>
4656ba386dSMyung Bae #include <string_view>
475fe4ef35SMyung Bae #include <utility>
482ac69850SEd Tanous #include <variant>
49b52664e2SAppaRao Puli 
50b52664e2SAppaRao Puli namespace redfish
51b52664e2SAppaRao Puli {
52156d6b00SAppaRao Puli 
53156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
54156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
55156d6b00SAppaRao Puli 
561bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
571bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
581bf712bcSAyushi Smriti 
59b52664e2SAppaRao Puli class EventServiceManager
60b52664e2SAppaRao Puli {
61b52664e2SAppaRao Puli   private:
62d3a9e084SEd Tanous     bool serviceEnabled = false;
63d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
64d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
657d1cc387SAppaRao Puli 
669f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
679f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
68*6c58a03eSAlexander Hansen     std::optional<DbusEventLogMonitor> dbusEventLogMonitor;
692ac69850SEd Tanous     std::optional<DbusTelemetryMonitor> matchTelemetryMonitor;
707b669723SEd Tanous     std::optional<FilesystemLogWatcher> filesystemLogMonitor;
71b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
72b52664e2SAppaRao Puli         subscriptionsMap;
73b52664e2SAppaRao Puli 
749f616dd1SEd Tanous     uint64_t eventId{1};
7596330b99SSunitha Harish 
76f80a87f2SEd Tanous     struct Event
77f80a87f2SEd Tanous     {
78f80a87f2SEd Tanous         std::string id;
79f80a87f2SEd Tanous         nlohmann::json message;
80f80a87f2SEd Tanous     };
81f80a87f2SEd Tanous 
82f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
83f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
84f80a87f2SEd Tanous 
85f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
86f8ca6d79SEd Tanous 
87b52664e2SAppaRao Puli   public:
889f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
899f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
909f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
919f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
92ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
939f616dd1SEd Tanous 
94f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
95b52664e2SAppaRao Puli     {
96f8ca6d79SEd Tanous         // Load config from persist store.
97f8ca6d79SEd Tanous         initConfig();
98f8ca6d79SEd Tanous     }
99f8ca6d79SEd Tanous 
100f8ca6d79SEd Tanous     static EventServiceManager&
101f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
102f8ca6d79SEd Tanous     {
103f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
104b52664e2SAppaRao Puli         return handler;
105b52664e2SAppaRao Puli     }
106b52664e2SAppaRao Puli 
1071bf712bcSAyushi Smriti     void initConfig()
1081bf712bcSAyushi Smriti     {
10928afb49cSJunLin Chen         loadOldBehavior();
1101bf712bcSAyushi Smriti 
11128afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
11228afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
11328afb49cSJunLin Chen                 .getEventServiceConfig();
1141bf712bcSAyushi Smriti 
11528afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
11628afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
11728afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1181bf712bcSAyushi Smriti 
11928afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
12028afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1211bf712bcSAyushi Smriti         {
1225fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1235fe4ef35SMyung Bae                 it.second;
1244bbf237fSAppaRao Puli 
1256fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1265fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1271bf712bcSAyushi Smriti 
128a716aa74SEd Tanous             if (!url)
1291bf712bcSAyushi Smriti             {
13062598e31SEd Tanous                 BMCWEB_LOG_ERROR(
13162598e31SEd Tanous                     "Failed to validate and split destination url");
1321bf712bcSAyushi Smriti                 continue;
1331bf712bcSAyushi Smriti             }
1341bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
13521a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
1365fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
137a0969c70SMyung Bae             subValue->deleter = [id]() {
138a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
139a0969c70SMyung Bae             };
1401bf712bcSAyushi Smriti 
141a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
14228afb49cSJunLin Chen 
14328afb49cSJunLin Chen             updateNoOfSubscribersCount();
14428afb49cSJunLin Chen 
14528afb49cSJunLin Chen             // Update retry configuration.
14628afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
1471bf712bcSAyushi Smriti         }
1481bf712bcSAyushi Smriti     }
1491bf712bcSAyushi Smriti 
15056d2396dSEd Tanous     static void loadOldBehavior()
151b52664e2SAppaRao Puli     {
15228afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
15328afb49cSJunLin Chen         if (!eventConfigFile.good())
1541bf712bcSAyushi Smriti         {
15562598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
15628afb49cSJunLin Chen             return;
15728afb49cSJunLin Chen         }
15828afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
15928afb49cSJunLin Chen         if (jsonData.is_discarded())
1604bbf237fSAppaRao Puli         {
16162598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
16228afb49cSJunLin Chen             return;
16328afb49cSJunLin Chen         }
16428afb49cSJunLin Chen 
1650bdda665SEd Tanous         const nlohmann::json::object_t* obj =
1660bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
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             {
266*6c58a03eSAlexander Hansen                 if constexpr (BMCWEB_REDFISH_DBUS_LOG)
267*6c58a03eSAlexander Hansen                 {
268*6c58a03eSAlexander Hansen                     if (!dbusEventLogMonitor)
269*6c58a03eSAlexander Hansen                     {
270*6c58a03eSAlexander Hansen                         if constexpr (
271*6c58a03eSAlexander Hansen                             BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
272*6c58a03eSAlexander Hansen                         {
273*6c58a03eSAlexander Hansen                             dbusEventLogMonitor.emplace();
274*6c58a03eSAlexander Hansen                         }
275*6c58a03eSAlexander Hansen                     }
276*6c58a03eSAlexander Hansen                 }
277*6c58a03eSAlexander 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             {
287*6c58a03eSAlexander 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();
306*6c58a03eSAlexander 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;
364*6c58a03eSAlexander Hansen         if (eventLogSubCount > 0U)
3657d1cc387SAppaRao Puli         {
366*6c58a03eSAlexander Hansen             if constexpr (BMCWEB_REDFISH_DBUS_LOG)
367*6c58a03eSAlexander Hansen             {
368*6c58a03eSAlexander Hansen                 if (!dbusEventLogMonitor &&
369*6c58a03eSAlexander Hansen                     BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
370*6c58a03eSAlexander Hansen                 {
371*6c58a03eSAlexander Hansen                     dbusEventLogMonitor.emplace();
372*6c58a03eSAlexander Hansen                 }
373*6c58a03eSAlexander Hansen             }
374*6c58a03eSAlexander Hansen             else
375*6c58a03eSAlexander Hansen             {
376*6c58a03eSAlexander Hansen                 if (!filesystemLogMonitor)
377*6c58a03eSAlexander Hansen                 {
378*6c58a03eSAlexander Hansen                     filesystemLogMonitor.emplace(ioc);
379*6c58a03eSAlexander Hansen                 }
380*6c58a03eSAlexander Hansen             }
381*6c58a03eSAlexander Hansen         }
382*6c58a03eSAlexander Hansen         else
383*6c58a03eSAlexander Hansen         {
384*6c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
385*6c58a03eSAlexander Hansen             filesystemLogMonitor.reset();
386*6c58a03eSAlexander Hansen         }
387*6c58a03eSAlexander Hansen 
3887d1cc387SAppaRao Puli         noOfMetricReportSubscribers = metricReportSubCount;
389*6c58a03eSAlexander 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 
5836ba8c82eSsunharis_in     bool sendTestEventLog()
5840b4bdd93SAppaRao Puli     {
5855e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5860b4bdd93SAppaRao Puli         {
5870b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
5886ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
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));
6558ece0e45SEd Tanous             eventId++; // increment the eventId
65696330b99SSunitha Harish         }
65796330b99SSunitha Harish     }
65823a21a1cSEd Tanous };
659b52664e2SAppaRao Puli 
660b52664e2SAppaRao Puli } // namespace redfish
661