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