xref: /openbmc/bmcweb/redfish-core/lib/eventservice_sse.hpp (revision 9838eb20341568971b9543c2187372d20daf64aa)
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 
createSubscription(crow::sse_socket::Connection & conn,const crow::Request & req)25 inline void createSubscription(crow::sse_socket::Connection& conn,
26                                const crow::Request& req)
27 {
28     EventServiceManager& manager = EventServiceManager::getInstance();
29     if ((manager.getNumberOfSubscriptions() >= maxNoOfSubscriptions) ||
30         manager.getNumberOfSSESubscriptions() >= maxNoOfSSESubscriptions)
31     {
32         BMCWEB_LOG_WARNING("Max SSE subscriptions reached");
33         conn.close("Max SSE subscriptions reached");
34         return;
35     }
36 
37     std::optional<filter_ast::LogicalAnd> filter;
38 
39     boost::urls::params_base::iterator filterIt =
40         req.url().params().find("$filter");
41 
42     if (filterIt != req.url().params().end())
43     {
44         std::string_view filterValue = (*filterIt).value;
45         filter = parseFilter(filterValue);
46         if (!filter)
47         {
48             conn.close(std::format("Bad $filter param: {}", filterValue));
49             return;
50         }
51     }
52 
53     std::string lastEventId(req.getHeaderValue("Last-Event-Id"));
54 
55     std::shared_ptr<Subscription> subValue =
56         std::make_shared<Subscription>(conn);
57 
58     if (subValue->userSub == nullptr)
59     {
60         BMCWEB_LOG_ERROR("Subscription data is null");
61         conn.close("Internal Error");
62         return;
63     }
64 
65     // GET on this URI means, Its SSE subscriptionType.
66     subValue->userSub->subscriptionType = redfish::subscriptionTypeSSE;
67 
68     subValue->userSub->protocol = "Redfish";
69     subValue->userSub->retryPolicy = "TerminateAfterRetries";
70     subValue->userSub->eventFormatType = "Event";
71 
72     std::string id = manager.addSSESubscription(subValue, lastEventId);
73     if (id.empty())
74     {
75         conn.close("Internal Error");
76     }
77 }
78 
deleteSubscription(crow::sse_socket::Connection & conn)79 inline void deleteSubscription(crow::sse_socket::Connection& conn)
80 {
81     EventServiceManager::getInstance().deleteSseSubscription(conn);
82 }
83 
requestRoutesEventServiceSse(App & app)84 inline void requestRoutesEventServiceSse(App& app)
85 {
86     // Note, this endpoint is given the same privilege level as creating a
87     // subscription, because functionally, that's the operation being done
88     BMCWEB_ROUTE(app, "/redfish/v1/EventService/SSE")
89         .privileges(redfish::privileges::postEventDestinationCollection)
90         .serverSentEvent()
91         .onopen(createSubscription)
92         .onclose(deleteSubscription);
93 }
94 } // namespace redfish
95