xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 9838eb20341568971b9543c2187372d20daf64aa)
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"
13*9838eb20SEd Tanous #include "io_context_singleton.hpp"
14d7857201SEd Tanous #include "logging.hpp"
15c0353249SWludzik, Jozef #include "metric_report.hpp"
162c6ffdb0SEd Tanous #include "ossl_random.hpp"
173ccb3adbSEd Tanous #include "persistent_data.hpp"
18d7857201SEd Tanous #include "server_sent_event.hpp"
1902c1e29fSAlexander Hansen #include "subscription.hpp"
205b90429aSEd Tanous #include "utils/time_utils.hpp"
217f4eb588SAppaRao Puli 
22f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
23d7857201SEd Tanous #include <boost/circular_buffer/base.hpp>
24b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
25d7857201SEd Tanous #include <boost/system/result.hpp>
26d7857201SEd Tanous #include <boost/url/parse.hpp>
274a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
281214b7e7SGunnar Mills 
295e44e3d8SAppaRao Puli #include <algorithm>
30d7857201SEd Tanous #include <cstdint>
31b52664e2SAppaRao Puli #include <cstdlib>
32b52664e2SAppaRao Puli #include <ctime>
33d7857201SEd Tanous #include <filesystem>
34a14c9113SEd Tanous #include <format>
351bf712bcSAyushi Smriti #include <fstream>
36b52664e2SAppaRao Puli #include <memory>
37d7857201SEd Tanous #include <optional>
38d7857201SEd Tanous #include <random>
39a14c9113SEd Tanous #include <string>
4056ba386dSMyung Bae #include <string_view>
41d7857201SEd Tanous #include <system_error>
425fe4ef35SMyung Bae #include <utility>
43d7857201SEd Tanous #include <vector>
44b52664e2SAppaRao Puli 
45b52664e2SAppaRao Puli namespace redfish
46b52664e2SAppaRao Puli {
47156d6b00SAppaRao Puli 
48156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
49156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
50156d6b00SAppaRao Puli 
511bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
521bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
531bf712bcSAyushi Smriti 
54b52664e2SAppaRao Puli class EventServiceManager
55b52664e2SAppaRao Puli {
56b52664e2SAppaRao Puli   private:
57d3a9e084SEd Tanous     bool serviceEnabled = false;
58d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
59d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
607d1cc387SAppaRao Puli 
619f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
629f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
636c58a03eSAlexander Hansen     std::optional<DbusEventLogMonitor> dbusEventLogMonitor;
642ac69850SEd Tanous     std::optional<DbusTelemetryMonitor> matchTelemetryMonitor;
657b669723SEd Tanous     std::optional<FilesystemLogWatcher> filesystemLogMonitor;
66b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
67b52664e2SAppaRao Puli         subscriptionsMap;
68b52664e2SAppaRao Puli 
699f616dd1SEd Tanous     uint64_t eventId{1};
7096330b99SSunitha Harish 
71f80a87f2SEd Tanous     struct Event
72f80a87f2SEd Tanous     {
73f80a87f2SEd Tanous         std::string id;
74f80a87f2SEd Tanous         nlohmann::json message;
75f80a87f2SEd Tanous     };
76f80a87f2SEd Tanous 
77f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
78f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
79f80a87f2SEd Tanous 
80b52664e2SAppaRao Puli   public:
819f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
829f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
839f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
849f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
85ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
869f616dd1SEd Tanous 
87*9838eb20SEd Tanous     explicit EventServiceManager()
88b52664e2SAppaRao Puli     {
89f8ca6d79SEd Tanous         // Load config from persist store.
90f8ca6d79SEd Tanous         initConfig();
91f8ca6d79SEd Tanous     }
92f8ca6d79SEd Tanous 
93*9838eb20SEd Tanous     static EventServiceManager& getInstance()
94f8ca6d79SEd Tanous     {
95*9838eb20SEd Tanous         static EventServiceManager handler;
96b52664e2SAppaRao Puli         return handler;
97b52664e2SAppaRao Puli     }
98b52664e2SAppaRao Puli 
991bf712bcSAyushi Smriti     void initConfig()
1001bf712bcSAyushi Smriti     {
10128afb49cSJunLin Chen         loadOldBehavior();
1021bf712bcSAyushi Smriti 
10328afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
10428afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
10528afb49cSJunLin Chen                 .getEventServiceConfig();
1061bf712bcSAyushi Smriti 
10728afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
10828afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
10928afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1101bf712bcSAyushi Smriti 
11128afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
11228afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1131bf712bcSAyushi Smriti         {
1145fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1155fe4ef35SMyung Bae                 it.second;
1164bbf237fSAppaRao Puli 
1176fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1185fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1191bf712bcSAyushi Smriti 
120a716aa74SEd Tanous             if (!url)
1211bf712bcSAyushi Smriti             {
12262598e31SEd Tanous                 BMCWEB_LOG_ERROR(
12362598e31SEd Tanous                     "Failed to validate and split destination url");
1241bf712bcSAyushi Smriti                 continue;
1251bf712bcSAyushi Smriti             }
1261bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
127*9838eb20SEd Tanous                 std::make_shared<Subscription>(newSub, *url, getIoContext());
1285fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
129a0969c70SMyung Bae             subValue->deleter = [id]() {
130a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
131a0969c70SMyung Bae             };
1321bf712bcSAyushi Smriti 
133a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
13428afb49cSJunLin Chen 
13528afb49cSJunLin Chen             updateNoOfSubscribersCount();
13628afb49cSJunLin Chen 
13728afb49cSJunLin Chen             // Update retry configuration.
13828afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
139fb546105SMyung Bae 
140fb546105SMyung Bae             // schedule a heartbeat if sendHeartbeat was set to true
141fb546105SMyung Bae             if (subValue->userSub->sendHeartbeat)
142fb546105SMyung Bae             {
143fb546105SMyung Bae                 subValue->scheduleNextHeartbeatEvent();
144fb546105SMyung Bae             }
1451bf712bcSAyushi Smriti         }
1461bf712bcSAyushi Smriti     }
1471bf712bcSAyushi Smriti 
14856d2396dSEd Tanous     static void loadOldBehavior()
149b52664e2SAppaRao Puli     {
15028afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
15128afb49cSJunLin Chen         if (!eventConfigFile.good())
1521bf712bcSAyushi Smriti         {
15362598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
15428afb49cSJunLin Chen             return;
15528afb49cSJunLin Chen         }
15628afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
15728afb49cSJunLin Chen         if (jsonData.is_discarded())
1584bbf237fSAppaRao Puli         {
15962598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
16028afb49cSJunLin Chen             return;
16128afb49cSJunLin Chen         }
16228afb49cSJunLin Chen 
1630bdda665SEd Tanous         const nlohmann::json::object_t* obj =
1640bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
1651c588de9SAbiola Asojo         if (obj == nullptr)
1661c588de9SAbiola Asojo         {
1671c588de9SAbiola Asojo             return;
1681c588de9SAbiola Asojo         }
1690bdda665SEd Tanous         for (const auto& item : *obj)
17028afb49cSJunLin Chen         {
1710bdda665SEd Tanous             if (item.first == "Configuration")
17228afb49cSJunLin Chen             {
17328afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
17428afb49cSJunLin Chen                     .getEventServiceConfig()
1750bdda665SEd Tanous                     .fromJson(item.second);
17628afb49cSJunLin Chen             }
1770bdda665SEd Tanous             else if (item.first == "Subscriptions")
17828afb49cSJunLin Chen             {
1790bdda665SEd Tanous                 for (const auto& elem : item.second)
18028afb49cSJunLin Chen                 {
1814b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
18228afb49cSJunLin Chen                         newSubscription =
18328afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
18428afb49cSJunLin Chen                                                                         true);
1854b712a29SEd Tanous                     if (!newSubscription)
18628afb49cSJunLin Chen                     {
18762598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
18862598e31SEd Tanous                                          "from old persistent store");
1894bbf237fSAppaRao Puli                         continue;
1904bbf237fSAppaRao Puli                     }
1914b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
1924b712a29SEd Tanous                         *newSubscription;
1931bf712bcSAyushi Smriti 
19428afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
19528afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
1961bf712bcSAyushi Smriti 
19728afb49cSJunLin Chen                     std::string id;
1981bf712bcSAyushi Smriti 
19928afb49cSJunLin Chen                     int retry = 3;
200e662eae8SEd Tanous                     while (retry != 0)
2011bf712bcSAyushi Smriti                     {
20228afb49cSJunLin Chen                         id = std::to_string(dist(gen));
20328afb49cSJunLin Chen                         if (gen.error())
2047d1cc387SAppaRao Puli                         {
20528afb49cSJunLin Chen                             retry = 0;
20628afb49cSJunLin Chen                             break;
20728afb49cSJunLin Chen                         }
2084b712a29SEd Tanous                         newSub.id = id;
20928afb49cSJunLin Chen                         auto inserted =
21028afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
2115fe4ef35SMyung Bae                                 .subscriptionsConfigMap.insert(std::pair(
2125fe4ef35SMyung Bae                                     id, std::make_shared<
2135fe4ef35SMyung Bae                                             persistent_data::UserSubscription>(
2145fe4ef35SMyung Bae                                             newSub)));
21528afb49cSJunLin Chen                         if (inserted.second)
21628afb49cSJunLin Chen                         {
21728afb49cSJunLin Chen                             break;
21828afb49cSJunLin Chen                         }
21928afb49cSJunLin Chen                         --retry;
2207d1cc387SAppaRao Puli                     }
2217d1cc387SAppaRao Puli 
22228afb49cSJunLin Chen                     if (retry <= 0)
22328afb49cSJunLin Chen                     {
22462598e31SEd Tanous                         BMCWEB_LOG_ERROR(
22562598e31SEd Tanous                             "Failed to generate random number from old "
22662598e31SEd Tanous                             "persistent store");
22728afb49cSJunLin Chen                         continue;
22828afb49cSJunLin Chen                     }
22928afb49cSJunLin Chen                 }
23028afb49cSJunLin Chen             }
23128afb49cSJunLin Chen 
23228afb49cSJunLin Chen             persistent_data::getConfig().writeData();
2334c521c3cSEd Tanous             std::error_code ec;
2344c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
2354c521c3cSEd Tanous             if (ec)
2364c521c3cSEd Tanous             {
2374c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
2384c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
2394c521c3cSEd Tanous             }
2404c521c3cSEd Tanous             else
2414c521c3cSEd Tanous             {
24262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
24328afb49cSJunLin Chen             }
24428afb49cSJunLin Chen         }
2454c521c3cSEd Tanous     }
24628afb49cSJunLin Chen 
2479eb808c1SEd Tanous     void updateSubscriptionData() const
24828afb49cSJunLin Chen     {
24928afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25028afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
25128afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25228afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
25328afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25428afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
25528afb49cSJunLin Chen 
25628afb49cSJunLin Chen         persistent_data::getConfig().writeData();
25728afb49cSJunLin Chen     }
25828afb49cSJunLin Chen 
25928afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
2607d1cc387SAppaRao Puli     {
2617d1cc387SAppaRao Puli         bool updateConfig = false;
262fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
2637d1cc387SAppaRao Puli 
2642ac69850SEd Tanous         if (serviceEnabled)
2657d1cc387SAppaRao Puli         {
2667b669723SEd Tanous             if (noOfEventLogSubscribers > 0U)
2677b669723SEd Tanous             {
2686c58a03eSAlexander Hansen                 if constexpr (BMCWEB_REDFISH_DBUS_LOG)
2696c58a03eSAlexander Hansen                 {
2706c58a03eSAlexander Hansen                     if (!dbusEventLogMonitor)
2716c58a03eSAlexander Hansen                     {
2726c58a03eSAlexander Hansen                         if constexpr (
2736c58a03eSAlexander Hansen                             BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
2746c58a03eSAlexander Hansen                         {
2756c58a03eSAlexander Hansen                             dbusEventLogMonitor.emplace();
2766c58a03eSAlexander Hansen                         }
2776c58a03eSAlexander Hansen                     }
2786c58a03eSAlexander Hansen                 }
2796c58a03eSAlexander Hansen                 else
2807b669723SEd Tanous                 {
2817b669723SEd Tanous                     if (!filesystemLogMonitor)
2827b669723SEd Tanous                     {
283*9838eb20SEd Tanous                         filesystemLogMonitor.emplace(getIoContext());
2847b669723SEd Tanous                     }
2857b669723SEd Tanous                 }
2867b669723SEd Tanous             }
2877b669723SEd Tanous             else
2887b669723SEd Tanous             {
2896c58a03eSAlexander Hansen                 dbusEventLogMonitor.reset();
2907b669723SEd Tanous                 filesystemLogMonitor.reset();
2917b669723SEd Tanous             }
2927b669723SEd Tanous 
2932ac69850SEd Tanous             if (noOfMetricReportSubscribers > 0U)
2947d1cc387SAppaRao Puli             {
2952ac69850SEd Tanous                 if (!matchTelemetryMonitor)
2962ac69850SEd Tanous                 {
2972ac69850SEd Tanous                     matchTelemetryMonitor.emplace();
2982ac69850SEd Tanous                 }
2997d1cc387SAppaRao Puli             }
3007d1cc387SAppaRao Puli             else
3017d1cc387SAppaRao Puli             {
3022ac69850SEd Tanous                 matchTelemetryMonitor.reset();
3037d1cc387SAppaRao Puli             }
3042ac69850SEd Tanous         }
3052ac69850SEd Tanous         else
3062ac69850SEd Tanous         {
3072ac69850SEd Tanous             matchTelemetryMonitor.reset();
3086c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
3097b669723SEd Tanous             filesystemLogMonitor.reset();
3102ac69850SEd Tanous         }
3112ac69850SEd Tanous 
3122ac69850SEd Tanous         if (serviceEnabled != cfg.enabled)
3132ac69850SEd Tanous         {
3142ac69850SEd Tanous             serviceEnabled = cfg.enabled;
3157d1cc387SAppaRao Puli             updateConfig = true;
3167d1cc387SAppaRao Puli         }
3177d1cc387SAppaRao Puli 
31828afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
3197d1cc387SAppaRao Puli         {
32028afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
3217d1cc387SAppaRao Puli             updateConfig = true;
322fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3237d1cc387SAppaRao Puli         }
3247d1cc387SAppaRao Puli 
32528afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
3267d1cc387SAppaRao Puli         {
32728afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
3287d1cc387SAppaRao Puli             updateConfig = true;
329fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3307d1cc387SAppaRao Puli         }
3317d1cc387SAppaRao Puli 
3327d1cc387SAppaRao Puli         if (updateConfig)
3337d1cc387SAppaRao Puli         {
3347d1cc387SAppaRao Puli             updateSubscriptionData();
3357d1cc387SAppaRao Puli         }
336fe44eb0bSAyushi Smriti 
337fe44eb0bSAyushi Smriti         if (updateRetryCfg)
338fe44eb0bSAyushi Smriti         {
339fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
340fe44eb0bSAyushi Smriti             for (const auto& it :
341fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
342fe44eb0bSAyushi Smriti             {
3435e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
3445e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
345fe44eb0bSAyushi Smriti             }
346fe44eb0bSAyushi Smriti         }
3477d1cc387SAppaRao Puli     }
3487d1cc387SAppaRao Puli 
3497d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
3507d1cc387SAppaRao Puli     {
3517d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
3527d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
3537d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
3547d1cc387SAppaRao Puli         {
3557d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
3565fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
3577d1cc387SAppaRao Puli             {
3587d1cc387SAppaRao Puli                 eventLogSubCount++;
3597d1cc387SAppaRao Puli             }
3605fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
3617d1cc387SAppaRao Puli             {
3627d1cc387SAppaRao Puli                 metricReportSubCount++;
3637d1cc387SAppaRao Puli             }
3647d1cc387SAppaRao Puli         }
3657d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
3666c58a03eSAlexander Hansen         if (eventLogSubCount > 0U)
3677d1cc387SAppaRao Puli         {
3686c58a03eSAlexander Hansen             if constexpr (BMCWEB_REDFISH_DBUS_LOG)
3696c58a03eSAlexander Hansen             {
3706c58a03eSAlexander Hansen                 if (!dbusEventLogMonitor &&
3716c58a03eSAlexander Hansen                     BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
3726c58a03eSAlexander Hansen                 {
3736c58a03eSAlexander Hansen                     dbusEventLogMonitor.emplace();
3746c58a03eSAlexander Hansen                 }
3756c58a03eSAlexander Hansen             }
3766c58a03eSAlexander Hansen             else
3776c58a03eSAlexander Hansen             {
3786c58a03eSAlexander Hansen                 if (!filesystemLogMonitor)
3796c58a03eSAlexander Hansen                 {
380*9838eb20SEd Tanous                     filesystemLogMonitor.emplace(getIoContext());
3816c58a03eSAlexander Hansen                 }
3826c58a03eSAlexander Hansen             }
3836c58a03eSAlexander Hansen         }
3846c58a03eSAlexander Hansen         else
3856c58a03eSAlexander Hansen         {
3866c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
3876c58a03eSAlexander Hansen             filesystemLogMonitor.reset();
3886c58a03eSAlexander Hansen         }
3896c58a03eSAlexander Hansen 
3907d1cc387SAppaRao Puli         noOfMetricReportSubscribers = metricReportSubCount;
3916c58a03eSAlexander Hansen         if (metricReportSubCount > 0U)
3927d1cc387SAppaRao Puli         {
3932ac69850SEd Tanous             if (!matchTelemetryMonitor)
3942ac69850SEd Tanous             {
3952ac69850SEd Tanous                 matchTelemetryMonitor.emplace();
3962ac69850SEd Tanous             }
3977d1cc387SAppaRao Puli         }
3987d1cc387SAppaRao Puli         else
3997d1cc387SAppaRao Puli         {
4002ac69850SEd Tanous             matchTelemetryMonitor.reset();
4017d1cc387SAppaRao Puli         }
4027d1cc387SAppaRao Puli     }
4037d1cc387SAppaRao Puli 
404b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
405b52664e2SAppaRao Puli     {
406b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
407b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
408b52664e2SAppaRao Puli         {
40962598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
410b52664e2SAppaRao Puli             return nullptr;
411b52664e2SAppaRao Puli         }
412b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
413b52664e2SAppaRao Puli         return subValue;
414b52664e2SAppaRao Puli     }
415b52664e2SAppaRao Puli 
416f80a87f2SEd Tanous     std::string
417f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
418b52664e2SAppaRao Puli     {
419fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
420fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
421fc76b8acSEd Tanous 
422b52664e2SAppaRao Puli         std::string id;
423b52664e2SAppaRao Puli 
424b52664e2SAppaRao Puli         int retry = 3;
425e662eae8SEd Tanous         while (retry != 0)
426b52664e2SAppaRao Puli         {
427fc76b8acSEd Tanous             id = std::to_string(dist(gen));
428fc76b8acSEd Tanous             if (gen.error())
429fc76b8acSEd Tanous             {
430fc76b8acSEd Tanous                 retry = 0;
431fc76b8acSEd Tanous                 break;
432fc76b8acSEd Tanous             }
433b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
434b52664e2SAppaRao Puli             if (inserted.second)
435b52664e2SAppaRao Puli             {
436b52664e2SAppaRao Puli                 break;
437b52664e2SAppaRao Puli             }
438b52664e2SAppaRao Puli             --retry;
43923a21a1cSEd Tanous         }
440b52664e2SAppaRao Puli 
441b52664e2SAppaRao Puli         if (retry <= 0)
442b52664e2SAppaRao Puli         {
44362598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
444abb93cddSEd Tanous             return "";
445b52664e2SAppaRao Puli         }
446b52664e2SAppaRao Puli 
44756ba386dSMyung Bae         // Set Subscription ID for back trace
4485fe4ef35SMyung Bae         subValue->userSub->id = id;
449a14c9113SEd Tanous 
45028afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4515fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
45228afb49cSJunLin Chen 
4537d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
4541bf712bcSAyushi Smriti 
455fe44eb0bSAyushi Smriti         // Update retry configuration.
456fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
457fe44eb0bSAyushi Smriti 
458f80a87f2SEd Tanous         return id;
459f80a87f2SEd Tanous     }
460f80a87f2SEd Tanous 
461f80a87f2SEd Tanous     std::string
462f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
463f80a87f2SEd Tanous                            std::string_view lastEventId)
464f80a87f2SEd Tanous     {
465f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
466f80a87f2SEd Tanous 
467f80a87f2SEd Tanous         if (!lastEventId.empty())
468f80a87f2SEd Tanous         {
469f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
470f80a87f2SEd Tanous                             lastEventId);
471f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
472f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
473f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
474f80a87f2SEd Tanous                                  return event.id == lastEventId;
475f80a87f2SEd Tanous                              });
476f80a87f2SEd Tanous             // Can't find a matching ID
477f80a87f2SEd Tanous             if (lastEvent == messages.end())
478f80a87f2SEd Tanous             {
479f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
480f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
4816d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
482f80a87f2SEd Tanous                 lastEvent = messages.begin();
483f80a87f2SEd Tanous             }
484f80a87f2SEd Tanous             else
485f80a87f2SEd Tanous             {
486f80a87f2SEd Tanous                 // Skip the last event the user already has
487f80a87f2SEd Tanous                 lastEvent++;
488f80a87f2SEd Tanous             }
489f80a87f2SEd Tanous 
490f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
491f80a87f2SEd Tanous                      lastEvent;
492f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
493f80a87f2SEd Tanous             {
4946d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
495f80a87f2SEd Tanous             }
496f80a87f2SEd Tanous         }
497f80a87f2SEd Tanous         return id;
498f80a87f2SEd Tanous     }
499f80a87f2SEd Tanous 
500f80a87f2SEd Tanous     std::string
501f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
502f80a87f2SEd Tanous     {
503f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
504a0969c70SMyung Bae         subValue->deleter = [id]() {
505a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
506a0969c70SMyung Bae         };
507f80a87f2SEd Tanous         updateSubscriptionData();
508b52664e2SAppaRao Puli         return id;
509b52664e2SAppaRao Puli     }
510b52664e2SAppaRao Puli 
511b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
512b52664e2SAppaRao Puli     {
513b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
51455f79e6fSEd Tanous         return obj != subscriptionsMap.end();
515b52664e2SAppaRao Puli     }
516b52664e2SAppaRao Puli 
5174b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
518b52664e2SAppaRao Puli     {
519b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
5204b712a29SEd Tanous         if (obj == subscriptionsMap.end())
521b52664e2SAppaRao Puli         {
5224b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
5234b712a29SEd Tanous             return false;
5244b712a29SEd Tanous         }
525b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
5264b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
5274b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
5284b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
5294b712a29SEd Tanous         {
5304b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
5314b712a29SEd Tanous             return true;
5324b712a29SEd Tanous         }
53328afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
5344b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
5357d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
536b52664e2SAppaRao Puli         updateSubscriptionData();
5374b712a29SEd Tanous 
5384b712a29SEd Tanous         return true;
539b52664e2SAppaRao Puli     }
540b52664e2SAppaRao Puli 
5415e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
5425e44e3d8SAppaRao Puli     {
543bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
5445e44e3d8SAppaRao Puli         {
545bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
5465e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
5475e44e3d8SAppaRao Puli             if (entryIsThisConn)
5485e44e3d8SAppaRao Puli             {
5495e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
5505fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
551bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
5525e44e3d8SAppaRao Puli                 return;
5535e44e3d8SAppaRao Puli             }
554bdbfae2aSEd Tanous             it++;
5555e44e3d8SAppaRao Puli         }
5565e44e3d8SAppaRao Puli     }
5575e44e3d8SAppaRao Puli 
5585e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
559b52664e2SAppaRao Puli     {
560b52664e2SAppaRao Puli         return subscriptionsMap.size();
561b52664e2SAppaRao Puli     }
562b52664e2SAppaRao Puli 
5635e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
5645e44e3d8SAppaRao Puli     {
5653544d2a7SEd Tanous         auto size = std::ranges::count_if(
5663544d2a7SEd Tanous             subscriptionsMap,
5675e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
5685e44e3d8SAppaRao Puli                    entry) {
5695fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
5704b712a29SEd Tanous                         subscriptionTypeSSE);
5715e44e3d8SAppaRao Puli             });
5725e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
5735e44e3d8SAppaRao Puli     }
5745e44e3d8SAppaRao Puli 
575b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
576b52664e2SAppaRao Puli     {
577b52664e2SAppaRao Puli         std::vector<std::string> idList;
578b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
579b52664e2SAppaRao Puli         {
580b52664e2SAppaRao Puli             idList.emplace_back(it.first);
581b52664e2SAppaRao Puli         }
582b52664e2SAppaRao Puli         return idList;
583b52664e2SAppaRao Puli     }
584b52664e2SAppaRao Puli 
58581ee0e74SChandramohan Harkude     bool sendTestEventLog(TestEvent& testEvent)
5860b4bdd93SAppaRao Puli     {
5875e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5880b4bdd93SAppaRao Puli         {
5890b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
59081ee0e74SChandramohan Harkude             if (!entry->sendTestEventLog(testEvent))
5916ba8c82eSsunharis_in             {
5926ba8c82eSsunharis_in                 return false;
5930b4bdd93SAppaRao Puli             }
5940b4bdd93SAppaRao Puli         }
5956ba8c82eSsunharis_in         return true;
5966ba8c82eSsunharis_in     }
597e9a14131SAppaRao Puli 
5983433b03aSEd Tanous     static void
5993433b03aSEd Tanous         sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords)
6003433b03aSEd Tanous     {
6013433b03aSEd Tanous         for (const auto& it :
6023433b03aSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
6033433b03aSEd Tanous         {
6043433b03aSEd Tanous             Subscription& entry = *it.second;
6053433b03aSEd Tanous             entry.filterAndSendEventLogs(eventRecords);
6063433b03aSEd Tanous         }
6073433b03aSEd Tanous     }
6083433b03aSEd Tanous 
609b26ff34dSEd Tanous     static void sendTelemetryReportToSubs(
610b26ff34dSEd Tanous         const std::string& reportId, const telemetry::TimestampReadings& var)
611b26ff34dSEd Tanous     {
612b26ff34dSEd Tanous         for (const auto& it :
613b26ff34dSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
614b26ff34dSEd Tanous         {
615b26ff34dSEd Tanous             Subscription& entry = *it.second;
616b26ff34dSEd Tanous             entry.filterAndSendReports(reportId, var);
617b26ff34dSEd Tanous         }
618b26ff34dSEd Tanous     }
619b26ff34dSEd Tanous 
620f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
621f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
62296330b99SSunitha Harish     {
623613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
624f80a87f2SEd Tanous 
625613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
626613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
627613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
628613dabeaSEd Tanous 
629f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
630788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
63196330b99SSunitha Harish 
632f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
633f80a87f2SEd Tanous 
634f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
63596330b99SSunitha Harish         {
636f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
6375fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
6385fe4ef35SMyung Bae                                     resourceType))
63996330b99SSunitha Harish             {
640f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
641f80a87f2SEd Tanous                 continue;
64296330b99SSunitha Harish             }
643f80a87f2SEd Tanous 
644f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
645f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
646f80a87f2SEd Tanous 
647613dabeaSEd Tanous             nlohmann::json msgJson;
648613dabeaSEd Tanous 
649613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
650613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
651613dabeaSEd Tanous             msgJson["Id"] = eventId;
652f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
653f52c03c1SCarson Labrado 
654f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
655f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
6566d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
65796330b99SSunitha Harish         }
65821c0ba6eSMyung Bae         eventId++; // increment the eventId
65996330b99SSunitha Harish     }
66023a21a1cSEd Tanous };
661b52664e2SAppaRao Puli 
662b52664e2SAppaRao Puli } // namespace redfish
663