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