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" 18fb546105SMyung Bae #include "dbus_singleton.hpp" 193ccb3adbSEd Tanous #include "dbus_utility.hpp" 203ccb3adbSEd Tanous #include "error_messages.hpp" 21b80ba2e4SAlexander Hansen #include "event_log.hpp" 22d3a48a14SEd Tanous #include "event_matches_filter.hpp" 233ccb3adbSEd Tanous #include "event_service_store.hpp" 242185ddeaSEd Tanous #include "filesystem_log_watcher.hpp" 25c0353249SWludzik, Jozef #include "metric_report.hpp" 262c6ffdb0SEd Tanous #include "ossl_random.hpp" 273ccb3adbSEd Tanous #include "persistent_data.hpp" 2802c1e29fSAlexander Hansen #include "subscription.hpp" 292ac69850SEd Tanous #include "utility.hpp" 302ac69850SEd Tanous #include "utils/dbus_event_log_entry.hpp" 312ac69850SEd Tanous #include "utils/json_utils.hpp" 325b90429aSEd Tanous #include "utils/time_utils.hpp" 337f4eb588SAppaRao Puli 34fb4fd5d4SZhenfei Tai #include <boost/asio/io_context.hpp> 35fb546105SMyung Bae #include <boost/asio/steady_timer.hpp> 36f80a87f2SEd Tanous #include <boost/circular_buffer.hpp> 37b52664e2SAppaRao Puli #include <boost/container/flat_map.hpp> 38ef4c65b7SEd Tanous #include <boost/url/format.hpp> 394a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp> 401214b7e7SGunnar Mills 415e44e3d8SAppaRao Puli #include <algorithm> 42b52664e2SAppaRao Puli #include <cstdlib> 43b52664e2SAppaRao Puli #include <ctime> 44a14c9113SEd Tanous #include <format> 451bf712bcSAyushi Smriti #include <fstream> 46b52664e2SAppaRao Puli #include <memory> 47a14c9113SEd Tanous #include <string> 4856ba386dSMyung Bae #include <string_view> 495fe4ef35SMyung Bae #include <utility> 502ac69850SEd Tanous #include <variant> 51b52664e2SAppaRao Puli 52b52664e2SAppaRao Puli namespace redfish 53b52664e2SAppaRao Puli { 54156d6b00SAppaRao Puli 55156d6b00SAppaRao Puli static constexpr const char* eventFormatType = "Event"; 56156d6b00SAppaRao Puli static constexpr const char* metricReportFormatType = "MetricReport"; 57156d6b00SAppaRao Puli 581bf712bcSAyushi Smriti static constexpr const char* eventServiceFile = 591bf712bcSAyushi Smriti "/var/lib/bmcweb/eventservice_config.json"; 601bf712bcSAyushi Smriti 61b52664e2SAppaRao Puli class EventServiceManager 62b52664e2SAppaRao Puli { 63b52664e2SAppaRao Puli private: 64d3a9e084SEd Tanous bool serviceEnabled = false; 65d3a9e084SEd Tanous uint32_t retryAttempts = 0; 66d3a9e084SEd Tanous uint32_t retryTimeoutInterval = 0; 677d1cc387SAppaRao Puli 689f616dd1SEd Tanous size_t noOfEventLogSubscribers{0}; 699f616dd1SEd Tanous size_t noOfMetricReportSubscribers{0}; 706c58a03eSAlexander Hansen std::optional<DbusEventLogMonitor> dbusEventLogMonitor; 712ac69850SEd Tanous std::optional<DbusTelemetryMonitor> matchTelemetryMonitor; 727b669723SEd Tanous std::optional<FilesystemLogWatcher> filesystemLogMonitor; 73b52664e2SAppaRao Puli boost::container::flat_map<std::string, std::shared_ptr<Subscription>> 74b52664e2SAppaRao Puli subscriptionsMap; 75b52664e2SAppaRao Puli 769f616dd1SEd Tanous uint64_t eventId{1}; 7796330b99SSunitha Harish 78f80a87f2SEd Tanous struct Event 79f80a87f2SEd Tanous { 80f80a87f2SEd Tanous std::string id; 81f80a87f2SEd Tanous nlohmann::json message; 82f80a87f2SEd Tanous }; 83f80a87f2SEd Tanous 84f80a87f2SEd Tanous constexpr static size_t maxMessages = 200; 85f80a87f2SEd Tanous boost::circular_buffer<Event> messages{maxMessages}; 86f80a87f2SEd Tanous 87f8ca6d79SEd Tanous boost::asio::io_context& ioc; 88f8ca6d79SEd Tanous 89b52664e2SAppaRao Puli public: 909f616dd1SEd Tanous EventServiceManager(const EventServiceManager&) = delete; 919f616dd1SEd Tanous EventServiceManager& operator=(const EventServiceManager&) = delete; 929f616dd1SEd Tanous EventServiceManager(EventServiceManager&&) = delete; 939f616dd1SEd Tanous EventServiceManager& operator=(EventServiceManager&&) = delete; 94ecd6a3a2SEd Tanous ~EventServiceManager() = default; 959f616dd1SEd Tanous 96f8ca6d79SEd Tanous explicit EventServiceManager(boost::asio::io_context& iocIn) : ioc(iocIn) 97b52664e2SAppaRao Puli { 98f8ca6d79SEd Tanous // Load config from persist store. 99f8ca6d79SEd Tanous initConfig(); 100f8ca6d79SEd Tanous } 101f8ca6d79SEd Tanous 102f8ca6d79SEd Tanous static EventServiceManager& 103f8ca6d79SEd Tanous getInstance(boost::asio::io_context* ioc = nullptr) 104f8ca6d79SEd Tanous { 105f8ca6d79SEd Tanous static EventServiceManager handler(*ioc); 106b52664e2SAppaRao Puli return handler; 107b52664e2SAppaRao Puli } 108b52664e2SAppaRao Puli 1091bf712bcSAyushi Smriti void initConfig() 1101bf712bcSAyushi Smriti { 11128afb49cSJunLin Chen loadOldBehavior(); 1121bf712bcSAyushi Smriti 11328afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 11428afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 11528afb49cSJunLin Chen .getEventServiceConfig(); 1161bf712bcSAyushi Smriti 11728afb49cSJunLin Chen serviceEnabled = eventServiceConfig.enabled; 11828afb49cSJunLin Chen retryAttempts = eventServiceConfig.retryAttempts; 11928afb49cSJunLin Chen retryTimeoutInterval = eventServiceConfig.retryTimeoutInterval; 1201bf712bcSAyushi Smriti 12128afb49cSJunLin Chen for (const auto& it : persistent_data::EventServiceStore::getInstance() 12228afb49cSJunLin Chen .subscriptionsConfigMap) 1231bf712bcSAyushi Smriti { 1245fe4ef35SMyung Bae std::shared_ptr<persistent_data::UserSubscription> newSub = 1255fe4ef35SMyung Bae it.second; 1264bbf237fSAppaRao Puli 1276fd29553SEd Tanous boost::system::result<boost::urls::url> url = 1285fe4ef35SMyung Bae boost::urls::parse_absolute_uri(newSub->destinationUrl); 1291bf712bcSAyushi Smriti 130a716aa74SEd Tanous if (!url) 1311bf712bcSAyushi Smriti { 13262598e31SEd Tanous BMCWEB_LOG_ERROR( 13362598e31SEd Tanous "Failed to validate and split destination url"); 1341bf712bcSAyushi Smriti continue; 1351bf712bcSAyushi Smriti } 1361bf712bcSAyushi Smriti std::shared_ptr<Subscription> subValue = 13721a94d5cSMyung Bae std::make_shared<Subscription>(newSub, *url, ioc); 1385fe4ef35SMyung Bae std::string id = subValue->userSub->id; 139a0969c70SMyung Bae subValue->deleter = [id]() { 140a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 141a0969c70SMyung Bae }; 1421bf712bcSAyushi Smriti 143a0969c70SMyung Bae subscriptionsMap.emplace(id, subValue); 14428afb49cSJunLin Chen 14528afb49cSJunLin Chen updateNoOfSubscribersCount(); 14628afb49cSJunLin Chen 14728afb49cSJunLin Chen // Update retry configuration. 14828afb49cSJunLin Chen subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 149fb546105SMyung Bae 150fb546105SMyung Bae // schedule a heartbeat if sendHeartbeat was set to true 151fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 152fb546105SMyung Bae { 153fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 154fb546105SMyung Bae } 1551bf712bcSAyushi Smriti } 1561bf712bcSAyushi Smriti } 1571bf712bcSAyushi Smriti 15856d2396dSEd Tanous static void loadOldBehavior() 159b52664e2SAppaRao Puli { 16028afb49cSJunLin Chen std::ifstream eventConfigFile(eventServiceFile); 16128afb49cSJunLin Chen if (!eventConfigFile.good()) 1621bf712bcSAyushi Smriti { 16362598e31SEd Tanous BMCWEB_LOG_DEBUG("Old eventService config not exist"); 16428afb49cSJunLin Chen return; 16528afb49cSJunLin Chen } 16628afb49cSJunLin Chen auto jsonData = nlohmann::json::parse(eventConfigFile, nullptr, false); 16728afb49cSJunLin Chen if (jsonData.is_discarded()) 1684bbf237fSAppaRao Puli { 16962598e31SEd Tanous BMCWEB_LOG_ERROR("Old eventService config parse error."); 17028afb49cSJunLin Chen return; 17128afb49cSJunLin Chen } 17228afb49cSJunLin Chen 1730bdda665SEd Tanous const nlohmann::json::object_t* obj = 1740bdda665SEd Tanous jsonData.get_ptr<const nlohmann::json::object_t*>(); 175*1c588de9SAbiola Asojo if (obj == nullptr) 176*1c588de9SAbiola Asojo { 177*1c588de9SAbiola Asojo return; 178*1c588de9SAbiola Asojo } 1790bdda665SEd Tanous for (const auto& item : *obj) 18028afb49cSJunLin Chen { 1810bdda665SEd Tanous if (item.first == "Configuration") 18228afb49cSJunLin Chen { 18328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 18428afb49cSJunLin Chen .getEventServiceConfig() 1850bdda665SEd Tanous .fromJson(item.second); 18628afb49cSJunLin Chen } 1870bdda665SEd Tanous else if (item.first == "Subscriptions") 18828afb49cSJunLin Chen { 1890bdda665SEd Tanous for (const auto& elem : item.second) 19028afb49cSJunLin Chen { 1914b712a29SEd Tanous std::optional<persistent_data::UserSubscription> 19228afb49cSJunLin Chen newSubscription = 19328afb49cSJunLin Chen persistent_data::UserSubscription::fromJson(elem, 19428afb49cSJunLin Chen true); 1954b712a29SEd Tanous if (!newSubscription) 19628afb49cSJunLin Chen { 19762598e31SEd Tanous BMCWEB_LOG_ERROR("Problem reading subscription " 19862598e31SEd Tanous "from old persistent store"); 1994bbf237fSAppaRao Puli continue; 2004bbf237fSAppaRao Puli } 2014b712a29SEd Tanous persistent_data::UserSubscription& newSub = 2024b712a29SEd Tanous *newSubscription; 2031bf712bcSAyushi Smriti 20428afb49cSJunLin Chen std::uniform_int_distribution<uint32_t> dist(0); 20528afb49cSJunLin Chen bmcweb::OpenSSLGenerator gen; 2061bf712bcSAyushi Smriti 20728afb49cSJunLin Chen std::string id; 2081bf712bcSAyushi Smriti 20928afb49cSJunLin Chen int retry = 3; 210e662eae8SEd Tanous while (retry != 0) 2111bf712bcSAyushi Smriti { 21228afb49cSJunLin Chen id = std::to_string(dist(gen)); 21328afb49cSJunLin Chen if (gen.error()) 2147d1cc387SAppaRao Puli { 21528afb49cSJunLin Chen retry = 0; 21628afb49cSJunLin Chen break; 21728afb49cSJunLin Chen } 2184b712a29SEd Tanous newSub.id = id; 21928afb49cSJunLin Chen auto inserted = 22028afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 2215fe4ef35SMyung Bae .subscriptionsConfigMap.insert(std::pair( 2225fe4ef35SMyung Bae id, std::make_shared< 2235fe4ef35SMyung Bae persistent_data::UserSubscription>( 2245fe4ef35SMyung Bae newSub))); 22528afb49cSJunLin Chen if (inserted.second) 22628afb49cSJunLin Chen { 22728afb49cSJunLin Chen break; 22828afb49cSJunLin Chen } 22928afb49cSJunLin Chen --retry; 2307d1cc387SAppaRao Puli } 2317d1cc387SAppaRao Puli 23228afb49cSJunLin Chen if (retry <= 0) 23328afb49cSJunLin Chen { 23462598e31SEd Tanous BMCWEB_LOG_ERROR( 23562598e31SEd Tanous "Failed to generate random number from old " 23662598e31SEd Tanous "persistent store"); 23728afb49cSJunLin Chen continue; 23828afb49cSJunLin Chen } 23928afb49cSJunLin Chen } 24028afb49cSJunLin Chen } 24128afb49cSJunLin Chen 24228afb49cSJunLin Chen persistent_data::getConfig().writeData(); 2434c521c3cSEd Tanous std::error_code ec; 2444c521c3cSEd Tanous std::filesystem::remove(eventServiceFile, ec); 2454c521c3cSEd Tanous if (ec) 2464c521c3cSEd Tanous { 2474c521c3cSEd Tanous BMCWEB_LOG_DEBUG( 2484c521c3cSEd Tanous "Failed to remove old event service file. Ignoring"); 2494c521c3cSEd Tanous } 2504c521c3cSEd Tanous else 2514c521c3cSEd Tanous { 25262598e31SEd Tanous BMCWEB_LOG_DEBUG("Remove old eventservice config"); 25328afb49cSJunLin Chen } 25428afb49cSJunLin Chen } 2554c521c3cSEd Tanous } 25628afb49cSJunLin Chen 2579eb808c1SEd Tanous void updateSubscriptionData() const 25828afb49cSJunLin Chen { 25928afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 26028afb49cSJunLin Chen .eventServiceConfig.enabled = serviceEnabled; 26128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 26228afb49cSJunLin Chen .eventServiceConfig.retryAttempts = retryAttempts; 26328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 26428afb49cSJunLin Chen .eventServiceConfig.retryTimeoutInterval = retryTimeoutInterval; 26528afb49cSJunLin Chen 26628afb49cSJunLin Chen persistent_data::getConfig().writeData(); 26728afb49cSJunLin Chen } 26828afb49cSJunLin Chen 26928afb49cSJunLin Chen void setEventServiceConfig(const persistent_data::EventServiceConfig& cfg) 2707d1cc387SAppaRao Puli { 2717d1cc387SAppaRao Puli bool updateConfig = false; 272fe44eb0bSAyushi Smriti bool updateRetryCfg = false; 2737d1cc387SAppaRao Puli 2742ac69850SEd Tanous if (serviceEnabled) 2757d1cc387SAppaRao Puli { 2767b669723SEd Tanous if (noOfEventLogSubscribers > 0U) 2777b669723SEd Tanous { 2786c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 2796c58a03eSAlexander Hansen { 2806c58a03eSAlexander Hansen if (!dbusEventLogMonitor) 2816c58a03eSAlexander Hansen { 2826c58a03eSAlexander Hansen if constexpr ( 2836c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 2846c58a03eSAlexander Hansen { 2856c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 2866c58a03eSAlexander Hansen } 2876c58a03eSAlexander Hansen } 2886c58a03eSAlexander Hansen } 2896c58a03eSAlexander Hansen else 2907b669723SEd Tanous { 2917b669723SEd Tanous if (!filesystemLogMonitor) 2927b669723SEd Tanous { 2937b669723SEd Tanous filesystemLogMonitor.emplace(ioc); 2947b669723SEd Tanous } 2957b669723SEd Tanous } 2967b669723SEd Tanous } 2977b669723SEd Tanous else 2987b669723SEd Tanous { 2996c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3007b669723SEd Tanous filesystemLogMonitor.reset(); 3017b669723SEd Tanous } 3027b669723SEd Tanous 3032ac69850SEd Tanous if (noOfMetricReportSubscribers > 0U) 3047d1cc387SAppaRao Puli { 3052ac69850SEd Tanous if (!matchTelemetryMonitor) 3062ac69850SEd Tanous { 3072ac69850SEd Tanous matchTelemetryMonitor.emplace(); 3082ac69850SEd Tanous } 3097d1cc387SAppaRao Puli } 3107d1cc387SAppaRao Puli else 3117d1cc387SAppaRao Puli { 3122ac69850SEd Tanous matchTelemetryMonitor.reset(); 3137d1cc387SAppaRao Puli } 3142ac69850SEd Tanous } 3152ac69850SEd Tanous else 3162ac69850SEd Tanous { 3172ac69850SEd Tanous matchTelemetryMonitor.reset(); 3186c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3197b669723SEd Tanous filesystemLogMonitor.reset(); 3202ac69850SEd Tanous } 3212ac69850SEd Tanous 3222ac69850SEd Tanous if (serviceEnabled != cfg.enabled) 3232ac69850SEd Tanous { 3242ac69850SEd Tanous serviceEnabled = cfg.enabled; 3257d1cc387SAppaRao Puli updateConfig = true; 3267d1cc387SAppaRao Puli } 3277d1cc387SAppaRao Puli 32828afb49cSJunLin Chen if (retryAttempts != cfg.retryAttempts) 3297d1cc387SAppaRao Puli { 33028afb49cSJunLin Chen retryAttempts = cfg.retryAttempts; 3317d1cc387SAppaRao Puli updateConfig = true; 332fe44eb0bSAyushi Smriti updateRetryCfg = true; 3337d1cc387SAppaRao Puli } 3347d1cc387SAppaRao Puli 33528afb49cSJunLin Chen if (retryTimeoutInterval != cfg.retryTimeoutInterval) 3367d1cc387SAppaRao Puli { 33728afb49cSJunLin Chen retryTimeoutInterval = cfg.retryTimeoutInterval; 3387d1cc387SAppaRao Puli updateConfig = true; 339fe44eb0bSAyushi Smriti updateRetryCfg = true; 3407d1cc387SAppaRao Puli } 3417d1cc387SAppaRao Puli 3427d1cc387SAppaRao Puli if (updateConfig) 3437d1cc387SAppaRao Puli { 3447d1cc387SAppaRao Puli updateSubscriptionData(); 3457d1cc387SAppaRao Puli } 346fe44eb0bSAyushi Smriti 347fe44eb0bSAyushi Smriti if (updateRetryCfg) 348fe44eb0bSAyushi Smriti { 349fe44eb0bSAyushi Smriti // Update the changed retry config to all subscriptions 350fe44eb0bSAyushi Smriti for (const auto& it : 351fe44eb0bSAyushi Smriti EventServiceManager::getInstance().subscriptionsMap) 352fe44eb0bSAyushi Smriti { 3535e44e3d8SAppaRao Puli Subscription& entry = *it.second; 3545e44e3d8SAppaRao Puli entry.updateRetryConfig(retryAttempts, retryTimeoutInterval); 355fe44eb0bSAyushi Smriti } 356fe44eb0bSAyushi Smriti } 3577d1cc387SAppaRao Puli } 3587d1cc387SAppaRao Puli 3597d1cc387SAppaRao Puli void updateNoOfSubscribersCount() 3607d1cc387SAppaRao Puli { 3617d1cc387SAppaRao Puli size_t eventLogSubCount = 0; 3627d1cc387SAppaRao Puli size_t metricReportSubCount = 0; 3637d1cc387SAppaRao Puli for (const auto& it : subscriptionsMap) 3647d1cc387SAppaRao Puli { 3657d1cc387SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 3665fe4ef35SMyung Bae if (entry->userSub->eventFormatType == eventFormatType) 3677d1cc387SAppaRao Puli { 3687d1cc387SAppaRao Puli eventLogSubCount++; 3697d1cc387SAppaRao Puli } 3705fe4ef35SMyung Bae else if (entry->userSub->eventFormatType == metricReportFormatType) 3717d1cc387SAppaRao Puli { 3727d1cc387SAppaRao Puli metricReportSubCount++; 3737d1cc387SAppaRao Puli } 3747d1cc387SAppaRao Puli } 3757d1cc387SAppaRao Puli noOfEventLogSubscribers = eventLogSubCount; 3766c58a03eSAlexander Hansen if (eventLogSubCount > 0U) 3777d1cc387SAppaRao Puli { 3786c58a03eSAlexander Hansen if constexpr (BMCWEB_REDFISH_DBUS_LOG) 3796c58a03eSAlexander Hansen { 3806c58a03eSAlexander Hansen if (!dbusEventLogMonitor && 3816c58a03eSAlexander Hansen BMCWEB_EXPERIMENTAL_REDFISH_DBUS_LOG_SUBSCRIPTION) 3826c58a03eSAlexander Hansen { 3836c58a03eSAlexander Hansen dbusEventLogMonitor.emplace(); 3846c58a03eSAlexander Hansen } 3856c58a03eSAlexander Hansen } 3866c58a03eSAlexander Hansen else 3876c58a03eSAlexander Hansen { 3886c58a03eSAlexander Hansen if (!filesystemLogMonitor) 3896c58a03eSAlexander Hansen { 3906c58a03eSAlexander Hansen filesystemLogMonitor.emplace(ioc); 3916c58a03eSAlexander Hansen } 3926c58a03eSAlexander Hansen } 3936c58a03eSAlexander Hansen } 3946c58a03eSAlexander Hansen else 3956c58a03eSAlexander Hansen { 3966c58a03eSAlexander Hansen dbusEventLogMonitor.reset(); 3976c58a03eSAlexander Hansen filesystemLogMonitor.reset(); 3986c58a03eSAlexander Hansen } 3996c58a03eSAlexander Hansen 4007d1cc387SAppaRao Puli noOfMetricReportSubscribers = metricReportSubCount; 4016c58a03eSAlexander Hansen if (metricReportSubCount > 0U) 4027d1cc387SAppaRao Puli { 4032ac69850SEd Tanous if (!matchTelemetryMonitor) 4042ac69850SEd Tanous { 4052ac69850SEd Tanous matchTelemetryMonitor.emplace(); 4062ac69850SEd Tanous } 4077d1cc387SAppaRao Puli } 4087d1cc387SAppaRao Puli else 4097d1cc387SAppaRao Puli { 4102ac69850SEd Tanous matchTelemetryMonitor.reset(); 4117d1cc387SAppaRao Puli } 4127d1cc387SAppaRao Puli } 4137d1cc387SAppaRao Puli 414b52664e2SAppaRao Puli std::shared_ptr<Subscription> getSubscription(const std::string& id) 415b52664e2SAppaRao Puli { 416b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 417b52664e2SAppaRao Puli if (obj == subscriptionsMap.end()) 418b52664e2SAppaRao Puli { 41962598e31SEd Tanous BMCWEB_LOG_ERROR("No subscription exist with ID:{}", id); 420b52664e2SAppaRao Puli return nullptr; 421b52664e2SAppaRao Puli } 422b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = obj->second; 423b52664e2SAppaRao Puli return subValue; 424b52664e2SAppaRao Puli } 425b52664e2SAppaRao Puli 426f80a87f2SEd Tanous std::string 427f80a87f2SEd Tanous addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue) 428b52664e2SAppaRao Puli { 429fc76b8acSEd Tanous std::uniform_int_distribution<uint32_t> dist(0); 430fc76b8acSEd Tanous bmcweb::OpenSSLGenerator gen; 431fc76b8acSEd Tanous 432b52664e2SAppaRao Puli std::string id; 433b52664e2SAppaRao Puli 434b52664e2SAppaRao Puli int retry = 3; 435e662eae8SEd Tanous while (retry != 0) 436b52664e2SAppaRao Puli { 437fc76b8acSEd Tanous id = std::to_string(dist(gen)); 438fc76b8acSEd Tanous if (gen.error()) 439fc76b8acSEd Tanous { 440fc76b8acSEd Tanous retry = 0; 441fc76b8acSEd Tanous break; 442fc76b8acSEd Tanous } 443b52664e2SAppaRao Puli auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 444b52664e2SAppaRao Puli if (inserted.second) 445b52664e2SAppaRao Puli { 446b52664e2SAppaRao Puli break; 447b52664e2SAppaRao Puli } 448b52664e2SAppaRao Puli --retry; 44923a21a1cSEd Tanous } 450b52664e2SAppaRao Puli 451b52664e2SAppaRao Puli if (retry <= 0) 452b52664e2SAppaRao Puli { 45362598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to generate random number"); 454abb93cddSEd Tanous return ""; 455b52664e2SAppaRao Puli } 456b52664e2SAppaRao Puli 45756ba386dSMyung Bae // Set Subscription ID for back trace 4585fe4ef35SMyung Bae subValue->userSub->id = id; 459a14c9113SEd Tanous 46028afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 4615fe4ef35SMyung Bae .subscriptionsConfigMap.emplace(id, subValue->userSub); 46228afb49cSJunLin Chen 4637d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 4641bf712bcSAyushi Smriti 465fe44eb0bSAyushi Smriti // Update retry configuration. 466fe44eb0bSAyushi Smriti subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval); 467fe44eb0bSAyushi Smriti 468f80a87f2SEd Tanous return id; 469f80a87f2SEd Tanous } 470f80a87f2SEd Tanous 471f80a87f2SEd Tanous std::string 472f80a87f2SEd Tanous addSSESubscription(const std::shared_ptr<Subscription>& subValue, 473f80a87f2SEd Tanous std::string_view lastEventId) 474f80a87f2SEd Tanous { 475f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 476f80a87f2SEd Tanous 477f80a87f2SEd Tanous if (!lastEventId.empty()) 478f80a87f2SEd Tanous { 479f80a87f2SEd Tanous BMCWEB_LOG_INFO("Attempting to find message for last id {}", 480f80a87f2SEd Tanous lastEventId); 481f80a87f2SEd Tanous boost::circular_buffer<Event>::iterator lastEvent = 482f80a87f2SEd Tanous std::find_if(messages.begin(), messages.end(), 483f80a87f2SEd Tanous [&lastEventId](const Event& event) { 484f80a87f2SEd Tanous return event.id == lastEventId; 485f80a87f2SEd Tanous }); 486f80a87f2SEd Tanous // Can't find a matching ID 487f80a87f2SEd Tanous if (lastEvent == messages.end()) 488f80a87f2SEd Tanous { 489f80a87f2SEd Tanous nlohmann::json msg = messages::eventBufferExceeded(); 490f80a87f2SEd Tanous // If the buffer overloaded, send all messages. 4916d799e14SEd Tanous subValue->sendEventToSubscriber(msg); 492f80a87f2SEd Tanous lastEvent = messages.begin(); 493f80a87f2SEd Tanous } 494f80a87f2SEd Tanous else 495f80a87f2SEd Tanous { 496f80a87f2SEd Tanous // Skip the last event the user already has 497f80a87f2SEd Tanous lastEvent++; 498f80a87f2SEd Tanous } 499f80a87f2SEd Tanous 500f80a87f2SEd Tanous for (boost::circular_buffer<Event>::const_iterator event = 501f80a87f2SEd Tanous lastEvent; 502f80a87f2SEd Tanous lastEvent != messages.end(); lastEvent++) 503f80a87f2SEd Tanous { 5046d799e14SEd Tanous subValue->sendEventToSubscriber(event->message); 505f80a87f2SEd Tanous } 506f80a87f2SEd Tanous } 507f80a87f2SEd Tanous return id; 508f80a87f2SEd Tanous } 509f80a87f2SEd Tanous 510f80a87f2SEd Tanous std::string 511f80a87f2SEd Tanous addPushSubscription(const std::shared_ptr<Subscription>& subValue) 512f80a87f2SEd Tanous { 513f80a87f2SEd Tanous std::string id = addSubscriptionInternal(subValue); 514a0969c70SMyung Bae subValue->deleter = [id]() { 515a0969c70SMyung Bae EventServiceManager::getInstance().deleteSubscription(id); 516a0969c70SMyung Bae }; 517f80a87f2SEd Tanous updateSubscriptionData(); 518b52664e2SAppaRao Puli return id; 519b52664e2SAppaRao Puli } 520b52664e2SAppaRao Puli 521b52664e2SAppaRao Puli bool isSubscriptionExist(const std::string& id) 522b52664e2SAppaRao Puli { 523b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 52455f79e6fSEd Tanous return obj != subscriptionsMap.end(); 525b52664e2SAppaRao Puli } 526b52664e2SAppaRao Puli 5274b712a29SEd Tanous bool deleteSubscription(const std::string& id) 528b52664e2SAppaRao Puli { 529b52664e2SAppaRao Puli auto obj = subscriptionsMap.find(id); 5304b712a29SEd Tanous if (obj == subscriptionsMap.end()) 531b52664e2SAppaRao Puli { 5324b712a29SEd Tanous BMCWEB_LOG_WARNING("Could not find subscription with id {}", id); 5334b712a29SEd Tanous return false; 5344b712a29SEd Tanous } 535b52664e2SAppaRao Puli subscriptionsMap.erase(obj); 5364b712a29SEd Tanous auto& event = persistent_data::EventServiceStore::getInstance(); 5374b712a29SEd Tanous auto persistentObj = event.subscriptionsConfigMap.find(id); 5384b712a29SEd Tanous if (persistentObj == event.subscriptionsConfigMap.end()) 5394b712a29SEd Tanous { 5404b712a29SEd Tanous BMCWEB_LOG_ERROR("Subscription wasn't in persistent data"); 5414b712a29SEd Tanous return true; 5424b712a29SEd Tanous } 54328afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 5444b712a29SEd Tanous .subscriptionsConfigMap.erase(persistentObj); 5457d1cc387SAppaRao Puli updateNoOfSubscribersCount(); 546b52664e2SAppaRao Puli updateSubscriptionData(); 5474b712a29SEd Tanous 5484b712a29SEd Tanous return true; 549b52664e2SAppaRao Puli } 550b52664e2SAppaRao Puli 5515e44e3d8SAppaRao Puli void deleteSseSubscription(const crow::sse_socket::Connection& thisConn) 5525e44e3d8SAppaRao Puli { 553bdbfae2aSEd Tanous for (auto it = subscriptionsMap.begin(); it != subscriptionsMap.end();) 5545e44e3d8SAppaRao Puli { 555bdbfae2aSEd Tanous std::shared_ptr<Subscription> entry = it->second; 5565e44e3d8SAppaRao Puli bool entryIsThisConn = entry->matchSseId(thisConn); 5575e44e3d8SAppaRao Puli if (entryIsThisConn) 5585e44e3d8SAppaRao Puli { 5595e44e3d8SAppaRao Puli persistent_data::EventServiceStore::getInstance() 5605fe4ef35SMyung Bae .subscriptionsConfigMap.erase(entry->userSub->id); 561bdbfae2aSEd Tanous it = subscriptionsMap.erase(it); 5625e44e3d8SAppaRao Puli return; 5635e44e3d8SAppaRao Puli } 564bdbfae2aSEd Tanous it++; 5655e44e3d8SAppaRao Puli } 5665e44e3d8SAppaRao Puli } 5675e44e3d8SAppaRao Puli 5685e44e3d8SAppaRao Puli size_t getNumberOfSubscriptions() const 569b52664e2SAppaRao Puli { 570b52664e2SAppaRao Puli return subscriptionsMap.size(); 571b52664e2SAppaRao Puli } 572b52664e2SAppaRao Puli 5735e44e3d8SAppaRao Puli size_t getNumberOfSSESubscriptions() const 5745e44e3d8SAppaRao Puli { 5753544d2a7SEd Tanous auto size = std::ranges::count_if( 5763544d2a7SEd Tanous subscriptionsMap, 5775e44e3d8SAppaRao Puli [](const std::pair<std::string, std::shared_ptr<Subscription>>& 5785e44e3d8SAppaRao Puli entry) { 5795fe4ef35SMyung Bae return (entry.second->userSub->subscriptionType == 5804b712a29SEd Tanous subscriptionTypeSSE); 5815e44e3d8SAppaRao Puli }); 5825e44e3d8SAppaRao Puli return static_cast<size_t>(size); 5835e44e3d8SAppaRao Puli } 5845e44e3d8SAppaRao Puli 585b52664e2SAppaRao Puli std::vector<std::string> getAllIDs() 586b52664e2SAppaRao Puli { 587b52664e2SAppaRao Puli std::vector<std::string> idList; 588b52664e2SAppaRao Puli for (const auto& it : subscriptionsMap) 589b52664e2SAppaRao Puli { 590b52664e2SAppaRao Puli idList.emplace_back(it.first); 591b52664e2SAppaRao Puli } 592b52664e2SAppaRao Puli return idList; 593b52664e2SAppaRao Puli } 594b52664e2SAppaRao Puli 59581ee0e74SChandramohan Harkude bool sendTestEventLog(TestEvent& testEvent) 5960b4bdd93SAppaRao Puli { 5975e44e3d8SAppaRao Puli for (const auto& it : subscriptionsMap) 5980b4bdd93SAppaRao Puli { 5990b4bdd93SAppaRao Puli std::shared_ptr<Subscription> entry = it.second; 60081ee0e74SChandramohan Harkude if (!entry->sendTestEventLog(testEvent)) 6016ba8c82eSsunharis_in { 6026ba8c82eSsunharis_in return false; 6030b4bdd93SAppaRao Puli } 6040b4bdd93SAppaRao Puli } 6056ba8c82eSsunharis_in return true; 6066ba8c82eSsunharis_in } 607e9a14131SAppaRao Puli 6083433b03aSEd Tanous static void 6093433b03aSEd Tanous sendEventsToSubs(const std::vector<EventLogObjectsType>& eventRecords) 6103433b03aSEd Tanous { 6113433b03aSEd Tanous for (const auto& it : 6123433b03aSEd Tanous EventServiceManager::getInstance().subscriptionsMap) 6133433b03aSEd Tanous { 6143433b03aSEd Tanous Subscription& entry = *it.second; 6153433b03aSEd Tanous entry.filterAndSendEventLogs(eventRecords); 6163433b03aSEd Tanous } 6173433b03aSEd Tanous } 6183433b03aSEd Tanous 619b26ff34dSEd Tanous static void sendTelemetryReportToSubs( 620b26ff34dSEd Tanous const std::string& reportId, const telemetry::TimestampReadings& var) 621b26ff34dSEd Tanous { 622b26ff34dSEd Tanous for (const auto& it : 623b26ff34dSEd Tanous EventServiceManager::getInstance().subscriptionsMap) 624b26ff34dSEd Tanous { 625b26ff34dSEd Tanous Subscription& entry = *it.second; 626b26ff34dSEd Tanous entry.filterAndSendReports(reportId, var); 627b26ff34dSEd Tanous } 628b26ff34dSEd Tanous } 629b26ff34dSEd Tanous 630f80a87f2SEd Tanous void sendEvent(nlohmann::json::object_t eventMessage, 631f80a87f2SEd Tanous std::string_view origin, std::string_view resourceType) 63296330b99SSunitha Harish { 633613dabeaSEd Tanous eventMessage["EventId"] = eventId; 634f80a87f2SEd Tanous 635613dabeaSEd Tanous eventMessage["EventTimestamp"] = 636613dabeaSEd Tanous redfish::time_utils::getDateTimeOffsetNow().first; 637613dabeaSEd Tanous eventMessage["OriginOfCondition"] = origin; 638613dabeaSEd Tanous 639f80a87f2SEd Tanous // MemberId is 0 : since we are sending one event record. 640788b091bSIgor Kanyuka eventMessage["MemberId"] = "0"; 64196330b99SSunitha Harish 642f80a87f2SEd Tanous messages.push_back(Event(std::to_string(eventId), eventMessage)); 643f80a87f2SEd Tanous 644f80a87f2SEd Tanous for (auto& it : subscriptionsMap) 64596330b99SSunitha Harish { 646f80a87f2SEd Tanous std::shared_ptr<Subscription>& entry = it.second; 6475fe4ef35SMyung Bae if (!eventMatchesFilter(*entry->userSub, eventMessage, 6485fe4ef35SMyung Bae resourceType)) 64996330b99SSunitha Harish { 650f80a87f2SEd Tanous BMCWEB_LOG_DEBUG("Filter didn't match"); 651f80a87f2SEd Tanous continue; 65296330b99SSunitha Harish } 653f80a87f2SEd Tanous 654f80a87f2SEd Tanous nlohmann::json::array_t eventRecord; 655f80a87f2SEd Tanous eventRecord.emplace_back(eventMessage); 656f80a87f2SEd Tanous 657613dabeaSEd Tanous nlohmann::json msgJson; 658613dabeaSEd Tanous 659613dabeaSEd Tanous msgJson["@odata.type"] = "#Event.v1_4_0.Event"; 660613dabeaSEd Tanous msgJson["Name"] = "Event Log"; 661613dabeaSEd Tanous msgJson["Id"] = eventId; 662f80a87f2SEd Tanous msgJson["Events"] = std::move(eventRecord); 663f52c03c1SCarson Labrado 664f52c03c1SCarson Labrado std::string strMsg = msgJson.dump( 665f52c03c1SCarson Labrado 2, ' ', true, nlohmann::json::error_handler_t::replace); 6666d799e14SEd Tanous entry->sendEventToSubscriber(std::move(strMsg)); 66796330b99SSunitha Harish } 66821c0ba6eSMyung Bae eventId++; // increment the eventId 66996330b99SSunitha Harish } 67023a21a1cSEd Tanous }; 671b52664e2SAppaRao Puli 672b52664e2SAppaRao Puli } // namespace redfish 673