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/params_base.hpp> 15 #include <event_service_manager.hpp> 16 17 #include <format> 18 #include <memory> 19 #include <optional> 20 #include <string> 21 22 namespace redfish 23 { 24 25 inline void createSubscription(crow::sse_socket::Connection& conn, 26 const crow::Request& req) 27 { 28 EventServiceManager& manager = 29 EventServiceManager::getInstance(&conn.getIoContext()); 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 std::string_view filterValue = (*filterIt).value; 46 filter = parseFilter(filterValue); 47 if (!filter) 48 { 49 conn.close(std::format("Bad $filter param: {}", filterValue)); 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 80 inline void deleteSubscription(crow::sse_socket::Connection& conn) 81 { 82 redfish::EventServiceManager::getInstance(&conn.getIoContext()) 83 .deleteSseSubscription(conn); 84 } 85 86 inline void requestRoutesEventServiceSse(App& app) 87 { 88 // Note, this endpoint is given the same privilege level as creating a 89 // subscription, because functionally, that's the operation being done 90 BMCWEB_ROUTE(app, "/redfish/v1/EventService/SSE") 91 .privileges(redfish::privileges::postEventDestinationCollection) 92 .serverSentEvent() 93 .onopen(createSubscription) 94 .onclose(deleteSubscription); 95 } 96 } // namespace redfish 97