Move UserSubscription to composition

This allows for two very important simplifying changes.  First, we can
use the default copy operators on the UserSubscription class, which is
far less error prone than writing it manually, which we have two copies
of in code already.

Second, it allows the Subscription class to move to using values rather
than shared_ptr everywhere, which cleans up a significant amount of
code.

Tested:
Ran Redfish-Event-Listener, subscription created and destroyed
correctly.
Calling POST SubmitTestEvent showed events propagating to server.

Change-Id: I6d258cfe3594edddf3960ae2d4559d70acca1bf8
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/http/http_client.hpp b/http/http_client.hpp
index 0df0656..546d92c 100644
--- a/http/http_client.hpp
+++ b/http/http_client.hpp
@@ -848,7 +848,9 @@
   private:
     std::unordered_map<std::string, std::shared_ptr<ConnectionPool>>
         connectionPools;
-    boost::asio::io_context& ioc;
+
+    // reference_wrapper here makes HttpClient movable
+    std::reference_wrapper<boost::asio::io_context> ioc;
     std::shared_ptr<ConnectionPolicy> connPolicy;
 
     // Used as a dummy callback by sendData() in order to call
@@ -868,8 +870,8 @@
 
     HttpClient(const HttpClient&) = delete;
     HttpClient& operator=(const HttpClient&) = delete;
-    HttpClient(HttpClient&&) = delete;
-    HttpClient& operator=(HttpClient&&) = delete;
+    HttpClient(HttpClient&& client) = default;
+    HttpClient& operator=(HttpClient&& client) = default;
     ~HttpClient() = default;
 
     // Send a request to destIP where additional processing of the
diff --git a/include/event_service_store.hpp b/include/event_service_store.hpp
index 9761eb5..f875986 100644
--- a/include/event_service_store.hpp
+++ b/include/event_service_store.hpp
@@ -12,6 +12,7 @@
 
 struct UserSubscription
 {
+    // Represents a Redfish EventDestination instance
     std::string id;
     boost::urls::url destinationUrl;
     std::string protocol;
@@ -27,11 +28,10 @@
     std::vector<std::string> metricReportDefinitions;
     std::vector<std::string> originResources;
 
-    static std::shared_ptr<UserSubscription> fromJson(
+    static std::optional<UserSubscription> fromJson(
         const nlohmann::json::object_t& j, const bool loadFromOldConfig = false)
     {
-        std::shared_ptr<UserSubscription> subvalue =
-            std::make_shared<UserSubscription>();
+        UserSubscription subvalue;
         for (const auto& element : j)
         {
             if (element.first == "Id")
@@ -42,7 +42,7 @@
                 {
                     continue;
                 }
-                subvalue->id = *value;
+                subvalue.id = *value;
             }
             else if (element.first == "Destination")
             {
@@ -58,7 +58,7 @@
                 {
                     continue;
                 }
-                subvalue->destinationUrl = std::move(*url);
+                subvalue.destinationUrl = std::move(*url);
             }
             else if (element.first == "Protocol")
             {
@@ -68,7 +68,7 @@
                 {
                     continue;
                 }
-                subvalue->protocol = *value;
+                subvalue.protocol = *value;
             }
             else if (element.first == "VerifyCertificate")
             {
@@ -77,7 +77,7 @@
                 {
                     continue;
                 }
-                subvalue->verifyCertificate = *value;
+                subvalue.verifyCertificate = *value;
             }
             else if (element.first == "DeliveryRetryPolicy")
             {
@@ -87,7 +87,7 @@
                 {
                     continue;
                 }
-                subvalue->retryPolicy = *value;
+                subvalue.retryPolicy = *value;
             }
             else if (element.first == "Context")
             {
@@ -97,7 +97,7 @@
                 {
                     continue;
                 }
-                subvalue->customText = *value;
+                subvalue.customText = *value;
             }
             else if (element.first == "EventFormatType")
             {
@@ -107,7 +107,7 @@
                 {
                     continue;
                 }
-                subvalue->eventFormatType = *value;
+                subvalue.eventFormatType = *value;
             }
             else if (element.first == "SubscriptionType")
             {
@@ -117,7 +117,7 @@
                 {
                     continue;
                 }
-                subvalue->subscriptionType = *value;
+                subvalue.subscriptionType = *value;
             }
             else if (element.first == "MessageIds")
             {
@@ -135,7 +135,7 @@
                     {
                         continue;
                     }
-                    subvalue->registryMsgIds.emplace_back(*value);
+                    subvalue.registryMsgIds.emplace_back(*value);
                 }
             }
             else if (element.first == "RegistryPrefixes")
@@ -154,7 +154,7 @@
                     {
                         continue;
                     }
-                    subvalue->registryPrefixes.emplace_back(*value);
+                    subvalue.registryPrefixes.emplace_back(*value);
                 }
             }
             else if (element.first == "ResourceTypes")
@@ -173,7 +173,7 @@
                     {
                         continue;
                     }
-                    subvalue->resourceTypes.emplace_back(*value);
+                    subvalue.resourceTypes.emplace_back(*value);
                 }
             }
             else if (element.first == "HttpHeaders")
@@ -194,7 +194,7 @@
                                          val.first);
                         continue;
                     }
-                    subvalue->httpHeaders.set(val.first, *value);
+                    subvalue.httpHeaders.set(val.first, *value);
                 }
             }
             else if (element.first == "MetricReportDefinitions")
@@ -213,7 +213,7 @@
                     {
                         continue;
                     }
-                    subvalue->metricReportDefinitions.emplace_back(*value);
+                    subvalue.metricReportDefinitions.emplace_back(*value);
                 }
             }
             else if (element.first == "OriginResources")
@@ -232,7 +232,7 @@
                     {
                         continue;
                     }
-                    subvalue->originResources.emplace_back(*value);
+                    subvalue.originResources.emplace_back(*value);
                 }
             }
             else
@@ -244,15 +244,14 @@
             }
         }
 
-        if ((subvalue->id.empty() && !loadFromOldConfig) ||
-            subvalue->destinationUrl.empty() || subvalue->protocol.empty() ||
-            subvalue->retryPolicy.empty() ||
-            subvalue->eventFormatType.empty() ||
-            subvalue->subscriptionType.empty())
+        if ((subvalue.id.empty() && !loadFromOldConfig) ||
+            subvalue.destinationUrl.empty() || subvalue.protocol.empty() ||
+            subvalue.retryPolicy.empty() || subvalue.eventFormatType.empty() ||
+            subvalue.subscriptionType.empty())
         {
             BMCWEB_LOG_ERROR("Subscription missing required field "
                              "information, refusing to restore");
-            return nullptr;
+            return std::nullopt;
         }
 
         return subvalue;
@@ -307,7 +306,7 @@
 class EventServiceStore
 {
   public:
-    boost::container::flat_map<std::string, std::shared_ptr<UserSubscription>>
+    boost::container::flat_map<std::string, UserSubscription>
         subscriptionsConfigMap;
     EventServiceConfig eventServiceConfig;
 
diff --git a/include/persistent_data.hpp b/include/persistent_data.hpp
index bcecf9f..13a43c4 100644
--- a/include/persistent_data.hpp
+++ b/include/persistent_data.hpp
@@ -157,10 +157,10 @@
                     {
                         for (const auto& elem : item.second)
                         {
-                            std::shared_ptr<UserSubscription> newSubscription =
+                            std::optional<UserSubscription> newSub =
                                 UserSubscription::fromJson(elem);
 
-                            if (newSubscription == nullptr)
+                            if (!newSub)
                             {
                                 BMCWEB_LOG_ERROR("Problem reading subscription "
                                                  "from persistent store");
@@ -168,11 +168,13 @@
                             }
 
                             BMCWEB_LOG_DEBUG("Restored subscription: {} {}",
-                                             newSubscription->id,
-                                             newSubscription->customText);
-                            EventServiceStore::getInstance()
-                                .subscriptionsConfigMap.emplace(
-                                    newSubscription->id, newSubscription);
+                                             newSub->id, newSub->customText);
+
+                            boost::container::flat_map<
+                                std::string, UserSubscription>& configMap =
+                                EventServiceStore::getInstance()
+                                    .subscriptionsConfigMap;
+                            configMap.emplace(newSub->id, *newSub);
                         }
                     }
                     else
@@ -268,7 +270,7 @@
         for (const auto& it :
              EventServiceStore::getInstance().subscriptionsConfigMap)
         {
-            const UserSubscription& subValue = *it.second;
+            const UserSubscription& subValue = it.second;
             if (subValue.subscriptionType == "SSE")
             {
                 BMCWEB_LOG_DEBUG("The subscription type is SSE, so skipping.");
diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
index 8fd0157..f9ac760 100644
--- a/redfish-core/include/event_service_manager.hpp
+++ b/redfish-core/include/event_service_manager.hpp
@@ -267,7 +267,7 @@
 
 } // namespace event_log
 
-class Subscription : public persistent_data::UserSubscription
+class Subscription
 {
   public:
     Subscription(const Subscription&) = delete;
@@ -279,7 +279,7 @@
                  boost::asio::io_context& ioc) :
         policy(std::make_shared<crow::ConnectionPolicy>())
     {
-        destinationUrl = url;
+        userSub.destinationUrl = url;
         client.emplace(ioc, policy);
         // Subscription constructor
         policy->invalidResp = retryRespHandler;
@@ -303,10 +303,11 @@
 
         if (client)
         {
-            client->sendData(
-                std::move(msg), destinationUrl,
-                static_cast<ensuressl::VerifyCertificate>(verifyCertificate),
-                httpHeaders, boost::beast::http::verb::post);
+            client->sendData(std::move(msg), userSub.destinationUrl,
+                             static_cast<ensuressl::VerifyCertificate>(
+                                 userSub.verifyCertificate),
+                             userSub.httpHeaders,
+                             boost::beast::http::verb::post);
             return true;
         }
 
@@ -322,14 +323,14 @@
                             std::string_view resType)
     {
         // If resourceTypes list is empty, assume all
-        if (!resourceTypes.empty())
+        if (!userSub.resourceTypes.empty())
         {
             // Search the resourceTypes list for the subscription.
             auto resourceTypeIndex = std::ranges::find_if(
-                resourceTypes, [resType](const std::string& rtEntry) {
+                userSub.resourceTypes, [resType](const std::string& rtEntry) {
                     return rtEntry == resType;
                 });
-            if (resourceTypeIndex == resourceTypes.end())
+            if (resourceTypeIndex == userSub.resourceTypes.end())
             {
                 BMCWEB_LOG_DEBUG("Not subscribed to this resource");
                 return false;
@@ -340,7 +341,7 @@
 
         // If registryPrefixes list is empty, don't filter events
         // send everything.
-        if (!registryPrefixes.empty())
+        if (!userSub.registryPrefixes.empty())
         {
             auto eventJson = eventMessage.find("MessageId");
             if (eventJson == eventMessage.end())
@@ -361,14 +362,14 @@
             event_log::getRegistryAndMessageKey(*messageId, registry,
                                                 messageKey);
 
-            auto obj = std::ranges::find(registryPrefixes, registry);
-            if (obj == registryPrefixes.end())
+            auto obj = std::ranges::find(userSub.registryPrefixes, registry);
+            if (obj == userSub.registryPrefixes.end())
             {
                 return false;
             }
         }
 
-        if (!originResources.empty())
+        if (!userSub.originResources.empty())
         {
             auto eventJson = eventMessage.find("OriginOfCondition");
             if (eventJson == eventMessage.end())
@@ -384,16 +385,17 @@
                 return false;
             }
 
-            auto obj = std::ranges::find(originResources, *originOfCondition);
+            auto obj =
+                std::ranges::find(userSub.originResources, *originOfCondition);
 
-            if (obj == originResources.end())
+            if (obj == userSub.originResources.end())
             {
                 return false;
             }
         }
 
         // If registryMsgIds list is empty, assume all
-        if (!registryMsgIds.empty())
+        if (!userSub.registryMsgIds.empty())
         {
             auto eventJson = eventMessage.find("MessageId");
             if (eventJson == eventMessage.end())
@@ -418,14 +420,15 @@
             BMCWEB_LOG_DEBUG("extracted registry {}", registry);
             BMCWEB_LOG_DEBUG("extracted message key {}", messageKey);
 
-            auto obj = std::ranges::find(
-                registryMsgIds, std::format("{}.{}", registry, messageKey));
-            if (obj == registryMsgIds.end())
+            auto obj =
+                std::ranges::find(userSub.registryMsgIds,
+                                  std::format("{}.{}", registry, messageKey));
+            if (obj == userSub.registryMsgIds.end())
             {
                 BMCWEB_LOG_DEBUG("did not find registry {} in registryMsgIds",
                                  registry);
                 BMCWEB_LOG_DEBUG("registryMsgIds has {} entries",
-                                 registryMsgIds.size());
+                                 userSub.registryMsgIds.size());
                 return false;
             }
         }
@@ -456,7 +459,7 @@
         logEntryJson["MessageArgs"] = nlohmann::json::array();
         logEntryJson["EventTimestamp"] =
             redfish::time_utils::getDateTimeOffsetNow().first;
-        logEntryJson["Context"] = customText;
+        logEntryJson["Context"] = userSub.customText;
 
         nlohmann::json msg;
         msg["@odata.type"] = "#Event.v1_4_0.Event";
@@ -481,7 +484,7 @@
             nlohmann::json::object_t bmcLogEntry;
             if (event_log::formatEventLogEntry(
                     logEntry.id, logEntry.messageId, messageArgsView,
-                    logEntry.timestamp, customText, bmcLogEntry) != 0)
+                    logEntry.timestamp, userSub.customText, bmcLogEntry) != 0)
             {
                 BMCWEB_LOG_DEBUG("Read eventLog entry failed");
                 continue;
@@ -522,10 +525,11 @@
             reportId);
 
         // Empty list means no filter. Send everything.
-        if (!metricReportDefinitions.empty())
+        if (!userSub.metricReportDefinitions.empty())
         {
-            if (std::ranges::find(metricReportDefinitions, mrdUri.buffer()) ==
-                metricReportDefinitions.end())
+            if (std::ranges::find(userSub.metricReportDefinitions,
+                                  mrdUri.buffer()) ==
+                userSub.metricReportDefinitions.end())
             {
                 return;
             }
@@ -542,9 +546,9 @@
 
         // Context is set by user during Event subscription and it must be
         // set for MetricReport response.
-        if (!customText.empty())
+        if (!userSub.customText.empty())
         {
-            msg["Context"] = customText;
+            msg["Context"] = userSub.customText;
         }
 
         std::string strMsg =
@@ -602,6 +606,8 @@
             boost::system::errc::success);
     }
 
+    persistent_data::UserSubscription userSub;
+
   private:
     std::string subId;
     uint64_t eventSeqNum = 1;
@@ -677,11 +683,10 @@
         for (const auto& it : persistent_data::EventServiceStore::getInstance()
                                   .subscriptionsConfigMap)
         {
-            std::shared_ptr<persistent_data::UserSubscription> newSub =
-                it.second;
+            const persistent_data::UserSubscription& newSub = it.second;
 
             boost::system::result<boost::urls::url> url =
-                boost::urls::parse_absolute_uri(newSub->destinationUrl);
+                boost::urls::parse_absolute_uri(newSub.destinationUrl);
 
             if (!url)
             {
@@ -691,27 +696,9 @@
             }
             std::shared_ptr<Subscription> subValue =
                 std::make_shared<Subscription>(*url, ioc);
+            subValue->userSub = newSub;
 
-            subValue->id = newSub->id;
-            subValue->destinationUrl = newSub->destinationUrl;
-            subValue->protocol = newSub->protocol;
-            subValue->verifyCertificate = newSub->verifyCertificate;
-            subValue->retryPolicy = newSub->retryPolicy;
-            subValue->customText = newSub->customText;
-            subValue->eventFormatType = newSub->eventFormatType;
-            subValue->subscriptionType = newSub->subscriptionType;
-            subValue->registryMsgIds = newSub->registryMsgIds;
-            subValue->registryPrefixes = newSub->registryPrefixes;
-            subValue->resourceTypes = newSub->resourceTypes;
-            subValue->httpHeaders = newSub->httpHeaders;
-            subValue->metricReportDefinitions = newSub->metricReportDefinitions;
-            subValue->originResources = newSub->originResources;
-
-            if (subValue->id.empty())
-            {
-                BMCWEB_LOG_ERROR("Failed to add subscription");
-            }
-            subscriptionsMap.insert(std::pair(subValue->id, subValue));
+            subscriptionsMap.insert(std::pair(subValue->userSub.id, subValue));
 
             updateNoOfSubscribersCount();
 
@@ -754,16 +741,18 @@
             {
                 for (const auto& elem : item.second)
                 {
-                    std::shared_ptr<persistent_data::UserSubscription>
+                    std::optional<persistent_data::UserSubscription>
                         newSubscription =
                             persistent_data::UserSubscription::fromJson(elem,
                                                                         true);
-                    if (newSubscription == nullptr)
+                    if (!newSubscription)
                     {
                         BMCWEB_LOG_ERROR("Problem reading subscription "
                                          "from old persistent store");
                         continue;
                     }
+                    persistent_data::UserSubscription& newSub =
+                        *newSubscription;
 
                     std::uniform_int_distribution<uint32_t> dist(0);
                     bmcweb::OpenSSLGenerator gen;
@@ -779,11 +768,11 @@
                             retry = 0;
                             break;
                         }
-                        newSubscription->id = id;
+                        newSub.id = id;
                         auto inserted =
                             persistent_data::EventServiceStore::getInstance()
                                 .subscriptionsConfigMap.insert(
-                                    std::pair(id, newSubscription));
+                                    std::pair(id, newSub));
                         if (inserted.second)
                         {
                             break;
@@ -885,11 +874,11 @@
         for (const auto& it : subscriptionsMap)
         {
             std::shared_ptr<Subscription> entry = it.second;
-            if (entry->eventFormatType == eventFormatType)
+            if (entry->userSub.eventFormatType == eventFormatType)
             {
                 eventLogSubCount++;
             }
-            else if (entry->eventFormatType == metricReportFormatType)
+            else if (entry->userSub.eventFormatType == metricReportFormatType)
             {
                 metricReportSubCount++;
             }
@@ -953,24 +942,10 @@
             return "";
         }
 
-        std::shared_ptr<persistent_data::UserSubscription> newSub =
-            std::make_shared<persistent_data::UserSubscription>();
-        newSub->id = id;
-        newSub->destinationUrl = subValue->destinationUrl;
-        newSub->protocol = subValue->protocol;
-        newSub->retryPolicy = subValue->retryPolicy;
-        newSub->customText = subValue->customText;
-        newSub->eventFormatType = subValue->eventFormatType;
-        newSub->subscriptionType = subValue->subscriptionType;
-        newSub->registryMsgIds = subValue->registryMsgIds;
-        newSub->registryPrefixes = subValue->registryPrefixes;
-        newSub->resourceTypes = subValue->resourceTypes;
-        newSub->httpHeaders = subValue->httpHeaders;
-        newSub->metricReportDefinitions = subValue->metricReportDefinitions;
-        newSub->originResources = subValue->originResources;
+        persistent_data::UserSubscription newSub(subValue->userSub);
 
         persistent_data::EventServiceStore::getInstance()
-            .subscriptionsConfigMap.emplace(newSub->id, newSub);
+            .subscriptionsConfigMap.emplace(newSub.id, newSub);
 
         updateNoOfSubscribersCount();
 
@@ -1044,19 +1019,28 @@
         return obj != subscriptionsMap.end();
     }
 
-    void deleteSubscription(const std::string& id)
+    bool deleteSubscription(const std::string& id)
     {
         auto obj = subscriptionsMap.find(id);
-        if (obj != subscriptionsMap.end())
+        if (obj == subscriptionsMap.end())
         {
-            subscriptionsMap.erase(obj);
-            auto obj2 = persistent_data::EventServiceStore::getInstance()
-                            .subscriptionsConfigMap.find(id);
-            persistent_data::EventServiceStore::getInstance()
-                .subscriptionsConfigMap.erase(obj2);
-            updateNoOfSubscribersCount();
-            updateSubscriptionData();
+            BMCWEB_LOG_WARNING("Could not find subscription with id {}", id);
+            return false;
         }
+        subscriptionsMap.erase(obj);
+        auto& event = persistent_data::EventServiceStore::getInstance();
+        auto persistentObj = event.subscriptionsConfigMap.find(id);
+        if (persistentObj == event.subscriptionsConfigMap.end())
+        {
+            BMCWEB_LOG_ERROR("Subscription wasn't in persistent data");
+            return true;
+        }
+        persistent_data::EventServiceStore::getInstance()
+            .subscriptionsConfigMap.erase(persistentObj);
+        updateNoOfSubscribersCount();
+        updateSubscriptionData();
+
+        return true;
     }
 
     void deleteSseSubscription(const crow::sse_socket::Connection& thisConn)
@@ -1088,7 +1072,8 @@
             subscriptionsMap,
             [](const std::pair<std::string, std::shared_ptr<Subscription>>&
                    entry) {
-                return (entry.second->subscriptionType == subscriptionTypeSSE);
+                return (entry.second->userSub.subscriptionType ==
+                        subscriptionTypeSSE);
             });
         return static_cast<size_t>(size);
     }
@@ -1254,7 +1239,7 @@
         for (const auto& it : subscriptionsMap)
         {
             std::shared_ptr<Subscription> entry = it.second;
-            if (entry->eventFormatType == "Event")
+            if (entry->userSub.eventFormatType == "Event")
             {
                 entry->filterAndSendEventLogs(eventRecords);
             }
@@ -1452,7 +1437,7 @@
              EventServiceManager::getInstance().subscriptionsMap)
         {
             Subscription& entry = *it.second;
-            if (entry.eventFormatType == metricReportFormatType)
+            if (entry.userSub.eventFormatType == metricReportFormatType)
             {
                 entry.filterAndSendReports(id, *readings);
             }
diff --git a/redfish-core/include/snmp_trap_event_clients.hpp b/redfish-core/include/snmp_trap_event_clients.hpp
index d71d59f..ebc0280 100644
--- a/redfish-core/include/snmp_trap_event_clients.hpp
+++ b/redfish-core/include/snmp_trap_event_clients.hpp
@@ -70,17 +70,6 @@
     asyncResp->res.jsonValue["EventFormatType"] =
         event_destination::EventFormatType::Event;
 
-    std::shared_ptr<Subscription> subValue =
-        EventServiceManager::getInstance().getSubscription(id);
-    if (subValue != nullptr)
-    {
-        asyncResp->res.jsonValue["Context"] = subValue->customText;
-    }
-    else
-    {
-        asyncResp->res.jsonValue["Context"] = "";
-    }
-
     sdbusplus::asio::getAllProperties(
         *crow::connections::systemBus, "xyz.openbmc_project.Network.SNMP",
         objectPath, "xyz.openbmc_project.Network.Client",
diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
index 76f3c5a..60946b2 100644
--- a/redfish-core/lib/event_service.hpp
+++ b/redfish-core/lib/event_service.hpp
@@ -302,18 +302,27 @@
             std::optional<std::vector<nlohmann::json::object_t>> headers;
             std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
 
+            // clang-format off
             if (!json_util::readJsonPatch(
-                    req, asyncResp->res, "Destination", destUrl, "Context",
-                    context, "Protocol", protocol, "SubscriptionType",
-                    subscriptionType, "EventFormatType", eventFormatType2,
-                    "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
-                    "OriginResources", originResources, "MessageIds", msgIds,
+                    req, asyncResp->res,
+                    "Context", context,
                     "DeliveryRetryPolicy", retryPolicy,
-                    "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
-                    resTypes, "VerifyCertificate", verifyCertificate))
+                    "Destination", destUrl,
+                    "EventFormatType", eventFormatType2,
+                    "HttpHeaders", headers,
+                    "MessageIds", msgIds,
+                    "MetricReportDefinitions", mrdJsonArray,
+                    "OriginResources", originResources,
+                    "Protocol", protocol,
+                    "RegistryPrefixes", regPrefixes,
+                    "ResourceTypes", resTypes,
+                    "SubscriptionType", subscriptionType,
+                    "VerifyCertificate", verifyCertificate
+            ))
             {
                 return;
             }
+            // clang-format on
 
             // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
             static constexpr const uint16_t maxDestinationSize = 2000;
@@ -425,7 +434,7 @@
             std::shared_ptr<Subscription> subValue =
                 std::make_shared<Subscription>(*url, app.ioContext());
 
-            subValue->destinationUrl = std::move(*url);
+            subValue->userSub.destinationUrl = std::move(*url);
 
             if (subscriptionType)
             {
@@ -435,11 +444,12 @@
                         asyncResp->res, *subscriptionType, "SubscriptionType");
                     return;
                 }
-                subValue->subscriptionType = *subscriptionType;
+                subValue->userSub.subscriptionType = *subscriptionType;
             }
             else
             {
-                subValue->subscriptionType = "RedfishEvent"; // Default
+                // Default
+                subValue->userSub.subscriptionType = "RedfishEvent";
             }
 
             if (protocol != "Redfish")
@@ -448,11 +458,11 @@
                                                  "Protocol");
                 return;
             }
-            subValue->protocol = protocol;
+            subValue->userSub.protocol = protocol;
 
             if (verifyCertificate)
             {
-                subValue->verifyCertificate = *verifyCertificate;
+                subValue->userSub.verifyCertificate = *verifyCertificate;
             }
 
             if (eventFormatType2)
@@ -465,12 +475,12 @@
                         asyncResp->res, *eventFormatType2, "EventFormatType");
                     return;
                 }
-                subValue->eventFormatType = *eventFormatType2;
+                subValue->userSub.eventFormatType = *eventFormatType2;
             }
             else
             {
                 // If not specified, use default "Event"
-                subValue->eventFormatType = "Event";
+                subValue->userSub.eventFormatType = "Event";
             }
 
             if (context)
@@ -483,7 +493,7 @@
                                                  maxContextSize);
                     return;
                 }
-                subValue->customText = *context;
+                subValue->userSub.customText = *context;
             }
 
             if (headers)
@@ -516,7 +526,7 @@
                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
                             return;
                         }
-                        subValue->httpHeaders.set(item.first, *value);
+                        subValue->userSub.httpHeaders.set(item.first, *value);
                     }
                 }
             }
@@ -533,12 +543,12 @@
                         return;
                     }
                 }
-                subValue->registryPrefixes = *regPrefixes;
+                subValue->userSub.registryPrefixes = *regPrefixes;
             }
 
             if (originResources)
             {
-                subValue->originResources = *originResources;
+                subValue->userSub.originResources = *originResources;
             }
 
             if (resTypes)
@@ -553,7 +563,7 @@
                         return;
                     }
                 }
-                subValue->resourceTypes = *resTypes;
+                subValue->userSub.resourceTypes = *resTypes;
             }
 
             if (msgIds)
@@ -562,14 +572,14 @@
 
                 // If no registry prefixes are mentioned, consider all
                 // supported prefixes
-                if (subValue->registryPrefixes.empty())
+                if (subValue->userSub.registryPrefixes.empty())
                 {
                     registryPrefix.assign(supportedRegPrefixes.begin(),
                                           supportedRegPrefixes.end());
                 }
                 else
                 {
-                    registryPrefix = subValue->registryPrefixes;
+                    registryPrefix = subValue->userSub.registryPrefixes;
                 }
 
                 for (const std::string& id : *msgIds)
@@ -603,7 +613,7 @@
                     }
                 }
 
-                subValue->registryMsgIds = *msgIds;
+                subValue->userSub.registryMsgIds = *msgIds;
             }
 
             if (retryPolicy)
@@ -615,12 +625,12 @@
                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
                     return;
                 }
-                subValue->retryPolicy = *retryPolicy;
+                subValue->userSub.retryPolicy = *retryPolicy;
             }
             else
             {
                 // Default "TerminateAfterRetries"
-                subValue->retryPolicy = "TerminateAfterRetries";
+                subValue->userSub.retryPolicy = "TerminateAfterRetries";
             }
 
             if (mrdJsonArray)
@@ -635,7 +645,8 @@
                     {
                         return;
                     }
-                    subValue->metricReportDefinitions.emplace_back(mrdUri);
+                    subValue->userSub.metricReportDefinitions.emplace_back(
+                        mrdUri);
                 }
             }
 
@@ -683,44 +694,38 @@
                 }
                 const std::string& id = param;
 
-                asyncResp->res.jsonValue["@odata.type"] =
-                    "#EventDestination.v1_14_1.EventDestination";
-                asyncResp->res.jsonValue["Protocol"] =
-                    event_destination::EventDestinationProtocol::Redfish;
-                asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
-                    "/redfish/v1/EventService/Subscriptions/{}", id);
-                asyncResp->res.jsonValue["Id"] = id;
-                asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
-                asyncResp->res.jsonValue["Destination"] =
-                    subValue->destinationUrl;
-                asyncResp->res.jsonValue["Context"] = subValue->customText;
-                asyncResp->res.jsonValue["SubscriptionType"] =
-                    subValue->subscriptionType;
-                asyncResp->res.jsonValue["HttpHeaders"] =
-                    nlohmann::json::array();
-                asyncResp->res.jsonValue["EventFormatType"] =
-                    subValue->eventFormatType;
-                asyncResp->res.jsonValue["RegistryPrefixes"] =
-                    subValue->registryPrefixes;
-                asyncResp->res.jsonValue["ResourceTypes"] =
-                    subValue->resourceTypes;
+                const persistent_data::UserSubscription& userSub =
+                    subValue->userSub;
 
-                asyncResp->res.jsonValue["MessageIds"] =
-                    subValue->registryMsgIds;
-                asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
-                    subValue->retryPolicy;
-                asyncResp->res.jsonValue["VerifyCertificate"] =
-                    subValue->verifyCertificate;
+                nlohmann::json& jVal = asyncResp->res.jsonValue;
+                jVal["@odata.type"] =
+                    "#EventDestination.v1_14_1.EventDestination";
+                jVal["Protocol"] =
+                    event_destination::EventDestinationProtocol::Redfish;
+                jVal["@odata.id"] = boost::urls::format(
+                    "/redfish/v1/EventService/Subscriptions/{}", id);
+                jVal["Id"] = id;
+                jVal["Name"] = "Event Destination " + id;
+                jVal["Destination"] = userSub.destinationUrl;
+                jVal["Context"] = userSub.customText;
+                jVal["SubscriptionType"] = userSub.subscriptionType;
+                jVal["HttpHeaders"] = nlohmann::json::array();
+                jVal["EventFormatType"] = userSub.eventFormatType;
+                jVal["RegistryPrefixes"] = userSub.registryPrefixes;
+                jVal["ResourceTypes"] = userSub.resourceTypes;
+
+                jVal["MessageIds"] = userSub.registryMsgIds;
+                jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
+                jVal["VerifyCertificate"] = userSub.verifyCertificate;
 
                 nlohmann::json::array_t mrdJsonArray;
-                for (const auto& mdrUri : subValue->metricReportDefinitions)
+                for (const auto& mdrUri : userSub.metricReportDefinitions)
                 {
                     nlohmann::json::object_t mdr;
                     mdr["@odata.id"] = mdrUri;
                     mrdJsonArray.emplace_back(std::move(mdr));
                 }
-                asyncResp->res.jsonValue["MetricReportDefinitions"] =
-                    mrdJsonArray;
+                jVal["MetricReportDefinitions"] = mrdJsonArray;
             });
     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
         // The below privilege is wrong, it should be ConfigureManager OR
@@ -761,7 +766,7 @@
 
                 if (context)
                 {
-                    subValue->customText = *context;
+                    subValue->userSub.customText = *context;
                 }
 
                 if (headers)
@@ -783,7 +788,7 @@
                             fields.set(it.first, *value);
                         }
                     }
-                    subValue->httpHeaders = std::move(fields);
+                    subValue->userSub.httpHeaders = std::move(fields);
                 }
 
                 if (retryPolicy)
@@ -797,12 +802,12 @@
                                                          "DeliveryRetryPolicy");
                         return;
                     }
-                    subValue->retryPolicy = *retryPolicy;
+                    subValue->userSub.retryPolicy = *retryPolicy;
                 }
 
                 if (verifyCertificate)
                 {
-                    subValue->verifyCertificate = *verifyCertificate;
+                    subValue->userSub.verifyCertificate = *verifyCertificate;
                 }
 
                 EventServiceManager::getInstance().updateSubscriptionData();
@@ -821,23 +826,21 @@
                 {
                     return;
                 }
-
+                EventServiceManager& event = EventServiceManager::getInstance();
                 if (param.starts_with("snmp"))
                 {
                     deleteSnmpTrapClient(asyncResp, param);
-                    EventServiceManager::getInstance().deleteSubscription(
-                        param);
+                    event.deleteSubscription(param);
                     return;
                 }
 
-                if (!EventServiceManager::getInstance().isSubscriptionExist(
-                        param))
+                if (!event.deleteSubscription(param))
                 {
-                    asyncResp->res.result(
-                        boost::beast::http::status::not_found);
+                    messages::resourceNotFound(asyncResp->res,
+                                               "EventDestination", param);
                     return;
                 }
-                EventServiceManager::getInstance().deleteSubscription(param);
+                messages::success(asyncResp->res);
             });
 }
 
diff --git a/redfish-core/lib/eventservice_sse.hpp b/redfish-core/lib/eventservice_sse.hpp
index c0a9527..80c0a3a 100644
--- a/redfish-core/lib/eventservice_sse.hpp
+++ b/redfish-core/lib/eventservice_sse.hpp
@@ -44,16 +44,15 @@
 
     std::string lastEventId(req.getHeaderValue("Last-Event-Id"));
 
-    std::shared_ptr<redfish::Subscription> subValue =
-        std::make_shared<redfish::Subscription>(conn);
+    std::shared_ptr<Subscription> subValue =
+        std::make_shared<Subscription>(conn);
 
     // GET on this URI means, Its SSE subscriptionType.
-    subValue->subscriptionType = redfish::subscriptionTypeSSE;
+    subValue->userSub.subscriptionType = redfish::subscriptionTypeSSE;
 
-    subValue->protocol = "Redfish";
-    subValue->retryPolicy = "TerminateAfterRetries";
-    subValue->eventFormatType = "Event";
-    subValue->filter = filter;
+    subValue->userSub.protocol = "Redfish";
+    subValue->userSub.retryPolicy = "TerminateAfterRetries";
+    subValue->userSub.eventFormatType = "Event";
 
     std::string id = manager.addSSESubscription(subValue, lastEventId);
     if (id.empty())
diff --git a/test/redfish-core/include/event_service_manager_test.cpp b/test/redfish-core/include/event_service_manager_test.cpp
index bb86e77..fa3818d 100644
--- a/test/redfish-core/include/event_service_manager_test.cpp
+++ b/test/redfish-core/include/event_service_manager_test.cpp
@@ -1,4 +1,5 @@
 #include "event_service_manager.hpp"
+#include "event_service_store.hpp"
 #include "filter_expr_printer.hpp"
 
 #include <boost/asio/io_context.hpp>
@@ -19,83 +20,88 @@
     boost::urls::url url;
 
     {
-        Subscription sub(url, io);
+        Subscription ioSub(url, io);
         nlohmann::json::object_t event;
 
         // Default constructed should always pass
-        EXPECT_TRUE(sub.eventMatchesFilter(event, "Event"));
+        EXPECT_TRUE(ioSub.eventMatchesFilter(event, "Event"));
     }
     {
         nlohmann::json::object_t event;
         // Resource types filter
-        Subscription sub(url, io);
+        Subscription ioSub(url, io);
+        persistent_data::UserSubscription& sub = ioSub.userSub;
         sub.resourceTypes.emplace_back("Task");
-        EXPECT_FALSE(sub.eventMatchesFilter(event, "Event"));
-        EXPECT_TRUE(sub.eventMatchesFilter(event, "Task"));
+        EXPECT_FALSE(ioSub.eventMatchesFilter(event, "Event"));
+        EXPECT_TRUE(ioSub.eventMatchesFilter(event, "Task"));
     }
     {
         nlohmann::json::object_t event;
         // Resource types filter
-        Subscription sub(url, io);
+        Subscription ioSub(url, io);
+        persistent_data::UserSubscription& sub = ioSub.userSub;
         sub.registryMsgIds.emplace_back("OpenBMC.PostComplete");
 
         // Correct message registry
         event["MessageId"] = "OpenBMC.0.1.PostComplete";
-        EXPECT_TRUE(sub.eventMatchesFilter(event, "Event"));
+        EXPECT_TRUE(ioSub.eventMatchesFilter(event, "Event"));
 
         // Different message registry
         event["MessageId"] = "Task.0.1.PostComplete";
-        EXPECT_FALSE(sub.eventMatchesFilter(event, "Event"));
+        EXPECT_FALSE(ioSub.eventMatchesFilter(event, "Event"));
 
         // Different MessageId
         event["MessageId"] = "OpenBMC.0.1.NoMatch";
-        EXPECT_FALSE(sub.eventMatchesFilter(event, "Event"));
+        EXPECT_FALSE(ioSub.eventMatchesFilter(event, "Event"));
     }
     {
         nlohmann::json::object_t event;
         // Resource types filter
-        Subscription sub(url, io);
+        Subscription ioSub(url, io);
         event["MessageId"] = "OpenBMC.0.1.PostComplete";
 
         // Correct message registry
-        sub.filter = parseFilter("MessageId eq 'OpenBMC.0.1.PostComplete'");
-        EXPECT_TRUE(sub.eventMatchesFilter(event, "Event"));
+        ioSub.filter = parseFilter("MessageId eq 'OpenBMC.0.1.PostComplete'");
+        EXPECT_TRUE(ioSub.eventMatchesFilter(event, "Event"));
 
         // Different message registry
-        sub.filter = parseFilter("MessageId ne 'OpenBMC.0.1.PostComplete'");
-        EXPECT_FALSE(sub.eventMatchesFilter(event, "Event"));
+        ioSub.filter = parseFilter("MessageId ne 'OpenBMC.0.1.PostComplete'");
+        EXPECT_FALSE(ioSub.eventMatchesFilter(event, "Event"));
     }
     {
         nlohmann::json::object_t event;
         // Resource types filter
-        Subscription sub(url, io);
+        Subscription ioSub(url, io);
+        persistent_data::UserSubscription& sub = ioSub.userSub;
         event["MessageId"] = "OpenBMC.0.1.PostComplete";
 
         // Correct message registry
         sub.registryPrefixes.emplace_back("OpenBMC");
-        EXPECT_TRUE(sub.eventMatchesFilter(event, "Event"));
+        EXPECT_TRUE(ioSub.eventMatchesFilter(event, "Event"));
 
         // Different message registry
         event["MessageId"] = "Task.0.1.PostComplete";
-        EXPECT_FALSE(sub.eventMatchesFilter(event, "Event"));
+        EXPECT_FALSE(ioSub.eventMatchesFilter(event, "Event"));
     }
     {
         nlohmann::json::object_t event;
         // Resource types filter
         {
-            Subscription sub(url, io);
+            Subscription ioSub(url, io);
+            persistent_data::UserSubscription& sub = ioSub.userSub;
             event["OriginOfCondition"] = "/redfish/v1/Managers/bmc";
 
             // Correct origin
             sub.originResources.emplace_back("/redfish/v1/Managers/bmc");
-            EXPECT_TRUE(sub.eventMatchesFilter(event, "Event"));
+            EXPECT_TRUE(ioSub.eventMatchesFilter(event, "Event"));
         }
         {
-            Subscription sub(url, io);
+            Subscription ioSub(url, io);
+            persistent_data::UserSubscription& sub = ioSub.userSub;
             // Incorrect origin
             sub.originResources.clear();
             sub.originResources.emplace_back("/redfish/v1/Managers/bmc_not");
-            EXPECT_FALSE(sub.eventMatchesFilter(event, "Event"));
+            EXPECT_FALSE(ioSub.eventMatchesFilter(event, "Event"));
         }
     }
 }