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 eventSeqNum(1), 52 host(inHost), 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 void sendTestEventLog() 78 { 79 nlohmann::json logEntryArray; 80 logEntryArray.push_back({}); 81 nlohmann::json& logEntryJson = logEntryArray.back(); 82 83 logEntryJson = {{"EventId", "TestID"}, 84 {"EventType", "Event"}, 85 {"Severity", "OK"}, 86 {"Message", "Generated test event"}, 87 {"MessageId", "OpenBMC.0.1.TestEventLog"}, 88 {"MessageArgs", nlohmann::json::array()}, 89 {"EventTimestamp", crow::utility::dateTimeNow()}, 90 {"Context", customText}}; 91 92 nlohmann::json msg = {{"@odata.type", "#Event.v1_4_0.Event"}, 93 {"Id", std::to_string(eventSeqNum)}, 94 {"Name", "Event Log"}, 95 {"Events", logEntryArray}}; 96 97 this->sendEvent(msg.dump()); 98 this->eventSeqNum++; 99 } 100 101 private: 102 uint64_t eventSeqNum; 103 std::string host; 104 std::string port; 105 std::string path; 106 std::string uriProto; 107 std::shared_ptr<crow::HttpClient> conn; 108 }; 109 110 class EventServiceManager 111 { 112 private: 113 EventServiceManager(const EventServiceManager&) = delete; 114 EventServiceManager& operator=(const EventServiceManager&) = delete; 115 EventServiceManager(EventServiceManager&&) = delete; 116 EventServiceManager& operator=(EventServiceManager&&) = delete; 117 118 EventServiceManager() 119 { 120 // TODO: Read the persistent data from store and populate. 121 // Populating with default. 122 enabled = true; 123 retryAttempts = 3; 124 retryTimeoutInterval = 30; // seconds 125 } 126 127 boost::container::flat_map<std::string, std::shared_ptr<Subscription>> 128 subscriptionsMap; 129 130 public: 131 bool enabled; 132 uint32_t retryAttempts; 133 uint32_t retryTimeoutInterval; 134 135 static EventServiceManager& getInstance() 136 { 137 static EventServiceManager handler; 138 return handler; 139 } 140 141 void updateSubscriptionData() 142 { 143 // Persist the config and subscription data. 144 // TODO: subscriptionsMap & configData need to be 145 // written to Persist store. 146 return; 147 } 148 149 std::shared_ptr<Subscription> getSubscription(const std::string& id) 150 { 151 auto obj = subscriptionsMap.find(id); 152 if (obj == subscriptionsMap.end()) 153 { 154 BMCWEB_LOG_ERROR << "No subscription exist with ID:" << id; 155 return nullptr; 156 } 157 std::shared_ptr<Subscription> subValue = obj->second; 158 return subValue; 159 } 160 161 std::string addSubscription(const std::shared_ptr<Subscription> subValue) 162 { 163 std::srand(static_cast<uint32_t>(std::time(0))); 164 std::string id; 165 166 int retry = 3; 167 while (retry) 168 { 169 id = std::to_string(std::rand()); 170 auto inserted = subscriptionsMap.insert(std::pair(id, subValue)); 171 if (inserted.second) 172 { 173 break; 174 } 175 --retry; 176 }; 177 178 if (retry <= 0) 179 { 180 BMCWEB_LOG_ERROR << "Failed to generate random number"; 181 return std::string(""); 182 } 183 184 updateSubscriptionData(); 185 return id; 186 } 187 188 bool isSubscriptionExist(const std::string& id) 189 { 190 auto obj = subscriptionsMap.find(id); 191 if (obj == subscriptionsMap.end()) 192 { 193 return false; 194 } 195 return true; 196 } 197 198 void deleteSubscription(const std::string& id) 199 { 200 auto obj = subscriptionsMap.find(id); 201 if (obj != subscriptionsMap.end()) 202 { 203 subscriptionsMap.erase(obj); 204 updateSubscriptionData(); 205 } 206 } 207 208 size_t getNumberOfSubscriptions() 209 { 210 return subscriptionsMap.size(); 211 } 212 213 std::vector<std::string> getAllIDs() 214 { 215 std::vector<std::string> idList; 216 for (const auto& it : subscriptionsMap) 217 { 218 idList.emplace_back(it.first); 219 } 220 return idList; 221 } 222 223 bool isDestinationExist(const std::string& destUrl) 224 { 225 for (const auto& it : subscriptionsMap) 226 { 227 std::shared_ptr<Subscription> entry = it.second; 228 if (entry->destinationUrl == destUrl) 229 { 230 BMCWEB_LOG_ERROR << "Destination exist already" << destUrl; 231 return true; 232 } 233 } 234 return false; 235 } 236 237 void sendTestEventLog() 238 { 239 for (const auto& it : this->subscriptionsMap) 240 { 241 std::shared_ptr<Subscription> entry = it.second; 242 entry->sendTestEventLog(); 243 } 244 } 245 }; 246 247 } // namespace redfish 248