1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 #pragma once 4 5 #include "filter_expr_parser_ast.hpp" 6 #include "filter_expr_printer.hpp" 7 #include "http_request.hpp" 8 #include "logging.hpp" 9 #include "registries/privilege_registry.hpp" 10 #include "server_sent_event.hpp" 11 #include "subscription.hpp" 12 13 #include <app.hpp> 14 #include <boost/url/param.hpp> 15 #include <boost/url/params_base.hpp> 16 #include <event_service_manager.hpp> 17 18 #include <format> 19 #include <memory> 20 #include <optional> 21 #include <string> 22 23 namespace redfish 24 { 25 createSubscription(crow::sse_socket::Connection & conn,const crow::Request & req)26inline void createSubscription(crow::sse_socket::Connection& conn, 27 const crow::Request& req) 28 { 29 EventServiceManager& manager = EventServiceManager::getInstance(); 30 if ((manager.getNumberOfSubscriptions() >= maxNoOfSubscriptions) || 31 manager.getNumberOfSSESubscriptions() >= maxNoOfSSESubscriptions) 32 { 33 BMCWEB_LOG_WARNING("Max SSE subscriptions reached"); 34 conn.close("Max SSE subscriptions reached"); 35 return; 36 } 37 38 std::optional<filter_ast::LogicalAnd> filter; 39 40 boost::urls::params_base::iterator filterIt = 41 req.url().params().find("$filter"); 42 43 if (filterIt != req.url().params().end()) 44 { 45 const boost::urls::param& filterParam = *filterIt; 46 filter = parseFilter(filterParam.value); 47 if (!filter) 48 { 49 conn.close(std::format("Bad $filter param: {}", filterParam.value)); 50 return; 51 } 52 } 53 54 std::string lastEventId(req.getHeaderValue("Last-Event-Id")); 55 56 std::shared_ptr<Subscription> subValue = 57 std::make_shared<Subscription>(conn); 58 59 if (subValue->userSub == nullptr) 60 { 61 BMCWEB_LOG_ERROR("Subscription data is null"); 62 conn.close("Internal Error"); 63 return; 64 } 65 66 // GET on this URI means, Its SSE subscriptionType. 67 subValue->userSub->subscriptionType = redfish::subscriptionTypeSSE; 68 69 subValue->userSub->protocol = "Redfish"; 70 subValue->userSub->retryPolicy = "TerminateAfterRetries"; 71 subValue->userSub->eventFormatType = "Event"; 72 73 std::string id = manager.addSSESubscription(subValue, lastEventId); 74 if (id.empty()) 75 { 76 conn.close("Internal Error"); 77 } 78 } 79 deleteSubscription(crow::sse_socket::Connection & conn)80inline void deleteSubscription(crow::sse_socket::Connection& conn) 81 { 82 EventServiceManager::getInstance().deleteSseSubscription(conn); 83 } 84 requestRoutesEventServiceSse(App & app)85inline void requestRoutesEventServiceSse(App& app) 86 { 87 // Note, this endpoint is given the same privilege level as creating a 88 // subscription, because functionally, that's the operation being done 89 BMCWEB_ROUTE(app, "/redfish/v1/EventService/SSE") 90 .privileges(redfish::privileges::postEventDestinationCollection) 91 .serverSentEvent() 92 .onopen(createSubscription) 93 .onclose(deleteSubscription); 94 } 95 } // namespace redfish 96