xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 82b286fb77833c70bd670f3b428e49f6d9416d06)
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"
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 
51b52664e2SAppaRao Puli class EventServiceManager
52b52664e2SAppaRao Puli {
53b52664e2SAppaRao Puli   private:
54d3a9e084SEd Tanous     bool serviceEnabled = false;
55d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
56d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
577d1cc387SAppaRao Puli 
589f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
599f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
606c58a03eSAlexander Hansen     std::optional<DbusEventLogMonitor> dbusEventLogMonitor;
612ac69850SEd Tanous     std::optional<DbusTelemetryMonitor> matchTelemetryMonitor;
627b669723SEd Tanous     std::optional<FilesystemLogWatcher> filesystemLogMonitor;
63b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
64b52664e2SAppaRao Puli         subscriptionsMap;
65b52664e2SAppaRao Puli 
669f616dd1SEd Tanous     uint64_t eventId{1};
6796330b99SSunitha Harish 
68f80a87f2SEd Tanous     struct Event
69f80a87f2SEd Tanous     {
704a19a7b5SEd Tanous         uint64_t id;
714a19a7b5SEd Tanous         nlohmann::json::object_t message;
72f80a87f2SEd Tanous     };
73f80a87f2SEd Tanous 
74f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
75f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
76f80a87f2SEd Tanous 
77b52664e2SAppaRao Puli   public:
789f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
799f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
809f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
819f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
82ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
839f616dd1SEd Tanous 
849838eb20SEd Tanous     explicit EventServiceManager()
85b52664e2SAppaRao Puli     {
86f8ca6d79SEd Tanous         // Load config from persist store.
87f8ca6d79SEd Tanous         initConfig();
88f8ca6d79SEd Tanous     }
89f8ca6d79SEd Tanous 
909838eb20SEd Tanous     static EventServiceManager& getInstance()
91f8ca6d79SEd Tanous     {
929838eb20SEd Tanous         static EventServiceManager handler;
93b52664e2SAppaRao Puli         return handler;
94b52664e2SAppaRao Puli     }
95b52664e2SAppaRao Puli 
961bf712bcSAyushi Smriti     void initConfig()
971bf712bcSAyushi Smriti     {
9828afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
9928afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
10028afb49cSJunLin Chen                 .getEventServiceConfig();
1011bf712bcSAyushi Smriti 
10228afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
10328afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
10428afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1051bf712bcSAyushi Smriti 
10628afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
10728afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1081bf712bcSAyushi Smriti         {
1095fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1105fe4ef35SMyung Bae                 it.second;
1114bbf237fSAppaRao Puli 
1126fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1135fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1141bf712bcSAyushi Smriti 
115a716aa74SEd Tanous             if (!url)
1161bf712bcSAyushi Smriti             {
11762598e31SEd Tanous                 BMCWEB_LOG_ERROR(
11862598e31SEd Tanous                     "Failed to validate and split destination url");
1191bf712bcSAyushi Smriti                 continue;
1201bf712bcSAyushi Smriti             }
1211bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
1229838eb20SEd Tanous                 std::make_shared<Subscription>(newSub, *url, getIoContext());
1235fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
124a0969c70SMyung Bae             subValue->deleter = [id]() {
125a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
126a0969c70SMyung Bae             };
1271bf712bcSAyushi Smriti 
128a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
12928afb49cSJunLin Chen 
13028afb49cSJunLin Chen             updateNoOfSubscribersCount();
13128afb49cSJunLin Chen 
13228afb49cSJunLin Chen             // Update retry configuration.
13328afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
134fb546105SMyung Bae 
135fb546105SMyung Bae             // schedule a heartbeat if sendHeartbeat was set to true
136fb546105SMyung Bae             if (subValue->userSub->sendHeartbeat)
137fb546105SMyung Bae             {
138fb546105SMyung Bae                 subValue->scheduleNextHeartbeatEvent();
139fb546105SMyung Bae             }
1401bf712bcSAyushi Smriti         }
1411bf712bcSAyushi Smriti     }
1421bf712bcSAyushi Smriti 
1439eb808c1SEd Tanous     void updateSubscriptionData() const
14428afb49cSJunLin Chen     {
14528afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
14628afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
14728afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
14828afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
14928afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
15028afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
15128afb49cSJunLin Chen 
15228afb49cSJunLin Chen         persistent_data::getConfig().writeData();
15328afb49cSJunLin Chen     }
15428afb49cSJunLin Chen 
15528afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
1567d1cc387SAppaRao Puli     {
1577d1cc387SAppaRao Puli         bool updateConfig = false;
158fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
1597d1cc387SAppaRao Puli 
1602ac69850SEd Tanous         if (serviceEnabled)
1617d1cc387SAppaRao Puli         {
1627b669723SEd Tanous             if (noOfEventLogSubscribers > 0U)
1637b669723SEd Tanous             {
1646c58a03eSAlexander Hansen                 if constexpr (BMCWEB_REDFISH_DBUS_LOG)
1656c58a03eSAlexander Hansen                 {
1666c58a03eSAlexander Hansen                     if (!dbusEventLogMonitor)
1676c58a03eSAlexander Hansen                     {
1686c58a03eSAlexander Hansen                         if constexpr (
1696c58a03eSAlexander Hansen                             BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
1706c58a03eSAlexander Hansen                         {
1716c58a03eSAlexander Hansen                             dbusEventLogMonitor.emplace();
1726c58a03eSAlexander Hansen                         }
1736c58a03eSAlexander Hansen                     }
1746c58a03eSAlexander Hansen                 }
1756c58a03eSAlexander Hansen                 else
1767b669723SEd Tanous                 {
1777b669723SEd Tanous                     if (!filesystemLogMonitor)
1787b669723SEd Tanous                     {
1799838eb20SEd Tanous                         filesystemLogMonitor.emplace(getIoContext());
1807b669723SEd Tanous                     }
1817b669723SEd Tanous                 }
1827b669723SEd Tanous             }
1837b669723SEd Tanous             else
1847b669723SEd Tanous             {
1856c58a03eSAlexander Hansen                 dbusEventLogMonitor.reset();
1867b669723SEd Tanous                 filesystemLogMonitor.reset();
1877b669723SEd Tanous             }
1887b669723SEd Tanous 
1892ac69850SEd Tanous             if (noOfMetricReportSubscribers > 0U)
1907d1cc387SAppaRao Puli             {
1912ac69850SEd Tanous                 if (!matchTelemetryMonitor)
1922ac69850SEd Tanous                 {
1932ac69850SEd Tanous                     matchTelemetryMonitor.emplace();
1942ac69850SEd Tanous                 }
1957d1cc387SAppaRao Puli             }
1967d1cc387SAppaRao Puli             else
1977d1cc387SAppaRao Puli             {
1982ac69850SEd Tanous                 matchTelemetryMonitor.reset();
1997d1cc387SAppaRao Puli             }
2002ac69850SEd Tanous         }
2012ac69850SEd Tanous         else
2022ac69850SEd Tanous         {
2032ac69850SEd Tanous             matchTelemetryMonitor.reset();
2046c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
2057b669723SEd Tanous             filesystemLogMonitor.reset();
2062ac69850SEd Tanous         }
2072ac69850SEd Tanous 
2082ac69850SEd Tanous         if (serviceEnabled != cfg.enabled)
2092ac69850SEd Tanous         {
2102ac69850SEd Tanous             serviceEnabled = cfg.enabled;
2117d1cc387SAppaRao Puli             updateConfig = true;
2127d1cc387SAppaRao Puli         }
2137d1cc387SAppaRao Puli 
21428afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
2157d1cc387SAppaRao Puli         {
21628afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
2177d1cc387SAppaRao Puli             updateConfig = true;
218fe44eb0bSAyushi Smriti             updateRetryCfg = true;
2197d1cc387SAppaRao Puli         }
2207d1cc387SAppaRao Puli 
22128afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
2227d1cc387SAppaRao Puli         {
22328afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
2247d1cc387SAppaRao Puli             updateConfig = true;
225fe44eb0bSAyushi Smriti             updateRetryCfg = true;
2267d1cc387SAppaRao Puli         }
2277d1cc387SAppaRao Puli 
2287d1cc387SAppaRao Puli         if (updateConfig)
2297d1cc387SAppaRao Puli         {
2307d1cc387SAppaRao Puli             updateSubscriptionData();
2317d1cc387SAppaRao Puli         }
232fe44eb0bSAyushi Smriti 
233fe44eb0bSAyushi Smriti         if (updateRetryCfg)
234fe44eb0bSAyushi Smriti         {
235fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
236fe44eb0bSAyushi Smriti             for (const auto& it :
237fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
238fe44eb0bSAyushi Smriti             {
2395e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
2405e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
241fe44eb0bSAyushi Smriti             }
242fe44eb0bSAyushi Smriti         }
2437d1cc387SAppaRao Puli     }
2447d1cc387SAppaRao Puli 
2457d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
2467d1cc387SAppaRao Puli     {
2477d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
2487d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
2497d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
2507d1cc387SAppaRao Puli         {
2517d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
2525fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
2537d1cc387SAppaRao Puli             {
2547d1cc387SAppaRao Puli                 eventLogSubCount++;
2557d1cc387SAppaRao Puli             }
2565fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
2577d1cc387SAppaRao Puli             {
2587d1cc387SAppaRao Puli                 metricReportSubCount++;
2597d1cc387SAppaRao Puli             }
2607d1cc387SAppaRao Puli         }
2617d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
2626c58a03eSAlexander Hansen         if (eventLogSubCount > 0U)
2637d1cc387SAppaRao Puli         {
2646c58a03eSAlexander Hansen             if constexpr (BMCWEB_REDFISH_DBUS_LOG)
2656c58a03eSAlexander Hansen             {
2666c58a03eSAlexander Hansen                 if (!dbusEventLogMonitor &&
2676c58a03eSAlexander Hansen                     BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION)
2686c58a03eSAlexander Hansen                 {
2696c58a03eSAlexander Hansen                     dbusEventLogMonitor.emplace();
2706c58a03eSAlexander Hansen                 }
2716c58a03eSAlexander Hansen             }
2726c58a03eSAlexander Hansen             else
2736c58a03eSAlexander Hansen             {
2746c58a03eSAlexander Hansen                 if (!filesystemLogMonitor)
2756c58a03eSAlexander Hansen                 {
2769838eb20SEd Tanous                     filesystemLogMonitor.emplace(getIoContext());
2776c58a03eSAlexander Hansen                 }
2786c58a03eSAlexander Hansen             }
2796c58a03eSAlexander Hansen         }
2806c58a03eSAlexander Hansen         else
2816c58a03eSAlexander Hansen         {
2826c58a03eSAlexander Hansen             dbusEventLogMonitor.reset();
2836c58a03eSAlexander Hansen             filesystemLogMonitor.reset();
2846c58a03eSAlexander Hansen         }
2856c58a03eSAlexander Hansen 
2867d1cc387SAppaRao Puli         noOfMetricReportSubscribers = metricReportSubCount;
2876c58a03eSAlexander Hansen         if (metricReportSubCount > 0U)
2887d1cc387SAppaRao Puli         {
2892ac69850SEd Tanous             if (!matchTelemetryMonitor)
2902ac69850SEd Tanous             {
2912ac69850SEd Tanous                 matchTelemetryMonitor.emplace();
2922ac69850SEd Tanous             }
2937d1cc387SAppaRao Puli         }
2947d1cc387SAppaRao Puli         else
2957d1cc387SAppaRao Puli         {
2962ac69850SEd Tanous             matchTelemetryMonitor.reset();
2977d1cc387SAppaRao Puli         }
2987d1cc387SAppaRao Puli     }
2997d1cc387SAppaRao Puli 
300b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
301b52664e2SAppaRao Puli     {
302b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
303b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
304b52664e2SAppaRao Puli         {
30562598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
306b52664e2SAppaRao Puli             return nullptr;
307b52664e2SAppaRao Puli         }
308b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
309b52664e2SAppaRao Puli         return subValue;
310b52664e2SAppaRao Puli     }
311b52664e2SAppaRao Puli 
312504af5a0SPatrick Williams     std::string addSubscriptionInternal(
313504af5a0SPatrick Williams         const std::shared_ptr<Subscription>& subValue)
314b52664e2SAppaRao Puli     {
315fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
316fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
317fc76b8acSEd Tanous 
318b52664e2SAppaRao Puli         std::string id;
319b52664e2SAppaRao Puli 
320b52664e2SAppaRao Puli         int retry = 3;
321e662eae8SEd Tanous         while (retry != 0)
322b52664e2SAppaRao Puli         {
323fc76b8acSEd Tanous             id = std::to_string(dist(gen));
324fc76b8acSEd Tanous             if (gen.error())
325fc76b8acSEd Tanous             {
326fc76b8acSEd Tanous                 retry = 0;
327fc76b8acSEd Tanous                 break;
328fc76b8acSEd Tanous             }
329b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
330b52664e2SAppaRao Puli             if (inserted.second)
331b52664e2SAppaRao Puli             {
332b52664e2SAppaRao Puli                 break;
333b52664e2SAppaRao Puli             }
334b52664e2SAppaRao Puli             --retry;
33523a21a1cSEd Tanous         }
336b52664e2SAppaRao Puli 
337b52664e2SAppaRao Puli         if (retry <= 0)
338b52664e2SAppaRao Puli         {
33962598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
340abb93cddSEd Tanous             return "";
341b52664e2SAppaRao Puli         }
342b52664e2SAppaRao Puli 
34356ba386dSMyung Bae         // Set Subscription ID for back trace
3445fe4ef35SMyung Bae         subValue->userSub->id = id;
345a14c9113SEd Tanous 
34628afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
3475fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
34828afb49cSJunLin Chen 
3497d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
3501bf712bcSAyushi Smriti 
351fe44eb0bSAyushi Smriti         // Update retry configuration.
352fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
353fe44eb0bSAyushi Smriti 
354f80a87f2SEd Tanous         return id;
355f80a87f2SEd Tanous     }
356f80a87f2SEd Tanous 
357504af5a0SPatrick Williams     std::string addSSESubscription(
358504af5a0SPatrick Williams         const std::shared_ptr<Subscription>& subValue,
359f80a87f2SEd Tanous         std::string_view lastEventId)
360f80a87f2SEd Tanous     {
361f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
362f80a87f2SEd Tanous 
363f80a87f2SEd Tanous         if (!lastEventId.empty())
364f80a87f2SEd Tanous         {
365f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
366f80a87f2SEd Tanous                             lastEventId);
367f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
3684a19a7b5SEd Tanous                 std::ranges::find_if(
3694a19a7b5SEd Tanous                     messages, [&lastEventId](const Event& event) {
3704a19a7b5SEd Tanous                         return std::to_string(event.id) == lastEventId;
371f80a87f2SEd Tanous                     });
372f80a87f2SEd Tanous             // Can't find a matching ID
373f80a87f2SEd Tanous             if (lastEvent == messages.end())
374f80a87f2SEd Tanous             {
375f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
3764a19a7b5SEd Tanous 
3774a19a7b5SEd Tanous                 std::string strMsg = msg.dump(
3784a19a7b5SEd Tanous                     2, ' ', true, nlohmann::json::error_handler_t::replace);
3794a19a7b5SEd Tanous                 eventId++;
3804a19a7b5SEd Tanous                 subValue->sendEventToSubscriber(eventId, std::move(strMsg));
381f80a87f2SEd Tanous             }
382f80a87f2SEd Tanous             else
383f80a87f2SEd Tanous             {
384f80a87f2SEd Tanous                 // Skip the last event the user already has
385f80a87f2SEd Tanous                 lastEvent++;
386f80a87f2SEd Tanous 
387f80a87f2SEd Tanous                 for (boost::circular_buffer<Event>::const_iterator event =
388f80a87f2SEd Tanous                          lastEvent;
3894a19a7b5SEd Tanous                      event != messages.end(); event++)
390f80a87f2SEd Tanous                 {
3914a19a7b5SEd Tanous                     std::string strMsg =
3924a19a7b5SEd Tanous                         nlohmann::json(event->message)
3934a19a7b5SEd Tanous                             .dump(2, ' ', true,
3944a19a7b5SEd Tanous                                   nlohmann::json::error_handler_t::replace);
3954a19a7b5SEd Tanous 
3964a19a7b5SEd Tanous                     subValue->sendEventToSubscriber(event->id,
3974a19a7b5SEd Tanous                                                     std::move(strMsg));
3984a19a7b5SEd Tanous                 }
399f80a87f2SEd Tanous             }
400f80a87f2SEd Tanous         }
401f80a87f2SEd Tanous         return id;
402f80a87f2SEd Tanous     }
403f80a87f2SEd Tanous 
404504af5a0SPatrick Williams     std::string addPushSubscription(
405504af5a0SPatrick Williams         const std::shared_ptr<Subscription>& subValue)
406f80a87f2SEd Tanous     {
407f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
408a0969c70SMyung Bae         subValue->deleter = [id]() {
409a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
410a0969c70SMyung Bae         };
411f80a87f2SEd Tanous         updateSubscriptionData();
412b52664e2SAppaRao Puli         return id;
413b52664e2SAppaRao Puli     }
414b52664e2SAppaRao Puli 
415b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
416b52664e2SAppaRao Puli     {
417b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
41855f79e6fSEd Tanous         return obj != subscriptionsMap.end();
419b52664e2SAppaRao Puli     }
420b52664e2SAppaRao Puli 
4214b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
422b52664e2SAppaRao Puli     {
423b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
4244b712a29SEd Tanous         if (obj == subscriptionsMap.end())
425b52664e2SAppaRao Puli         {
4264b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
4274b712a29SEd Tanous             return false;
4284b712a29SEd Tanous         }
429b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
4304b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
4314b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
4324b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
4334b712a29SEd Tanous         {
4346136e852SMyung Bae             BMCWEB_LOG_ERROR("Subscription {} wasn't in persistent data", id);
4354b712a29SEd Tanous             return true;
4364b712a29SEd Tanous         }
43728afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4384b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
4397d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
440b52664e2SAppaRao Puli         updateSubscriptionData();
4414b712a29SEd Tanous 
4424b712a29SEd Tanous         return true;
443b52664e2SAppaRao Puli     }
444b52664e2SAppaRao Puli 
4455e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
4465e44e3d8SAppaRao Puli     {
447bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
4485e44e3d8SAppaRao Puli         {
449bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
4505e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
4515e44e3d8SAppaRao Puli             if (entryIsThisConn)
4525e44e3d8SAppaRao Puli             {
4535e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
4545fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
455bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
4565e44e3d8SAppaRao Puli                 return;
4575e44e3d8SAppaRao Puli             }
458bdbfae2aSEd Tanous             it++;
4595e44e3d8SAppaRao Puli         }
4605e44e3d8SAppaRao Puli     }
4615e44e3d8SAppaRao Puli 
4625e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
463b52664e2SAppaRao Puli     {
464b52664e2SAppaRao Puli         return subscriptionsMap.size();
465b52664e2SAppaRao Puli     }
466b52664e2SAppaRao Puli 
4675e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
4685e44e3d8SAppaRao Puli     {
4693544d2a7SEd Tanous         auto size = std::ranges::count_if(
4703544d2a7SEd Tanous             subscriptionsMap,
4715e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
4725e44e3d8SAppaRao Puli                    entry) {
4735fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
4744b712a29SEd Tanous                         subscriptionTypeSSE);
4755e44e3d8SAppaRao Puli             });
4765e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
4775e44e3d8SAppaRao Puli     }
4785e44e3d8SAppaRao Puli 
479b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
480b52664e2SAppaRao Puli     {
481b52664e2SAppaRao Puli         std::vector<std::string> idList;
482b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
483b52664e2SAppaRao Puli         {
484b52664e2SAppaRao Puli             idList.emplace_back(it.first);
485b52664e2SAppaRao Puli         }
486b52664e2SAppaRao Puli         return idList;
487b52664e2SAppaRao Puli     }
488b52664e2SAppaRao Puli 
48981ee0e74SChandramohan Harkude     bool sendTestEventLog(TestEvent& testEvent)
4900b4bdd93SAppaRao Puli     {
4914a19a7b5SEd Tanous         eventId++;
4924a19a7b5SEd Tanous         nlohmann::json::array_t logEntryArray;
4934a19a7b5SEd Tanous         nlohmann::json& logEntryJson = logEntryArray.emplace_back();
4944a19a7b5SEd Tanous 
4954a19a7b5SEd Tanous         if (testEvent.eventGroupId)
4964a19a7b5SEd Tanous         {
4974a19a7b5SEd Tanous             logEntryJson["EventGroupId"] = *testEvent.eventGroupId;
4984a19a7b5SEd Tanous         }
4994a19a7b5SEd Tanous 
5004a19a7b5SEd Tanous         if (testEvent.eventTimestamp)
5014a19a7b5SEd Tanous         {
5024a19a7b5SEd Tanous             logEntryJson["EventTimestamp"] = *testEvent.eventTimestamp;
5034a19a7b5SEd Tanous         }
5044a19a7b5SEd Tanous 
5054a19a7b5SEd Tanous         if (testEvent.originOfCondition)
5064a19a7b5SEd Tanous         {
5074a19a7b5SEd Tanous             logEntryJson["OriginOfCondition"]["@odata.id"] =
5084a19a7b5SEd Tanous                 *testEvent.originOfCondition;
5094a19a7b5SEd Tanous         }
5104a19a7b5SEd Tanous         if (testEvent.severity)
5114a19a7b5SEd Tanous         {
5124a19a7b5SEd Tanous             logEntryJson["Severity"] = *testEvent.severity;
5134a19a7b5SEd Tanous         }
5144a19a7b5SEd Tanous 
5154a19a7b5SEd Tanous         if (testEvent.message)
5164a19a7b5SEd Tanous         {
5174a19a7b5SEd Tanous             logEntryJson["Message"] = *testEvent.message;
5184a19a7b5SEd Tanous         }
5194a19a7b5SEd Tanous 
5204a19a7b5SEd Tanous         if (testEvent.resolution)
5214a19a7b5SEd Tanous         {
5224a19a7b5SEd Tanous             logEntryJson["Resolution"] = *testEvent.resolution;
5234a19a7b5SEd Tanous         }
5244a19a7b5SEd Tanous 
5254a19a7b5SEd Tanous         if (testEvent.messageId)
5264a19a7b5SEd Tanous         {
5274a19a7b5SEd Tanous             logEntryJson["MessageId"] = *testEvent.messageId;
5284a19a7b5SEd Tanous         }
5294a19a7b5SEd Tanous 
5304a19a7b5SEd Tanous         if (testEvent.messageArgs)
5314a19a7b5SEd Tanous         {
5324a19a7b5SEd Tanous             logEntryJson["MessageArgs"] = *testEvent.messageArgs;
5334a19a7b5SEd Tanous         }
5344a19a7b5SEd Tanous         // MemberId is 0 : since we are sending one event record.
5354a19a7b5SEd Tanous         logEntryJson["MemberId"] = "0";
5364a19a7b5SEd Tanous 
537*82b286fbSEd Tanous         nlohmann::json::object_t msg;
5384a19a7b5SEd Tanous         msg["@odata.type"] = "#Event.v1_4_0.Event";
5394a19a7b5SEd Tanous         msg["Id"] = std::to_string(eventId);
5404a19a7b5SEd Tanous         msg["Name"] = "Event Log";
5414a19a7b5SEd Tanous         msg["Events"] = logEntryArray;
5424a19a7b5SEd Tanous 
543*82b286fbSEd Tanous         std::string strMsg = nlohmann::json(msg).dump(
544*82b286fbSEd Tanous             2, ' ', true, nlohmann::json::error_handler_t::replace);
5454a19a7b5SEd Tanous 
5464a19a7b5SEd Tanous         messages.push_back(Event(eventId, msg));
5475e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5480b4bdd93SAppaRao Puli         {
5490b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
5504a19a7b5SEd Tanous             if (!entry->sendEventToSubscriber(eventId, std::string(strMsg)))
5516ba8c82eSsunharis_in             {
5526ba8c82eSsunharis_in                 return false;
5530b4bdd93SAppaRao Puli             }
5540b4bdd93SAppaRao Puli         }
5556ba8c82eSsunharis_in         return true;
5566ba8c82eSsunharis_in     }
557e9a14131SAppaRao Puli 
558504af5a0SPatrick Williams     static void sendEventsToSubs(
559504af5a0SPatrick Williams         const std::vector<EventLogObjectsType>& eventRecords)
5603433b03aSEd Tanous     {
5614a19a7b5SEd Tanous         EventServiceManager& mgr = EventServiceManager::getInstance();
5624a19a7b5SEd Tanous         mgr.eventId++;
5634a19a7b5SEd Tanous         for (const auto& it : mgr.subscriptionsMap)
5643433b03aSEd Tanous         {
5653433b03aSEd Tanous             Subscription& entry = *it.second;
5664a19a7b5SEd Tanous             entry.filterAndSendEventLogs(mgr.eventId, eventRecords);
5673433b03aSEd Tanous         }
5683433b03aSEd Tanous     }
5693433b03aSEd Tanous 
570b26ff34dSEd Tanous     static void sendTelemetryReportToSubs(
571b26ff34dSEd Tanous         const std::string& reportId, const telemetry::TimestampReadings& var)
572b26ff34dSEd Tanous     {
5734a19a7b5SEd Tanous         EventServiceManager& mgr = EventServiceManager::getInstance();
5744a19a7b5SEd Tanous         mgr.eventId++;
5754a19a7b5SEd Tanous 
5764a19a7b5SEd Tanous         for (const auto& it : mgr.subscriptionsMap)
577b26ff34dSEd Tanous         {
578b26ff34dSEd Tanous             Subscription& entry = *it.second;
5794a19a7b5SEd Tanous             entry.filterAndSendReports(mgr.eventId, reportId, var);
580b26ff34dSEd Tanous         }
581b26ff34dSEd Tanous     }
582b26ff34dSEd Tanous 
583f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
584f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
58596330b99SSunitha Harish     {
5864a19a7b5SEd Tanous         eventId++;
587613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
588f80a87f2SEd Tanous 
589613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
590613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
5914a19a7b5SEd Tanous 
5924a19a7b5SEd Tanous         if (!origin.empty())
5934a19a7b5SEd Tanous         {
594613dabeaSEd Tanous             eventMessage["OriginOfCondition"] = origin;
5954a19a7b5SEd Tanous         }
596613dabeaSEd Tanous 
597f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
598788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
59996330b99SSunitha Harish 
6004a19a7b5SEd Tanous         messages.push_back(Event(eventId, eventMessage));
601f80a87f2SEd Tanous 
602f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
60396330b99SSunitha Harish         {
604f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
6055fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
6065fe4ef35SMyung Bae                                     resourceType))
60796330b99SSunitha Harish             {
608f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
609f80a87f2SEd Tanous                 continue;
61096330b99SSunitha Harish             }
611f80a87f2SEd Tanous 
612f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
613f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
614f80a87f2SEd Tanous 
615613dabeaSEd Tanous             nlohmann::json msgJson;
616613dabeaSEd Tanous 
617613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
618613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
619613dabeaSEd Tanous             msgJson["Id"] = eventId;
620f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
621f52c03c1SCarson Labrado 
622f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
623f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
6244a19a7b5SEd Tanous             entry->sendEventToSubscriber(eventId, std::move(strMsg));
62596330b99SSunitha Harish         }
62696330b99SSunitha Harish     }
62723a21a1cSEd Tanous };
628b52664e2SAppaRao Puli 
629b52664e2SAppaRao Puli } // namespace redfish
630