xref: /openbmc/bmcweb/redfish-core/lib/eventservice_sse.hpp (revision 3577e44683a5ade8ad02a6418984b56f4ca2bcac)
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)26 inline 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)80 inline void deleteSubscription(crow::sse_socket::Connection& conn)
81 {
82     EventServiceManager::getInstance().deleteSseSubscription(conn);
83 }
84 
requestRoutesEventServiceSse(App & app)85 inline 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