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