xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 7b6697234817c8761e353ecae44e2b2515a6fefa)
1b52664e2SAppaRao Puli /*
26be832e2SEd Tanous Copyright (c) 2020 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
15b52664e2SAppaRao Puli */
16b52664e2SAppaRao Puli #pragma once
17b26ff34dSEd Tanous #include "dbus_log_watcher.hpp"
183ccb3adbSEd Tanous #include "dbus_utility.hpp"
193ccb3adbSEd Tanous #include "error_messages.hpp"
20b80ba2e4SAlexander Hansen #include "event_log.hpp"
21d3a48a14SEd Tanous #include "event_matches_filter.hpp"
223ccb3adbSEd Tanous #include "event_service_store.hpp"
232185ddeaSEd Tanous #include "filesystem_log_watcher.hpp"
24c0353249SWludzik, Jozef #include "metric_report.hpp"
252c6ffdb0SEd Tanous #include "ossl_random.hpp"
263ccb3adbSEd Tanous #include "persistent_data.hpp"
2702c1e29fSAlexander Hansen #include "subscription.hpp"
282ac69850SEd Tanous #include "utility.hpp"
292ac69850SEd Tanous #include "utils/dbus_event_log_entry.hpp"
302ac69850SEd Tanous #include "utils/json_utils.hpp"
315b90429aSEd Tanous #include "utils/time_utils.hpp"
327f4eb588SAppaRao Puli 
33fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp>
34f80a87f2SEd Tanous #include <boost/circular_buffer.hpp>
35b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp>
36ef4c65b7SEd Tanous #include <boost/url/format.hpp>
374a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
381214b7e7SGunnar Mills 
395e44e3d8SAppaRao Puli #include <algorithm>
40b52664e2SAppaRao Puli #include <cstdlib>
41b52664e2SAppaRao Puli #include <ctime>
42a14c9113SEd Tanous #include <format>
431bf712bcSAyushi Smriti #include <fstream>
44b52664e2SAppaRao Puli #include <memory>
45a14c9113SEd Tanous #include <string>
4656ba386dSMyung Bae #include <string_view>
475fe4ef35SMyung Bae #include <utility>
482ac69850SEd Tanous #include <variant>
49b52664e2SAppaRao Puli 
50b52664e2SAppaRao Puli namespace redfish
51b52664e2SAppaRao Puli {
52156d6b00SAppaRao Puli 
53156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event";
54156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport";
55156d6b00SAppaRao Puli 
561bf712bcSAyushi Smriti static constexpr const char* eventServiceFile =
571bf712bcSAyushi Smriti     "/var/lib/bmcweb/eventservice_config.json";
581bf712bcSAyushi Smriti 
59b52664e2SAppaRao Puli class EventServiceManager
60b52664e2SAppaRao Puli {
61b52664e2SAppaRao Puli   private:
62d3a9e084SEd Tanous     bool serviceEnabled = false;
63d3a9e084SEd Tanous     uint32_t retryAttempts = 0;
64d3a9e084SEd Tanous     uint32_t retryTimeoutInterval = 0;
657d1cc387SAppaRao Puli 
669f616dd1SEd Tanous     size_t noOfEventLogSubscribers{0};
679f616dd1SEd Tanous     size_t noOfMetricReportSubscribers{0};
682ac69850SEd Tanous     std::optional<DbusTelemetryMonitor> matchTelemetryMonitor;
69*7b669723SEd Tanous     std::optional<FilesystemLogWatcher> filesystemLogMonitor;
70b52664e2SAppaRao Puli     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
71b52664e2SAppaRao Puli         subscriptionsMap;
72b52664e2SAppaRao Puli 
739f616dd1SEd Tanous     uint64_t eventId{1};
7496330b99SSunitha Harish 
75f80a87f2SEd Tanous     struct Event
76f80a87f2SEd Tanous     {
77f80a87f2SEd Tanous         std::string id;
78f80a87f2SEd Tanous         nlohmann::json message;
79f80a87f2SEd Tanous     };
80f80a87f2SEd Tanous 
81f80a87f2SEd Tanous     constexpr static size_t maxMessages = 200;
82f80a87f2SEd Tanous     boost::circular_buffer<Event> messages{maxMessages};
83f80a87f2SEd Tanous 
84f8ca6d79SEd Tanous     boost::asio::io_context& ioc;
85f8ca6d79SEd Tanous 
86b52664e2SAppaRao Puli   public:
879f616dd1SEd Tanous     EventServiceManager(const EventServiceManager&) = delete;
889f616dd1SEd Tanous     EventServiceManager& operator=(const EventServiceManager&) = delete;
899f616dd1SEd Tanous     EventServiceManager(EventServiceManager&&) = delete;
909f616dd1SEd Tanous     EventServiceManager& operator=(EventServiceManager&&) = delete;
91ecd6a3a2SEd Tanous     ~EventServiceManager() = default;
929f616dd1SEd Tanous 
93f8ca6d79SEd Tanous     explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn)
94b52664e2SAppaRao Puli     {
95f8ca6d79SEd Tanous         // Load config from persist store.
96f8ca6d79SEd Tanous         initConfig();
97f8ca6d79SEd Tanous     }
98f8ca6d79SEd Tanous 
99f8ca6d79SEd Tanous     static EventServiceManager&
100f8ca6d79SEd Tanous         getInstance(boost::asio::io_context* ioc = nullptr)
101f8ca6d79SEd Tanous     {
102f8ca6d79SEd Tanous         static EventServiceManager handler(*ioc);
103b52664e2SAppaRao Puli         return handler;
104b52664e2SAppaRao Puli     }
105b52664e2SAppaRao Puli 
1061bf712bcSAyushi Smriti     void initConfig()
1071bf712bcSAyushi Smriti     {
10828afb49cSJunLin Chen         loadOldBehavior();
1091bf712bcSAyushi Smriti 
11028afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
11128afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
11228afb49cSJunLin Chen                 .getEventServiceConfig();
1131bf712bcSAyushi Smriti 
11428afb49cSJunLin Chen         serviceEnabled = eventServiceConfig.enabled;
11528afb49cSJunLin Chen         retryAttempts = eventServiceConfig.retryAttempts;
11628afb49cSJunLin Chen         retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval;
1171bf712bcSAyushi Smriti 
11828afb49cSJunLin Chen         for (const auto& it : persistent_data::EventServiceStore::getInstance()
11928afb49cSJunLin Chen                                   .subscriptionsConfigMap)
1201bf712bcSAyushi Smriti         {
1215fe4ef35SMyung Bae             std::shared_ptr<persistent_data::UserSubscription> newSub =
1225fe4ef35SMyung Bae                 it.second;
1234bbf237fSAppaRao Puli 
1246fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
1255fe4ef35SMyung Bae                 boost::urls::parse_absolute_uri(newSub->destinationUrl);
1261bf712bcSAyushi Smriti 
127a716aa74SEd Tanous             if (!url)
1281bf712bcSAyushi Smriti             {
12962598e31SEd Tanous                 BMCWEB_LOG_ERROR(
13062598e31SEd Tanous                     "Failed to validate and split destination url");
1311bf712bcSAyushi Smriti                 continue;
1321bf712bcSAyushi Smriti             }
1331bf712bcSAyushi Smriti             std::shared_ptr<Subscription> subValue =
13421a94d5cSMyung Bae                 std::make_shared<Subscription>(newSub, *url, ioc);
1355fe4ef35SMyung Bae             std::string id = subValue->userSub->id;
136a0969c70SMyung Bae             subValue->deleter = [id]() {
137a0969c70SMyung Bae                 EventServiceManager::getInstance().deleteSubscription(id);
138a0969c70SMyung Bae             };
1391bf712bcSAyushi Smriti 
140a0969c70SMyung Bae             subscriptionsMap.emplace(id, subValue);
14128afb49cSJunLin Chen 
14228afb49cSJunLin Chen             updateNoOfSubscribersCount();
14328afb49cSJunLin Chen 
14428afb49cSJunLin Chen             // Update retry configuration.
14528afb49cSJunLin Chen             subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
1461bf712bcSAyushi Smriti         }
1471bf712bcSAyushi Smriti     }
1481bf712bcSAyushi Smriti 
14956d2396dSEd Tanous     static void loadOldBehavior()
150b52664e2SAppaRao Puli     {
15128afb49cSJunLin Chen         std::ifstream eventConfigFile(eventServiceFile);
15228afb49cSJunLin Chen         if (!eventConfigFile.good())
1531bf712bcSAyushi Smriti         {
15462598e31SEd Tanous             BMCWEB_LOG_DEBUG("Old eventService config not exist");
15528afb49cSJunLin Chen             return;
15628afb49cSJunLin Chen         }
15728afb49cSJunLin Chen         auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false);
15828afb49cSJunLin Chen         if (jsonData.is_discarded())
1594bbf237fSAppaRao Puli         {
16062598e31SEd Tanous             BMCWEB_LOG_ERROR("Old eventService config parse error.");
16128afb49cSJunLin Chen             return;
16228afb49cSJunLin Chen         }
16328afb49cSJunLin Chen 
1640bdda665SEd Tanous         const nlohmann::json::object_t* obj =
1650bdda665SEd Tanous             jsonData.get_ptr<const nlohmann::json::object_t*>();
1660bdda665SEd Tanous         for (const auto& item : *obj)
16728afb49cSJunLin Chen         {
1680bdda665SEd Tanous             if (item.first == "Configuration")
16928afb49cSJunLin Chen             {
17028afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
17128afb49cSJunLin Chen                     .getEventServiceConfig()
1720bdda665SEd Tanous                     .fromJson(item.second);
17328afb49cSJunLin Chen             }
1740bdda665SEd Tanous             else if (item.first == "Subscriptions")
17528afb49cSJunLin Chen             {
1760bdda665SEd Tanous                 for (const auto& elem : item.second)
17728afb49cSJunLin Chen                 {
1784b712a29SEd Tanous                     std::optional<persistent_data::UserSubscription>
17928afb49cSJunLin Chen                         newSubscription =
18028afb49cSJunLin Chen                             persistent_data::UserSubscription::fromJson(elem,
18128afb49cSJunLin Chen                                                                         true);
1824b712a29SEd Tanous                     if (!newSubscription)
18328afb49cSJunLin Chen                     {
18462598e31SEd Tanous                         BMCWEB_LOG_ERROR("Problem reading subscription "
18562598e31SEd Tanous                                          "from old persistent store");
1864bbf237fSAppaRao Puli                         continue;
1874bbf237fSAppaRao Puli                     }
1884b712a29SEd Tanous                     persistent_data::UserSubscription& newSub =
1894b712a29SEd Tanous                         *newSubscription;
1901bf712bcSAyushi Smriti 
19128afb49cSJunLin Chen                     std::uniform_int_distribution<uint32_t> dist(0);
19228afb49cSJunLin Chen                     bmcweb::OpenSSLGenerator gen;
1931bf712bcSAyushi Smriti 
19428afb49cSJunLin Chen                     std::string id;
1951bf712bcSAyushi Smriti 
19628afb49cSJunLin Chen                     int retry = 3;
197e662eae8SEd Tanous                     while (retry != 0)
1981bf712bcSAyushi Smriti                     {
19928afb49cSJunLin Chen                         id = std::to_string(dist(gen));
20028afb49cSJunLin Chen                         if (gen.error())
2017d1cc387SAppaRao Puli                         {
20228afb49cSJunLin Chen                             retry = 0;
20328afb49cSJunLin Chen                             break;
20428afb49cSJunLin Chen                         }
2054b712a29SEd Tanous                         newSub.id = id;
20628afb49cSJunLin Chen                         auto inserted =
20728afb49cSJunLin Chen                             persistent_data::EventServiceStore::getInstance()
2085fe4ef35SMyung Bae                                 .subscriptionsConfigMap.insert(std::pair(
2095fe4ef35SMyung Bae                                     id, std::make_shared<
2105fe4ef35SMyung Bae                                             persistent_data::UserSubscription>(
2115fe4ef35SMyung Bae                                             newSub)));
21228afb49cSJunLin Chen                         if (inserted.second)
21328afb49cSJunLin Chen                         {
21428afb49cSJunLin Chen                             break;
21528afb49cSJunLin Chen                         }
21628afb49cSJunLin Chen                         --retry;
2177d1cc387SAppaRao Puli                     }
2187d1cc387SAppaRao Puli 
21928afb49cSJunLin Chen                     if (retry <= 0)
22028afb49cSJunLin Chen                     {
22162598e31SEd Tanous                         BMCWEB_LOG_ERROR(
22262598e31SEd Tanous                             "Failed to generate random number from old "
22362598e31SEd Tanous                             "persistent store");
22428afb49cSJunLin Chen                         continue;
22528afb49cSJunLin Chen                     }
22628afb49cSJunLin Chen                 }
22728afb49cSJunLin Chen             }
22828afb49cSJunLin Chen 
22928afb49cSJunLin Chen             persistent_data::getConfig().writeData();
2304c521c3cSEd Tanous             std::error_code ec;
2314c521c3cSEd Tanous             std::filesystem::remove(eventServiceFile, ec);
2324c521c3cSEd Tanous             if (ec)
2334c521c3cSEd Tanous             {
2344c521c3cSEd Tanous                 BMCWEB_LOG_DEBUG(
2354c521c3cSEd Tanous                     "Failed to remove old event service file.  Ignoring");
2364c521c3cSEd Tanous             }
2374c521c3cSEd Tanous             else
2384c521c3cSEd Tanous             {
23962598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remove old eventservice config");
24028afb49cSJunLin Chen             }
24128afb49cSJunLin Chen         }
2424c521c3cSEd Tanous     }
24328afb49cSJunLin Chen 
2449eb808c1SEd Tanous     void updateSubscriptionData() const
24528afb49cSJunLin Chen     {
24628afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
24728afb49cSJunLin Chen             .eventServiceConfig.enabled = serviceEnabled;
24828afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
24928afb49cSJunLin Chen             .eventServiceConfig.retryAttempts = retryAttempts;
25028afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
25128afb49cSJunLin Chen             .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval;
25228afb49cSJunLin Chen 
25328afb49cSJunLin Chen         persistent_data::getConfig().writeData();
25428afb49cSJunLin Chen     }
25528afb49cSJunLin Chen 
25628afb49cSJunLin Chen     void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg)
2577d1cc387SAppaRao Puli     {
2587d1cc387SAppaRao Puli         bool updateConfig = false;
259fe44eb0bSAyushi Smriti         bool updateRetryCfg = false;
2607d1cc387SAppaRao Puli 
2612ac69850SEd Tanous         if (serviceEnabled)
2627d1cc387SAppaRao Puli         {
263*7b669723SEd Tanous             if (noOfEventLogSubscribers > 0U)
264*7b669723SEd Tanous             {
265*7b669723SEd Tanous                 if constexpr (!BMCWEB_REDFISH_DBUS_LOG)
266*7b669723SEd Tanous                 {
267*7b669723SEd Tanous                     if (!filesystemLogMonitor)
268*7b669723SEd Tanous                     {
269*7b669723SEd Tanous                         filesystemLogMonitor.emplace(ioc);
270*7b669723SEd Tanous                     }
271*7b669723SEd Tanous                 }
272*7b669723SEd Tanous             }
273*7b669723SEd Tanous             else
274*7b669723SEd Tanous             {
275*7b669723SEd Tanous                 filesystemLogMonitor.reset();
276*7b669723SEd Tanous             }
277*7b669723SEd Tanous 
2782ac69850SEd Tanous             if (noOfMetricReportSubscribers > 0U)
2797d1cc387SAppaRao Puli             {
2802ac69850SEd Tanous                 if (!matchTelemetryMonitor)
2812ac69850SEd Tanous                 {
2822ac69850SEd Tanous                     matchTelemetryMonitor.emplace();
2832ac69850SEd Tanous                 }
2847d1cc387SAppaRao Puli             }
2857d1cc387SAppaRao Puli             else
2867d1cc387SAppaRao Puli             {
2872ac69850SEd Tanous                 matchTelemetryMonitor.reset();
2887d1cc387SAppaRao Puli             }
2892ac69850SEd Tanous         }
2902ac69850SEd Tanous         else
2912ac69850SEd Tanous         {
2922ac69850SEd Tanous             matchTelemetryMonitor.reset();
293*7b669723SEd Tanous             filesystemLogMonitor.reset();
2942ac69850SEd Tanous         }
2952ac69850SEd Tanous 
2962ac69850SEd Tanous         if (serviceEnabled != cfg.enabled)
2972ac69850SEd Tanous         {
2982ac69850SEd Tanous             serviceEnabled = cfg.enabled;
2997d1cc387SAppaRao Puli             updateConfig = true;
3007d1cc387SAppaRao Puli         }
3017d1cc387SAppaRao Puli 
30228afb49cSJunLin Chen         if (retryAttempts != cfg.retryAttempts)
3037d1cc387SAppaRao Puli         {
30428afb49cSJunLin Chen             retryAttempts = cfg.retryAttempts;
3057d1cc387SAppaRao Puli             updateConfig = true;
306fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3077d1cc387SAppaRao Puli         }
3087d1cc387SAppaRao Puli 
30928afb49cSJunLin Chen         if (retryTimeoutInterval != cfg.retryTimeoutInterval)
3107d1cc387SAppaRao Puli         {
31128afb49cSJunLin Chen             retryTimeoutInterval = cfg.retryTimeoutInterval;
3127d1cc387SAppaRao Puli             updateConfig = true;
313fe44eb0bSAyushi Smriti             updateRetryCfg = true;
3147d1cc387SAppaRao Puli         }
3157d1cc387SAppaRao Puli 
3167d1cc387SAppaRao Puli         if (updateConfig)
3177d1cc387SAppaRao Puli         {
3187d1cc387SAppaRao Puli             updateSubscriptionData();
3197d1cc387SAppaRao Puli         }
320fe44eb0bSAyushi Smriti 
321fe44eb0bSAyushi Smriti         if (updateRetryCfg)
322fe44eb0bSAyushi Smriti         {
323fe44eb0bSAyushi Smriti             // Update the changed retry config to all subscriptions
324fe44eb0bSAyushi Smriti             for (const auto& it :
325fe44eb0bSAyushi Smriti                  EventServiceManager::getInstance().subscriptionsMap)
326fe44eb0bSAyushi Smriti             {
3275e44e3d8SAppaRao Puli                 Subscription& entry = *it.second;
3285e44e3d8SAppaRao Puli                 entry.updateRetryConfig(retryAttempts, retryTimeoutInterval);
329fe44eb0bSAyushi Smriti             }
330fe44eb0bSAyushi Smriti         }
3317d1cc387SAppaRao Puli     }
3327d1cc387SAppaRao Puli 
3337d1cc387SAppaRao Puli     void updateNoOfSubscribersCount()
3347d1cc387SAppaRao Puli     {
3357d1cc387SAppaRao Puli         size_t eventLogSubCount = 0;
3367d1cc387SAppaRao Puli         size_t metricReportSubCount = 0;
3377d1cc387SAppaRao Puli         for (const auto& it : subscriptionsMap)
3387d1cc387SAppaRao Puli         {
3397d1cc387SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
3405fe4ef35SMyung Bae             if (entry->userSub->eventFormatType == eventFormatType)
3417d1cc387SAppaRao Puli             {
3427d1cc387SAppaRao Puli                 eventLogSubCount++;
3437d1cc387SAppaRao Puli             }
3445fe4ef35SMyung Bae             else if (entry->userSub->eventFormatType == metricReportFormatType)
3457d1cc387SAppaRao Puli             {
3467d1cc387SAppaRao Puli                 metricReportSubCount++;
3477d1cc387SAppaRao Puli             }
3487d1cc387SAppaRao Puli         }
3497d1cc387SAppaRao Puli 
3507d1cc387SAppaRao Puli         noOfEventLogSubscribers = eventLogSubCount;
3517d1cc387SAppaRao Puli         if (noOfMetricReportSubscribers != metricReportSubCount)
3527d1cc387SAppaRao Puli         {
3537d1cc387SAppaRao Puli             noOfMetricReportSubscribers = metricReportSubCount;
354e662eae8SEd Tanous             if (noOfMetricReportSubscribers != 0U)
3557d1cc387SAppaRao Puli             {
3562ac69850SEd Tanous                 if (!matchTelemetryMonitor)
3572ac69850SEd Tanous                 {
3582ac69850SEd Tanous                     matchTelemetryMonitor.emplace();
3592ac69850SEd Tanous                 }
3607d1cc387SAppaRao Puli             }
3617d1cc387SAppaRao Puli             else
3627d1cc387SAppaRao Puli             {
3632ac69850SEd Tanous                 matchTelemetryMonitor.reset();
3647d1cc387SAppaRao Puli             }
3657d1cc387SAppaRao Puli         }
3667d1cc387SAppaRao Puli     }
3677d1cc387SAppaRao Puli 
368b52664e2SAppaRao Puli     std::shared_ptr<Subscription> getSubscription(const std::string& id)
369b52664e2SAppaRao Puli     {
370b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
371b52664e2SAppaRao Puli         if (obj == subscriptionsMap.end())
372b52664e2SAppaRao Puli         {
37362598e31SEd Tanous             BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id);
374b52664e2SAppaRao Puli             return nullptr;
375b52664e2SAppaRao Puli         }
376b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue = obj->second;
377b52664e2SAppaRao Puli         return subValue;
378b52664e2SAppaRao Puli     }
379b52664e2SAppaRao Puli 
380f80a87f2SEd Tanous     std::string
381f80a87f2SEd Tanous         addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue)
382b52664e2SAppaRao Puli     {
383fc76b8acSEd Tanous         std::uniform_int_distribution<uint32_t> dist(0);
384fc76b8acSEd Tanous         bmcweb::OpenSSLGenerator gen;
385fc76b8acSEd Tanous 
386b52664e2SAppaRao Puli         std::string id;
387b52664e2SAppaRao Puli 
388b52664e2SAppaRao Puli         int retry = 3;
389e662eae8SEd Tanous         while (retry != 0)
390b52664e2SAppaRao Puli         {
391fc76b8acSEd Tanous             id = std::to_string(dist(gen));
392fc76b8acSEd Tanous             if (gen.error())
393fc76b8acSEd Tanous             {
394fc76b8acSEd Tanous                 retry = 0;
395fc76b8acSEd Tanous                 break;
396fc76b8acSEd Tanous             }
397b52664e2SAppaRao Puli             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
398b52664e2SAppaRao Puli             if (inserted.second)
399b52664e2SAppaRao Puli             {
400b52664e2SAppaRao Puli                 break;
401b52664e2SAppaRao Puli             }
402b52664e2SAppaRao Puli             --retry;
40323a21a1cSEd Tanous         }
404b52664e2SAppaRao Puli 
405b52664e2SAppaRao Puli         if (retry <= 0)
406b52664e2SAppaRao Puli         {
40762598e31SEd Tanous             BMCWEB_LOG_ERROR("Failed to generate random number");
408abb93cddSEd Tanous             return "";
409b52664e2SAppaRao Puli         }
410b52664e2SAppaRao Puli 
41156ba386dSMyung Bae         // Set Subscription ID for back trace
4125fe4ef35SMyung Bae         subValue->userSub->id = id;
413a14c9113SEd Tanous 
41428afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4155fe4ef35SMyung Bae             .subscriptionsConfigMap.emplace(id, subValue->userSub);
41628afb49cSJunLin Chen 
4177d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
4181bf712bcSAyushi Smriti 
419fe44eb0bSAyushi Smriti         // Update retry configuration.
420fe44eb0bSAyushi Smriti         subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
421fe44eb0bSAyushi Smriti 
422f80a87f2SEd Tanous         return id;
423f80a87f2SEd Tanous     }
424f80a87f2SEd Tanous 
425f80a87f2SEd Tanous     std::string
426f80a87f2SEd Tanous         addSSESubscription(const std::shared_ptr<Subscription>& subValue,
427f80a87f2SEd Tanous                            std::string_view lastEventId)
428f80a87f2SEd Tanous     {
429f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
430f80a87f2SEd Tanous 
431f80a87f2SEd Tanous         if (!lastEventId.empty())
432f80a87f2SEd Tanous         {
433f80a87f2SEd Tanous             BMCWEB_LOG_INFO("Attempting to find message for last id {}",
434f80a87f2SEd Tanous                             lastEventId);
435f80a87f2SEd Tanous             boost::circular_buffer<Event>::iterator lastEvent =
436f80a87f2SEd Tanous                 std::find_if(messages.begin(), messages.end(),
437f80a87f2SEd Tanous                              [&lastEventId](const Event& event) {
438f80a87f2SEd Tanous                                  return event.id == lastEventId;
439f80a87f2SEd Tanous                              });
440f80a87f2SEd Tanous             // Can't find a matching ID
441f80a87f2SEd Tanous             if (lastEvent == messages.end())
442f80a87f2SEd Tanous             {
443f80a87f2SEd Tanous                 nlohmann::json msg = messages::eventBufferExceeded();
444f80a87f2SEd Tanous                 // If the buffer overloaded, send all messages.
4456d799e14SEd Tanous                 subValue->sendEventToSubscriber(msg);
446f80a87f2SEd Tanous                 lastEvent = messages.begin();
447f80a87f2SEd Tanous             }
448f80a87f2SEd Tanous             else
449f80a87f2SEd Tanous             {
450f80a87f2SEd Tanous                 // Skip the last event the user already has
451f80a87f2SEd Tanous                 lastEvent++;
452f80a87f2SEd Tanous             }
453f80a87f2SEd Tanous 
454f80a87f2SEd Tanous             for (boost::circular_buffer<Event>::const_iterator event =
455f80a87f2SEd Tanous                      lastEvent;
456f80a87f2SEd Tanous                  lastEvent != messages.end(); lastEvent++)
457f80a87f2SEd Tanous             {
4586d799e14SEd Tanous                 subValue->sendEventToSubscriber(event->message);
459f80a87f2SEd Tanous             }
460f80a87f2SEd Tanous         }
461f80a87f2SEd Tanous         return id;
462f80a87f2SEd Tanous     }
463f80a87f2SEd Tanous 
464f80a87f2SEd Tanous     std::string
465f80a87f2SEd Tanous         addPushSubscription(const std::shared_ptr<Subscription>& subValue)
466f80a87f2SEd Tanous     {
467f80a87f2SEd Tanous         std::string id = addSubscriptionInternal(subValue);
468a0969c70SMyung Bae         subValue->deleter = [id]() {
469a0969c70SMyung Bae             EventServiceManager::getInstance().deleteSubscription(id);
470a0969c70SMyung Bae         };
471f80a87f2SEd Tanous         updateSubscriptionData();
472b52664e2SAppaRao Puli         return id;
473b52664e2SAppaRao Puli     }
474b52664e2SAppaRao Puli 
475b52664e2SAppaRao Puli     bool isSubscriptionExist(const std::string& id)
476b52664e2SAppaRao Puli     {
477b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
47855f79e6fSEd Tanous         return obj != subscriptionsMap.end();
479b52664e2SAppaRao Puli     }
480b52664e2SAppaRao Puli 
4814b712a29SEd Tanous     bool deleteSubscription(const std::string& id)
482b52664e2SAppaRao Puli     {
483b52664e2SAppaRao Puli         auto obj = subscriptionsMap.find(id);
4844b712a29SEd Tanous         if (obj == subscriptionsMap.end())
485b52664e2SAppaRao Puli         {
4864b712a29SEd Tanous             BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
4874b712a29SEd Tanous             return false;
4884b712a29SEd Tanous         }
489b52664e2SAppaRao Puli         subscriptionsMap.erase(obj);
4904b712a29SEd Tanous         auto& event = persistent_data::EventServiceStore::getInstance();
4914b712a29SEd Tanous         auto persistentObj = event.subscriptionsConfigMap.find(id);
4924b712a29SEd Tanous         if (persistentObj == event.subscriptionsConfigMap.end())
4934b712a29SEd Tanous         {
4944b712a29SEd Tanous             BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
4954b712a29SEd Tanous             return true;
4964b712a29SEd Tanous         }
49728afb49cSJunLin Chen         persistent_data::EventServiceStore::getInstance()
4984b712a29SEd Tanous             .subscriptionsConfigMap.erase(persistentObj);
4997d1cc387SAppaRao Puli         updateNoOfSubscribersCount();
500b52664e2SAppaRao Puli         updateSubscriptionData();
5014b712a29SEd Tanous 
5024b712a29SEd Tanous         return true;
503b52664e2SAppaRao Puli     }
504b52664e2SAppaRao Puli 
5055e44e3d8SAppaRao Puli     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
5065e44e3d8SAppaRao Puli     {
507bdbfae2aSEd Tanous         for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();)
5085e44e3d8SAppaRao Puli         {
509bdbfae2aSEd Tanous             std::shared_ptr<Subscription> entry = it->second;
5105e44e3d8SAppaRao Puli             bool entryIsThisConn = entry->matchSseId(thisConn);
5115e44e3d8SAppaRao Puli             if (entryIsThisConn)
5125e44e3d8SAppaRao Puli             {
5135e44e3d8SAppaRao Puli                 persistent_data::EventServiceStore::getInstance()
5145fe4ef35SMyung Bae                     .subscriptionsConfigMap.erase(entry->userSub->id);
515bdbfae2aSEd Tanous                 it = subscriptionsMap.erase(it);
5165e44e3d8SAppaRao Puli                 return;
5175e44e3d8SAppaRao Puli             }
518bdbfae2aSEd Tanous             it++;
5195e44e3d8SAppaRao Puli         }
5205e44e3d8SAppaRao Puli     }
5215e44e3d8SAppaRao Puli 
5225e44e3d8SAppaRao Puli     size_t getNumberOfSubscriptions() const
523b52664e2SAppaRao Puli     {
524b52664e2SAppaRao Puli         return subscriptionsMap.size();
525b52664e2SAppaRao Puli     }
526b52664e2SAppaRao Puli 
5275e44e3d8SAppaRao Puli     size_t getNumberOfSSESubscriptions() const
5285e44e3d8SAppaRao Puli     {
5293544d2a7SEd Tanous         auto size = std::ranges::count_if(
5303544d2a7SEd Tanous             subscriptionsMap,
5315e44e3d8SAppaRao Puli             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
5325e44e3d8SAppaRao Puli                    entry) {
5335fe4ef35SMyung Bae                 return (entry.second->userSub->subscriptionType ==
5344b712a29SEd Tanous                         subscriptionTypeSSE);
5355e44e3d8SAppaRao Puli             });
5365e44e3d8SAppaRao Puli         return static_cast<size_t>(size);
5375e44e3d8SAppaRao Puli     }
5385e44e3d8SAppaRao Puli 
539b52664e2SAppaRao Puli     std::vector<std::string> getAllIDs()
540b52664e2SAppaRao Puli     {
541b52664e2SAppaRao Puli         std::vector<std::string> idList;
542b52664e2SAppaRao Puli         for (const auto& it : subscriptionsMap)
543b52664e2SAppaRao Puli         {
544b52664e2SAppaRao Puli             idList.emplace_back(it.first);
545b52664e2SAppaRao Puli         }
546b52664e2SAppaRao Puli         return idList;
547b52664e2SAppaRao Puli     }
548b52664e2SAppaRao Puli 
5496ba8c82eSsunharis_in     bool sendTestEventLog()
5500b4bdd93SAppaRao Puli     {
5515e44e3d8SAppaRao Puli         for (const auto& it : subscriptionsMap)
5520b4bdd93SAppaRao Puli         {
5530b4bdd93SAppaRao Puli             std::shared_ptr<Subscription> entry = it.second;
5546ba8c82eSsunharis_in             if (!entry->sendTestEventLog())
5556ba8c82eSsunharis_in             {
5566ba8c82eSsunharis_in                 return false;
5570b4bdd93SAppaRao Puli             }
5580b4bdd93SAppaRao Puli         }
5596ba8c82eSsunharis_in         return true;
5606ba8c82eSsunharis_in     }
561e9a14131SAppaRao Puli 
5623433b03aSEd Tanous     static void
5633433b03aSEd Tanous         sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords)
5643433b03aSEd Tanous     {
5653433b03aSEd Tanous         for (const auto& it :
5663433b03aSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
5673433b03aSEd Tanous         {
5683433b03aSEd Tanous             Subscription& entry = *it.second;
5693433b03aSEd Tanous             entry.filterAndSendEventLogs(eventRecords);
5703433b03aSEd Tanous         }
5713433b03aSEd Tanous     }
5723433b03aSEd Tanous 
573b26ff34dSEd Tanous     static void sendTelemetryReportToSubs(
574b26ff34dSEd Tanous         const std::string& reportId, const telemetry::TimestampReadings& var)
575b26ff34dSEd Tanous     {
576b26ff34dSEd Tanous         for (const auto& it :
577b26ff34dSEd Tanous              EventServiceManager::getInstance().subscriptionsMap)
578b26ff34dSEd Tanous         {
579b26ff34dSEd Tanous             Subscription& entry = *it.second;
580b26ff34dSEd Tanous             entry.filterAndSendReports(reportId, var);
581b26ff34dSEd Tanous         }
582b26ff34dSEd Tanous     }
583b26ff34dSEd Tanous 
584f80a87f2SEd Tanous     void sendEvent(nlohmann::json::object_t eventMessage,
585f80a87f2SEd Tanous                    std::string_view origin, std::string_view resourceType)
58696330b99SSunitha Harish     {
587613dabeaSEd Tanous         eventMessage["EventId"] = eventId;
588f80a87f2SEd Tanous 
589613dabeaSEd Tanous         eventMessage["EventTimestamp"] =
590613dabeaSEd Tanous             redfish::time_utils::getDateTimeOffsetNow().first;
591613dabeaSEd Tanous         eventMessage["OriginOfCondition"] = origin;
592613dabeaSEd Tanous 
593f80a87f2SEd Tanous         // MemberId is 0 : since we are sending one event record.
594788b091bSIgor Kanyuka         eventMessage["MemberId"] = "0";
59596330b99SSunitha Harish 
596f80a87f2SEd Tanous         messages.push_back(Event(std::to_string(eventId), eventMessage));
597f80a87f2SEd Tanous 
598f80a87f2SEd Tanous         for (auto& it : subscriptionsMap)
59996330b99SSunitha Harish         {
600f80a87f2SEd Tanous             std::shared_ptr<Subscription>& entry = it.second;
6015fe4ef35SMyung Bae             if (!eventMatchesFilter(*entry->userSub, eventMessage,
6025fe4ef35SMyung Bae                                     resourceType))
60396330b99SSunitha Harish             {
604f80a87f2SEd Tanous                 BMCWEB_LOG_DEBUG("Filter didn't match");
605f80a87f2SEd Tanous                 continue;
60696330b99SSunitha Harish             }
607f80a87f2SEd Tanous 
608f80a87f2SEd Tanous             nlohmann::json::array_t eventRecord;
609f80a87f2SEd Tanous             eventRecord.emplace_back(eventMessage);
610f80a87f2SEd Tanous 
611613dabeaSEd Tanous             nlohmann::json msgJson;
612613dabeaSEd Tanous 
613613dabeaSEd Tanous             msgJson["@odata.type"] = "#Event.v1_4_0.Event";
614613dabeaSEd Tanous             msgJson["Name"] = "Event Log";
615613dabeaSEd Tanous             msgJson["Id"] = eventId;
616f80a87f2SEd Tanous             msgJson["Events"] = std::move(eventRecord);
617f52c03c1SCarson Labrado 
618f52c03c1SCarson Labrado             std::string strMsg = msgJson.dump(
619f52c03c1SCarson Labrado                 2, ' ', true, nlohmann::json::error_handler_t::replace);
6206d799e14SEd Tanous             entry->sendEventToSubscriber(std::move(strMsg));
6218ece0e45SEd Tanous             eventId++; // increment the eventId
62296330b99SSunitha Harish         }
62396330b99SSunitha Harish     }
62423a21a1cSEd Tanous };
625b52664e2SAppaRao Puli 
626b52664e2SAppaRao Puli } // namespace redfish
627