xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision d78572018fc2022091ff8b8eb5a7fef2172ba3d6)
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
5*d7857201SEd Tanous #include "bmcweb_config.h"
6*d7857201SEd Tanous 
7b26ff34dSEd Tanous #include "dbus_log_watcher.hpp"
83ccb3adbSEd Tanous #include "error_messages.hpp"
9*d7857201SEd 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*d7857201SEd Tanous #include "logging.hpp"
14c0353249SWludzik, Jozef #include "metric_report.hpp"
152c6ffdb0SEd Tanous #include "ossl_random.hpp"
163ccb3adbSEd Tanous #include "persistent_data.hpp"
17*d7857201SEd Tanous #include "server_sent_event.hpp"
1802c1e29fSAlexander Hansen #include "subscription.hpp"
195b90429aSEd Tanous #include "utils/time_utils.hpp"
207f4eb588SAppaRao Puli 
21fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
22f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
23*d7857201SEd Tanous #include <boost/circular_buffer/base.hpp>
24b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
25*d7857201SEd Tanous #include <boost/system/result.hpp>
26*d7857201SEd Tanous #include <boost/url/parse.hpp>
274a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
281214b7e7SGunnar Mills 
295e44e3d8SAppaRao Puli #include <algorithm>
30*d7857201SEd Tanous #include <cstdint>
31b52664e2SAppaRao Puli #include <cstdlib>
32b52664e2SAppaRao Puli #include <ctime>
33*d7857201SEd Tanous #include <filesystem>
34a14c9113SEd Tanous #include <format>
351bf712bcSAyushi Smriti #include <fstream>
36b52664e2SAppaRao Puli #include <memory>
37*d7857201SEd Tanous #include <optional>
38*d7857201SEd Tanous #include <random>
39a14c9113SEd Tanous #include <string>
4056ba386dSMyung Bae #include <string_view>
41*d7857201SEd Tanous #include <system_error>
425fe4ef35SMyung Bae #include <utility>
43*d7857201SEd 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 
80f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
81f8ca6d79SEd Tanous 
82b52664e2SAppaRao Puli   public:
839f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
849f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
859f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
869f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
87ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
889f616dd1SEd Tanous 
89f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
90b52664e2SAppaRao Puli     {
91f8ca6d79SEd Tanous         // Load config from persist store.
92f8ca6d79SEd Tanous         initConfig();
93f8ca6d79SEd Tanous     }
94f8ca6d79SEd Tanous 
95f8ca6d79SEd Tanous     static EventServiceManager&
96f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
97f8ca6d79SEd Tanous     {
98f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
99b52664e2SAppaRao Puli         return handler;
100b52664e2SAppaRao Puli     }
101b52664e2SAppaRao Puli 
1021bf712bcSAyushi Smriti     void initConfig()
1031bf712bcSAyushi Smriti     {
10428afb49cSJunLin Chen         loadOldBehavior();
1051bf712bcSAyushi Smriti 
10628afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
10728afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
10828afb49cSJunLin Chen                 .getEventServiceConfig();
1091bf712bcSAyushi Smriti 
11028afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
11128afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
11228afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1131bf712bcSAyushi Smriti 
11428afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
11528afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1161bf712bcSAyushi Smriti         {
1175fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1185fe4ef35SMyung Bae                 it.second;
1194bbf237fSAppaRao Puli 
1206fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1215fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1221bf712bcSAyushi Smriti 
123a716aa74SEd Tanous             if (!url)
1241bf712bcSAyushi Smriti             {
12562598e31SEd Tanous                 BMCWEB_LOG_ERROR(
12662598e31SEd Tanous                     "Failed to validate and split destination url");
1271bf712bcSAyushi Smriti                 continue;
1281bf712bcSAyushi Smriti             }
1291bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
13021a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
1315fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
132a0969c70SMyung Bae             subValue->deleter = [id]() {
133a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
134a0969c70SMyung Bae             };
1351bf712bcSAyushi Smriti 
136a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
13728afb49cSJunLin Chen 
13828afb49cSJunLin Chen             updateNoOfSubscribersCount();
13928afb49cSJunLin Chen 
14028afb49cSJunLin Chen             // Update retry configuration.
14128afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
142fb546105SMyung Bae 
143fb546105SMyung Bae             // schedule a heartbeat if sendHeartbeat was set to true
144fb546105SMyung Bae             if (subValue->userSub->sendHeartbeat)
145fb546105SMyung Bae             {
146fb546105SMyung Bae                 subValue->scheduleNextHeartbeatEvent();
147fb546105SMyung Bae             }
1481bf712bcSAyushi Smriti         }
1491bf712bcSAyushi Smriti     }
1501bf712bcSAyushi Smriti 
15156d2396dSEd Tanous     static void loadOldBehavior()
152b52664e2SAppaRao Puli     {
15328afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
15428afb49cSJunLin Chen         if (!eventConfigFile.good())
1551bf712bcSAyushi Smriti         {
15662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
15728afb49cSJunLin Chen             return;
15828afb49cSJunLin Chen         }
15928afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
16028afb49cSJunLin Chen         if (jsonData.is_discarded())
1614bbf237fSAppaRao Puli         {
16262598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
16328afb49cSJunLin Chen             return;
16428afb49cSJunLin Chen         }
16528afb49cSJunLin Chen 
1660bdda665SEd Tanous         const nlohmann::json::object_t* obj =
1670bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
1681c588de9SAbiola Asojo         if (obj == nullptr)
1691c588de9SAbiola Asojo         {
1701c588de9SAbiola Asojo             return;
1711c588de9SAbiola Asojo         }
1720bdda665SEd Tanous         for (const auto& item : *obj)
17328afb49cSJunLin Chen         {
1740bdda665SEd Tanous             if (item.first == "Configuration")
17528afb49cSJunLin Chen             {
17628afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
17728afb49cSJunLin Chen                     .getEventServiceConfig()
1780bdda665SEd Tanous                     .fromJson(item.second);
17928afb49cSJunLin Chen             }
1800bdda665SEd Tanous             else if (item.first == "Subscriptions")
18128afb49cSJunLin Chen             {
1820bdda665SEd Tanous                 for (const auto& elem : item.second)
18328afb49cSJunLin Chen                 {
1844b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
18528afb49cSJunLin Chen                         newSubscription =
18628afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
18728afb49cSJunLin Chen                                                                         true);
1884b712a29SEd Tanous                     if (!newSubscription)
18928afb49cSJunLin Chen                     {
19062598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
19162598e31SEd Tanous                                          "from old persistent store");
1924bbf237fSAppaRao Puli                         continue;
1934bbf237fSAppaRao Puli                     }
1944b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
1954b712a29SEd Tanous                         *newSubscription;
1961bf712bcSAyushi Smriti 
19728afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
19828afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
1991bf712bcSAyushi Smriti 
20028afb49cSJunLin Chen                     std::string id;
2011bf712bcSAyushi Smriti 
20228afb49cSJunLin Chen                     int retry = 3;
203e662eae8SEd Tanous                     while (retry != 0)
2041bf712bcSAyushi Smriti                     {
20528afb49cSJunLin Chen                         id = std::to_string(dist(gen));
20628afb49cSJunLin Chen                         if (gen.error())
2077d1cc387SAppaRao Puli                         {
20828afb49cSJunLin Chen                             retry = 0;
20928afb49cSJunLin Chen                             break;
21028afb49cSJunLin Chen                         }
2114b712a29SEd Tanous                         newSub.id = id;
21228afb49cSJunLin Chen                         auto inserted =
21328afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
2145fe4ef35SMyung Bae                                 .subscriptionsConfigMap.insert(std::pair(
2155fe4ef35SMyung Bae                                     id, std::make_shared<
2165fe4ef35SMyung Bae                                             persistent_data::UserSubscription>(
2175fe4ef35SMyung Bae                                             newSub)));
21828afb49cSJunLin Chen                         if (inserted.second)
21928afb49cSJunLin Chen                         {
22028afb49cSJunLin Chen                             break;
22128afb49cSJunLin Chen                         }
22228afb49cSJunLin Chen                         --retry;
2237d1cc387SAppaRao Puli                     }
2247d1cc387SAppaRao Puli 
22528afb49cSJunLin Chen                     if (retry <= 0)
22628afb49cSJunLin Chen                     {
22762598e31SEd Tanous                         BMCWEB_LOG_ERROR(
22862598e31SEd Tanous                             "Failed to generate random number from old "
22962598e31SEd Tanous                             "persistent store");
23028afb49cSJunLin Chen                         continue;
23128afb49cSJunLin Chen                     }
23228afb49cSJunLin Chen                 }
23328afb49cSJunLin Chen             }
23428afb49cSJunLin Chen 
23528afb49cSJunLin Chen             persistent_data::getConfig().writeData();
2364c521c3cSEd Tanous             std::error_code ec;
2374c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
2384c521c3cSEd Tanous             if (ec)
2394c521c3cSEd Tanous             {
2404c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
2414c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
2424c521c3cSEd Tanous             }
2434c521c3cSEd Tanous             else
2444c521c3cSEd Tanous             {
24562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
24628afb49cSJunLin Chen             }
24728afb49cSJunLin Chen         }
2484c521c3cSEd Tanous     }
24928afb49cSJunLin Chen 
2509eb808c1SEd Tanous     void updateSubscriptionData() const
25128afb49cSJunLin Chen     {
25228afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25328afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
25428afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25528afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
25628afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25728afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
25828afb49cSJunLin Chen 
25928afb49cSJunLin Chen         persistent_data::getConfig().writeData();
26028afb49cSJunLin Chen     }
26128afb49cSJunLin Chen 
26228afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
2637d1cc387SAppaRao Puli     {
2647d1cc387SAppaRao Puli         bool updateConfig = false;
265fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
2667d1cc387SAppaRao Puli 
2672ac69850SEd Tanous         if (serviceEnabled)
2687d1cc387SAppaRao Puli         {
2697b669723SEd Tanous             if (noOfEventLogSubscribers > 0U)
2707b669723SEd Tanous             {
2716c58a03eSAlexander Hansen                 if constexpr (BMCWEB_REDFISH_DBUS_LOG)
2726c58a03eSAlexander Hansen                 {
2736c58a03eSAlexander Hansen                     if (!dbusEventLogMonitor)
2746c58a03eSAlexander Hansen                     {
2756c58a03eSAlexander Hansen                         if constexpr (
2766c58a03eSAlexander Hansen                             BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
2776c58a03eSAlexander Hansen                         {
2786c58a03eSAlexander Hansen                             dbusEventLogMonitor.emplace();
2796c58a03eSAlexander Hansen                         }
2806c58a03eSAlexander Hansen                     }
2816c58a03eSAlexander Hansen                 }
2826c58a03eSAlexander Hansen                 else
2837b669723SEd Tanous                 {
2847b669723SEd Tanous                     if (!filesystemLogMonitor)
2857b669723SEd Tanous                     {
2867b669723SEd Tanous                         filesystemLogMonitor.emplace(ioc);
2877b669723SEd Tanous                     }
2887b669723SEd Tanous                 }
2897b669723SEd Tanous             }
2907b669723SEd Tanous             else
2917b669723SEd Tanous             {
2926c58a03eSAlexander Hansen                 dbusEventLogMonitor.reset();
2937b669723SEd Tanous                 filesystemLogMonitor.reset();
2947b669723SEd Tanous             }
2957b669723SEd Tanous 
2962ac69850SEd Tanous             if (noOfMetricReportSubscribers > 0U)
2977d1cc387SAppaRao Puli             {
2982ac69850SEd Tanous                 if (!matchTelemetryMonitor)
2992ac69850SEd Tanous                 {
3002ac69850SEd Tanous                     matchTelemetryMonitor.emplace();
3012ac69850SEd Tanous                 }
3027d1cc387SAppaRao Puli             }
3037d1cc387SAppaRao Puli             else
3047d1cc387SAppaRao Puli             {
3052ac69850SEd Tanous                 matchTelemetryMonitor.reset();
3067d1cc387SAppaRao Puli             }
3072ac69850SEd Tanous         }
3082ac69850SEd Tanous         else
3092ac69850SEd Tanous         {
3102ac69850SEd Tanous             matchTelemetryMonitor.reset();
3116c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
3127b669723SEd Tanous             filesystemLogMonitor.reset();
3132ac69850SEd Tanous         }
3142ac69850SEd Tanous 
3152ac69850SEd Tanous         if (serviceEnabled != cfg.enabled)
3162ac69850SEd Tanous         {
3172ac69850SEd Tanous             serviceEnabled = cfg.enabled;
3187d1cc387SAppaRao Puli             updateConfig = true;
3197d1cc387SAppaRao Puli         }
3207d1cc387SAppaRao Puli 
32128afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
3227d1cc387SAppaRao Puli         {
32328afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
3247d1cc387SAppaRao Puli             updateConfig = true;
325fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3267d1cc387SAppaRao Puli         }
3277d1cc387SAppaRao Puli 
32828afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
3297d1cc387SAppaRao Puli         {
33028afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
3317d1cc387SAppaRao Puli             updateConfig = true;
332fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3337d1cc387SAppaRao Puli         }
3347d1cc387SAppaRao Puli 
3357d1cc387SAppaRao Puli         if (updateConfig)
3367d1cc387SAppaRao Puli         {
3377d1cc387SAppaRao Puli             updateSubscriptionData();
3387d1cc387SAppaRao Puli         }
339fe44eb0bSAyushi Smriti 
340fe44eb0bSAyushi Smriti         if (updateRetryCfg)
341fe44eb0bSAyushi Smriti         {
342fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
343fe44eb0bSAyushi Smriti             for (const auto& it :
344fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
345fe44eb0bSAyushi Smriti             {
3465e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
3475e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
348fe44eb0bSAyushi Smriti             }
349fe44eb0bSAyushi Smriti         }
3507d1cc387SAppaRao Puli     }
3517d1cc387SAppaRao Puli 
3527d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
3537d1cc387SAppaRao Puli     {
3547d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
3557d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
3567d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
3577d1cc387SAppaRao Puli         {
3587d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
3595fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
3607d1cc387SAppaRao Puli             {
3617d1cc387SAppaRao Puli                 eventLogSubCount++;
3627d1cc387SAppaRao Puli             }
3635fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
3647d1cc387SAppaRao Puli             {
3657d1cc387SAppaRao Puli                 metricReportSubCount++;
3667d1cc387SAppaRao Puli             }
3677d1cc387SAppaRao Puli         }
3687d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
3696c58a03eSAlexander Hansen         if (eventLogSubCount > 0U)
3707d1cc387SAppaRao Puli         {
3716c58a03eSAlexander Hansen             if constexpr (BMCWEB_REDFISH_DBUS_LOG)
3726c58a03eSAlexander Hansen             {
3736c58a03eSAlexander Hansen                 if (!dbusEventLogMonitor &&
3746c58a03eSAlexander Hansen                     BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
3756c58a03eSAlexander Hansen                 {
3766c58a03eSAlexander Hansen                     dbusEventLogMonitor.emplace();
3776c58a03eSAlexander Hansen                 }
3786c58a03eSAlexander Hansen             }
3796c58a03eSAlexander Hansen             else
3806c58a03eSAlexander Hansen             {
3816c58a03eSAlexander Hansen                 if (!filesystemLogMonitor)
3826c58a03eSAlexander Hansen                 {
3836c58a03eSAlexander Hansen                     filesystemLogMonitor.emplace(ioc);
3846c58a03eSAlexander Hansen                 }
3856c58a03eSAlexander Hansen             }
3866c58a03eSAlexander Hansen         }
3876c58a03eSAlexander Hansen         else
3886c58a03eSAlexander Hansen         {
3896c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
3906c58a03eSAlexander Hansen             filesystemLogMonitor.reset();
3916c58a03eSAlexander Hansen         }
3926c58a03eSAlexander Hansen 
3937d1cc387SAppaRao Puli         noOfMetricReportSubscribers = metricReportSubCount;
3946c58a03eSAlexander Hansen         if (metricReportSubCount > 0U)
3957d1cc387SAppaRao Puli         {
3962ac69850SEd Tanous             if (!matchTelemetryMonitor)
3972ac69850SEd Tanous             {
3982ac69850SEd Tanous                 matchTelemetryMonitor.emplace();
3992ac69850SEd Tanous             }
4007d1cc387SAppaRao Puli         }
4017d1cc387SAppaRao Puli         else
4027d1cc387SAppaRao Puli         {
4032ac69850SEd Tanous             matchTelemetryMonitor.reset();
4047d1cc387SAppaRao Puli         }
4057d1cc387SAppaRao Puli     }
4067d1cc387SAppaRao Puli 
407b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
408b52664e2SAppaRao Puli     {
409b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
410b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
411b52664e2SAppaRao Puli         {
41262598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
413b52664e2SAppaRao Puli             return nullptr;
414b52664e2SAppaRao Puli         }
415b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
416b52664e2SAppaRao Puli         return subValue;
417b52664e2SAppaRao Puli     }
418b52664e2SAppaRao Puli 
419f80a87f2SEd Tanous     std::string
420f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
421b52664e2SAppaRao Puli     {
422fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
423fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
424fc76b8acSEd Tanous 
425b52664e2SAppaRao Puli         std::string id;
426b52664e2SAppaRao Puli 
427b52664e2SAppaRao Puli         int retry = 3;
428e662eae8SEd Tanous         while (retry != 0)
429b52664e2SAppaRao Puli         {
430fc76b8acSEd Tanous             id = std::to_string(dist(gen));
431fc76b8acSEd Tanous             if (gen.error())
432fc76b8acSEd Tanous             {
433fc76b8acSEd Tanous                 retry = 0;
434fc76b8acSEd Tanous                 break;
435fc76b8acSEd Tanous             }
436b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
437b52664e2SAppaRao Puli             if (inserted.second)
438b52664e2SAppaRao Puli             {
439b52664e2SAppaRao Puli                 break;
440b52664e2SAppaRao Puli             }
441b52664e2SAppaRao Puli             --retry;
44223a21a1cSEd Tanous         }
443b52664e2SAppaRao Puli 
444b52664e2SAppaRao Puli         if (retry <= 0)
445b52664e2SAppaRao Puli         {
44662598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
447abb93cddSEd Tanous             return "";
448b52664e2SAppaRao Puli         }
449b52664e2SAppaRao Puli 
45056ba386dSMyung Bae         // Set Subscription ID for back trace
4515fe4ef35SMyung Bae         subValue->userSub->id = id;
452a14c9113SEd Tanous 
45328afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4545fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
45528afb49cSJunLin Chen 
4567d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
4571bf712bcSAyushi Smriti 
458fe44eb0bSAyushi Smriti         // Update retry configuration.
459fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
460fe44eb0bSAyushi Smriti 
461f80a87f2SEd Tanous         return id;
462f80a87f2SEd Tanous     }
463f80a87f2SEd Tanous 
464f80a87f2SEd Tanous     std::string
465f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
466f80a87f2SEd Tanous                            std::string_view lastEventId)
467f80a87f2SEd Tanous     {
468f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
469f80a87f2SEd Tanous 
470f80a87f2SEd Tanous         if (!lastEventId.empty())
471f80a87f2SEd Tanous         {
472f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
473f80a87f2SEd Tanous                             lastEventId);
474f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
475f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
476f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
477f80a87f2SEd Tanous                                  return event.id == lastEventId;
478f80a87f2SEd Tanous                              });
479f80a87f2SEd Tanous             // Can't find a matching ID
480f80a87f2SEd Tanous             if (lastEvent == messages.end())
481f80a87f2SEd Tanous             {
482f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
483f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
4846d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
485f80a87f2SEd Tanous                 lastEvent = messages.begin();
486f80a87f2SEd Tanous             }
487f80a87f2SEd Tanous             else
488f80a87f2SEd Tanous             {
489f80a87f2SEd Tanous                 // Skip the last event the user already has
490f80a87f2SEd Tanous                 lastEvent++;
491f80a87f2SEd Tanous             }
492f80a87f2SEd Tanous 
493f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
494f80a87f2SEd Tanous                      lastEvent;
495f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
496f80a87f2SEd Tanous             {
4976d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
498f80a87f2SEd Tanous             }
499f80a87f2SEd Tanous         }
500f80a87f2SEd Tanous         return id;
501f80a87f2SEd Tanous     }
502f80a87f2SEd Tanous 
503f80a87f2SEd Tanous     std::string
504f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
505f80a87f2SEd Tanous     {
506f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
507a0969c70SMyung Bae         subValue->deleter = [id]() {
508a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
509a0969c70SMyung Bae         };
510f80a87f2SEd Tanous         updateSubscriptionData();
511b52664e2SAppaRao Puli         return id;
512b52664e2SAppaRao Puli     }
513b52664e2SAppaRao Puli 
514b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
515b52664e2SAppaRao Puli     {
516b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
51755f79e6fSEd Tanous         return obj != subscriptionsMap.end();
518b52664e2SAppaRao Puli     }
519b52664e2SAppaRao Puli 
5204b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
521b52664e2SAppaRao Puli     {
522b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
5234b712a29SEd Tanous         if (obj == subscriptionsMap.end())
524b52664e2SAppaRao Puli         {
5254b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
5264b712a29SEd Tanous             return false;
5274b712a29SEd Tanous         }
528b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
5294b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
5304b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
5314b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
5324b712a29SEd Tanous         {
5334b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
5344b712a29SEd Tanous             return true;
5354b712a29SEd Tanous         }
53628afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
5374b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
5387d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
539b52664e2SAppaRao Puli         updateSubscriptionData();
5404b712a29SEd Tanous 
5414b712a29SEd Tanous         return true;
542b52664e2SAppaRao Puli     }
543b52664e2SAppaRao Puli 
5445e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
5455e44e3d8SAppaRao Puli     {
546bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
5475e44e3d8SAppaRao Puli         {
548bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
5495e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
5505e44e3d8SAppaRao Puli             if (entryIsThisConn)
5515e44e3d8SAppaRao Puli             {
5525e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
5535fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
554bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
5555e44e3d8SAppaRao Puli                 return;
5565e44e3d8SAppaRao Puli             }
557bdbfae2aSEd Tanous             it++;
5585e44e3d8SAppaRao Puli         }
5595e44e3d8SAppaRao Puli     }
5605e44e3d8SAppaRao Puli 
5615e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
562b52664e2SAppaRao Puli     {
563b52664e2SAppaRao Puli         return subscriptionsMap.size();
564b52664e2SAppaRao Puli     }
565b52664e2SAppaRao Puli 
5665e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
5675e44e3d8SAppaRao Puli     {
5683544d2a7SEd Tanous         auto size = std::ranges::count_if(
5693544d2a7SEd Tanous             subscriptionsMap,
5705e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
5715e44e3d8SAppaRao Puli                    entry) {
5725fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
5734b712a29SEd Tanous                         subscriptionTypeSSE);
5745e44e3d8SAppaRao Puli             });
5755e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
5765e44e3d8SAppaRao Puli     }
5775e44e3d8SAppaRao Puli 
578b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
579b52664e2SAppaRao Puli     {
580b52664e2SAppaRao Puli         std::vector<std::string> idList;
581b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
582b52664e2SAppaRao Puli         {
583b52664e2SAppaRao Puli             idList.emplace_back(it.first);
584b52664e2SAppaRao Puli         }
585b52664e2SAppaRao Puli         return idList;
586b52664e2SAppaRao Puli     }
587b52664e2SAppaRao Puli 
58881ee0e74SChandramohan Harkude     bool sendTestEventLog(TestEvent& testEvent)
5890b4bdd93SAppaRao Puli     {
5905e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5910b4bdd93SAppaRao Puli         {
5920b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
59381ee0e74SChandramohan Harkude             if (!entry->sendTestEventLog(testEvent))
5946ba8c82eSsunharis_in             {
5956ba8c82eSsunharis_in                 return false;
5960b4bdd93SAppaRao Puli             }
5970b4bdd93SAppaRao Puli         }
5986ba8c82eSsunharis_in         return true;
5996ba8c82eSsunharis_in     }
600e9a14131SAppaRao Puli 
6013433b03aSEd Tanous     static void
6023433b03aSEd Tanous         sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords)
6033433b03aSEd Tanous     {
6043433b03aSEd Tanous         for (const auto& it :
6053433b03aSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
6063433b03aSEd Tanous         {
6073433b03aSEd Tanous             Subscription& entry = *it.second;
6083433b03aSEd Tanous             entry.filterAndSendEventLogs(eventRecords);
6093433b03aSEd Tanous         }
6103433b03aSEd Tanous     }
6113433b03aSEd Tanous 
612b26ff34dSEd Tanous     static void sendTelemetryReportToSubs(
613b26ff34dSEd Tanous         const std::string& reportId, const telemetry::TimestampReadings& var)
614b26ff34dSEd Tanous     {
615b26ff34dSEd Tanous         for (const auto& it :
616b26ff34dSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
617b26ff34dSEd Tanous         {
618b26ff34dSEd Tanous             Subscription& entry = *it.second;
619b26ff34dSEd Tanous             entry.filterAndSendReports(reportId, var);
620b26ff34dSEd Tanous         }
621b26ff34dSEd Tanous     }
622b26ff34dSEd Tanous 
623f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
624f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
62596330b99SSunitha Harish     {
626613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
627f80a87f2SEd Tanous 
628613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
629613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
630613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
631613dabeaSEd Tanous 
632f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
633788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
63496330b99SSunitha Harish 
635f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
636f80a87f2SEd Tanous 
637f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
63896330b99SSunitha Harish         {
639f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
6405fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
6415fe4ef35SMyung Bae                                     resourceType))
64296330b99SSunitha Harish             {
643f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
644f80a87f2SEd Tanous                 continue;
64596330b99SSunitha Harish             }
646f80a87f2SEd Tanous 
647f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
648f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
649f80a87f2SEd Tanous 
650613dabeaSEd Tanous             nlohmann::json msgJson;
651613dabeaSEd Tanous 
652613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
653613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
654613dabeaSEd Tanous             msgJson["Id"] = eventId;
655f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
656f52c03c1SCarson Labrado 
657f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
658f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
6596d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
66096330b99SSunitha Harish         }
66121c0ba6eSMyung Bae         eventId++; // increment the eventId
66296330b99SSunitha Harish     }
66323a21a1cSEd Tanous };
664b52664e2SAppaRao Puli 
665b52664e2SAppaRao Puli } // namespace redfish
666