140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 35e44e3d8SAppaRao Puli #pragma once 45e44e3d8SAppaRao Puli 5*d7857201SEd Tanous #include "filter_expr_parser_ast.hpp" 6*d7857201SEd Tanous #include "filter_expr_printer.hpp" 7*d7857201SEd Tanous #include "http_request.hpp" 8*d7857201SEd Tanous #include "logging.hpp" 95b90429aSEd Tanous #include "registries/privilege_registry.hpp" 10*d7857201SEd Tanous #include "server_sent_event.hpp" 11*d7857201SEd Tanous #include "subscription.hpp" 125b90429aSEd Tanous 135e44e3d8SAppaRao Puli #include <app.hpp> 14*d7857201SEd Tanous #include <boost/url/params_base.hpp> 155e44e3d8SAppaRao Puli #include <event_service_manager.hpp> 165e44e3d8SAppaRao Puli 17*d7857201SEd Tanous #include <format> 185b90429aSEd Tanous #include <memory> 19*d7857201SEd Tanous #include <optional> 205b90429aSEd Tanous #include <string> 215b90429aSEd Tanous 225e44e3d8SAppaRao Puli namespace redfish 235e44e3d8SAppaRao Puli { 245e44e3d8SAppaRao Puli 25f80a87f2SEd Tanous inline void createSubscription(crow::sse_socket::Connection& conn, 26f80a87f2SEd Tanous const crow::Request& req) 275e44e3d8SAppaRao Puli { 285e44e3d8SAppaRao Puli EventServiceManager& manager = 295e44e3d8SAppaRao Puli EventServiceManager::getInstance(&conn.getIoContext()); 305e44e3d8SAppaRao Puli if ((manager.getNumberOfSubscriptions() >= maxNoOfSubscriptions) || 315e44e3d8SAppaRao Puli manager.getNumberOfSSESubscriptions() >= maxNoOfSSESubscriptions) 325e44e3d8SAppaRao Puli { 3362598e31SEd Tanous BMCWEB_LOG_WARNING("Max SSE subscriptions reached"); 345e44e3d8SAppaRao Puli conn.close("Max SSE subscriptions reached"); 355e44e3d8SAppaRao Puli return; 365e44e3d8SAppaRao Puli } 37f80a87f2SEd Tanous 38f80a87f2SEd Tanous std::optional<filter_ast::LogicalAnd> filter; 39f80a87f2SEd Tanous 40f80a87f2SEd Tanous boost::urls::params_base::iterator filterIt = 41f80a87f2SEd Tanous req.url().params().find("$filter"); 42f80a87f2SEd Tanous 43f80a87f2SEd Tanous if (filterIt != req.url().params().end()) 44f80a87f2SEd Tanous { 45f80a87f2SEd Tanous std::string_view filterValue = (*filterIt).value; 46f80a87f2SEd Tanous filter = parseFilter(filterValue); 47f80a87f2SEd Tanous if (!filter) 48f80a87f2SEd Tanous { 49f80a87f2SEd Tanous conn.close(std::format("Bad $filter param: {}", filterValue)); 50f80a87f2SEd Tanous return; 51f80a87f2SEd Tanous } 52f80a87f2SEd Tanous } 53f80a87f2SEd Tanous 54f80a87f2SEd Tanous std::string lastEventId(req.getHeaderValue("Last-Event-Id")); 55f80a87f2SEd Tanous 564b712a29SEd Tanous std::shared_ptr<Subscription> subValue = 574b712a29SEd Tanous std::make_shared<Subscription>(conn); 585e44e3d8SAppaRao Puli 595fe4ef35SMyung Bae if (subValue->userSub == nullptr) 605fe4ef35SMyung Bae { 615fe4ef35SMyung Bae BMCWEB_LOG_ERROR("Subscription data is null"); 625fe4ef35SMyung Bae conn.close("Internal Error"); 635fe4ef35SMyung Bae return; 645fe4ef35SMyung Bae } 655e44e3d8SAppaRao Puli 665fe4ef35SMyung Bae // GET on this URI means, Its SSE subscriptionType. 675fe4ef35SMyung Bae subValue->userSub->subscriptionType = redfish::subscriptionTypeSSE; 685fe4ef35SMyung Bae 695fe4ef35SMyung Bae subValue->userSub->protocol = "Redfish"; 705fe4ef35SMyung Bae subValue->userSub->retryPolicy = "TerminateAfterRetries"; 715fe4ef35SMyung Bae subValue->userSub->eventFormatType = "Event"; 725e44e3d8SAppaRao Puli 73f80a87f2SEd Tanous std::string id = manager.addSSESubscription(subValue, lastEventId); 745e44e3d8SAppaRao Puli if (id.empty()) 755e44e3d8SAppaRao Puli { 765e44e3d8SAppaRao Puli conn.close("Internal Error"); 775e44e3d8SAppaRao Puli } 785e44e3d8SAppaRao Puli } 795e44e3d8SAppaRao Puli 805e44e3d8SAppaRao Puli inline void deleteSubscription(crow::sse_socket::Connection& conn) 815e44e3d8SAppaRao Puli { 825e44e3d8SAppaRao Puli redfish::EventServiceManager::getInstance(&conn.getIoContext()) 835e44e3d8SAppaRao Puli .deleteSseSubscription(conn); 845e44e3d8SAppaRao Puli } 855e44e3d8SAppaRao Puli 865e44e3d8SAppaRao Puli inline void requestRoutesEventServiceSse(App& app) 875e44e3d8SAppaRao Puli { 885e44e3d8SAppaRao Puli // Note, this endpoint is given the same privilege level as creating a 895e44e3d8SAppaRao Puli // subscription, because functionally, that's the operation being done 905e44e3d8SAppaRao Puli BMCWEB_ROUTE(app, "/redfish/v1/EventService/SSE") 915e44e3d8SAppaRao Puli .privileges(redfish::privileges::postEventDestinationCollection) 925e44e3d8SAppaRao Puli .serverSentEvent() 935e44e3d8SAppaRao Puli .onopen(createSubscription) 945e44e3d8SAppaRao Puli .onclose(deleteSubscription); 955e44e3d8SAppaRao Puli } 965e44e3d8SAppaRao Puli } // namespace redfish 97