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