xref: /openbmc/bmcweb/features/redfish/include/event_service_manager.hpp (revision 2a5689a752d31a4a5758d3827c7ca6302bc0acc7)
1 /*
2 // Copyright (c) 2020 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 #include "node.hpp"
18 
19 #include <boost/container/flat_map.hpp>
20 #include <cstdlib>
21 #include <ctime>
22 #include <error_messages.hpp>
23 #include <http_client.hpp>
24 #include <memory>
25 #include <utils/json_utils.hpp>
26 #include <variant>
27 
28 namespace redfish
29 {
30 class Subscription
31 {
32   public:
33     std::string id;
34     std::string destinationUrl;
35     std::string protocol;
36     std::string retryPolicy;
37     std::string customText;
38     std::string eventFormatType;
39     std::string subscriptionType;
40     std::vector<std::string> registryMsgIds;
41     std::vector<std::string> registryPrefixes;
42     std::vector<nlohmann::json> httpHeaders; // key-value pair
43 
44     Subscription(const Subscription&) = delete;
45     Subscription& operator=(const Subscription&) = delete;
46     Subscription(Subscription&&) = delete;
47     Subscription& operator=(Subscription&&) = delete;
48 
49     Subscription(const std::string& inHost, const std::string& inPort,
50                  const std::string& inPath, const std::string& inUriProto) :
51         host(inHost),
52         port(inPort), path(inPath), uriProto(inUriProto)
53     {
54         conn = std::make_shared<crow::HttpClient>(
55             crow::connections::systemBus->get_io_context(), host, port, path);
56     }
57     ~Subscription()
58     {
59     }
60 
61     void sendEvent(const std::string& msg)
62     {
63         std::vector<std::pair<std::string, std::string>> reqHeaders;
64         for (const auto& header : httpHeaders)
65         {
66             for (const auto& item : header.items())
67             {
68                 std::string key = item.key();
69                 std::string val = item.value();
70                 reqHeaders.emplace_back(std::pair(key, val));
71             }
72         }
73         conn->setHeaders(reqHeaders);
74         conn->sendData(msg);
75     }
76 
77   private:
78     std::string host;
79     std::string port;
80     std::string path;
81     std::string uriProto;
82     std::shared_ptr<crow::HttpClient> conn;
83 };
84 
85 class EventServiceManager
86 {
87   private:
88     EventServiceManager(const EventServiceManager&) = delete;
89     EventServiceManager& operator=(const EventServiceManager&) = delete;
90     EventServiceManager(EventServiceManager&&) = delete;
91     EventServiceManager& operator=(EventServiceManager&&) = delete;
92 
93     EventServiceManager()
94     {
95         // TODO: Read the persistent data from store and populate.
96         // Populating with default.
97         enabled = true;
98         retryAttempts = 3;
99         retryTimeoutInterval = 30; // seconds
100     }
101 
102     boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
103         subscriptionsMap;
104 
105   public:
106     bool enabled;
107     uint32_t retryAttempts;
108     uint32_t retryTimeoutInterval;
109 
110     static EventServiceManager& getInstance()
111     {
112         static EventServiceManager handler;
113         return handler;
114     }
115 
116     void updateSubscriptionData()
117     {
118         // Persist the config and subscription data.
119         // TODO: subscriptionsMap & configData need to be
120         // written to Persist store.
121         return;
122     }
123 
124     std::shared_ptr<Subscription> getSubscription(const std::string& id)
125     {
126         auto obj = subscriptionsMap.find(id);
127         if (obj == subscriptionsMap.end())
128         {
129             BMCWEB_LOG_ERROR << "No subscription exist with ID:" << id;
130             return nullptr;
131         }
132         std::shared_ptr<Subscription> subValue = obj->second;
133         return subValue;
134     }
135 
136     std::string addSubscription(const std::shared_ptr<Subscription> subValue)
137     {
138         std::srand(static_cast<uint32_t>(std::time(0)));
139         std::string id;
140 
141         int retry = 3;
142         while (retry)
143         {
144             id = std::to_string(std::rand());
145             auto inserted = subscriptionsMap.insert(std::pair(id, subValue));
146             if (inserted.second)
147             {
148                 break;
149             }
150             --retry;
151         };
152 
153         if (retry <= 0)
154         {
155             BMCWEB_LOG_ERROR << "Failed to generate random number";
156             return std::string("");
157         }
158 
159         updateSubscriptionData();
160         return id;
161     }
162 
163     bool isSubscriptionExist(const std::string& id)
164     {
165         auto obj = subscriptionsMap.find(id);
166         if (obj == subscriptionsMap.end())
167         {
168             return false;
169         }
170         return true;
171     }
172 
173     void deleteSubscription(const std::string& id)
174     {
175         auto obj = subscriptionsMap.find(id);
176         if (obj != subscriptionsMap.end())
177         {
178             subscriptionsMap.erase(obj);
179             updateSubscriptionData();
180         }
181     }
182 
183     size_t getNumberOfSubscriptions()
184     {
185         return subscriptionsMap.size();
186     }
187 
188     std::vector<std::string> getAllIDs()
189     {
190         std::vector<std::string> idList;
191         for (const auto& it : subscriptionsMap)
192         {
193             idList.emplace_back(it.first);
194         }
195         return idList;
196     }
197 
198     bool isDestinationExist(const std::string& destUrl)
199     {
200         for (const auto& it : subscriptionsMap)
201         {
202             std::shared_ptr<Subscription> entry = it.second;
203             if (entry->destinationUrl == destUrl)
204             {
205                 BMCWEB_LOG_ERROR << "Destination exist already" << destUrl;
206                 return true;
207             }
208         }
209         return false;
210     }
211 };
212 
213 } // namespace redfish
214