| #pragma once |
| |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/string_view.h" |
| #include "request_response.h" |
| #include "sse/sse_parser.h" |
| #include "google/protobuf/message.h" |
| |
| namespace milotic { |
| |
| class Proxy; |
| |
| // Interface for plugins to handle incoming gRPC requests. |
| // |
| // A plugin is enabled when it is added to the build dependencies, and its |
| // configuration is present in Configuration.proxy_configuration.plugins. The |
| // order of this repeated field determines the plugin execution order. |
| // An exception to this is redfish_passthrough_plugin (or any other plugin that |
| // defines CreateDefaultPlugin): This plugin will always be inserted to run |
| // after all others. |
| // |
| // Plugins that are not default should define a PluginFactory. See |
| // proxy_builder.h. |
| class RedfishPlugin { |
| public: |
| enum class RequestVerb : uint8_t { |
| kInvalid, |
| kGet, |
| kPost, |
| kPut, |
| kPatch, |
| kDelete, |
| kSubscribe, // This is only used in PreprocessRequest |
| kBidirectionalStream, // This is only used in PreprocessRequest |
| kInternal, |
| }; |
| enum class RequestAction : uint8_t { kInvalid, kDrop, kHandle, kNext }; |
| class EventHandler { |
| public: |
| virtual ~EventHandler() = default; |
| // Called when there is an initial response. This response should indicate |
| // if an event stream is starting, or it should report that there was a |
| // failure starting the stream. Returning an error will terminate the |
| // connection, but using `IsCancelled` to terminate the connection is |
| // preferred if there is no error. |
| virtual absl::Status OnResponse(const ProxyResponse& response) = 0; |
| // Called with the contents of a new event. Events may be SSE or some proto. |
| // The handler implementation may handle one or both of these. Returning an |
| // error will terminate the connection, but using `IsCancelled` to terminate |
| // the connection is preferred if there is no error. |
| virtual absl::Status OnEvent(const ServerSentEvent& event) = 0; |
| virtual absl::Status OnEvent(const google::protobuf::Message& event_message) = 0; |
| // The handler can terminate the subscription by returning `true` from this |
| // function. |
| virtual bool IsCancelled() const = 0; |
| virtual void OnFinished(const absl::Status& status) { |
| LOG(DFATAL) << "OnFinished is not implemented"; |
| } |
| }; |
| virtual ~RedfishPlugin() {} |
| |
| // Modify the request if needed, and return what to do with it. |
| // kDrop will drop the request |
| // kHandle will handle the request using this plugin. If the verb is |
| // `kSubscribe`, the `Subscribe` method will be called. Otherwise, the |
| // `Handle` method will called. |
| // kNext will continue to the next plugin |
| virtual RequestAction PreprocessRequest(RedfishPlugin::RequestVerb verb, |
| ProxyRequest& request) = 0; |
| |
| // Handles a single Redfish request of type verb. |
| // Takes ownership of the request |
| virtual absl::StatusOr<ProxyResponse> HandleRequest( |
| RedfishPlugin::RequestVerb verb, |
| std::unique_ptr<ProxyRequest> request) = 0; |
| |
| // Subscribe to event source. e.g. SSE. The plugin should call the appropriate |
| // callbacks in `handler`. See the descriptions in the `EventHandler` class. |
| virtual absl::Status Subscribe(std::unique_ptr<ProxyRequest> request, |
| EventHandler* handler) = 0; |
| |
| // Start a bidirectional stream. The plugin should call the appropriate |
| // callbacks in `handler`, and return another EventHandler to handle incoming |
| // messages. See the descriptions in the `EventHandler` class. |
| virtual absl::StatusOr<std::unique_ptr<EventHandler>> BidirectionalStream( |
| std::unique_ptr<ProxyRequest> request, EventHandler* handler) { |
| return absl::UnimplementedError("Not implemented"); |
| } |
| |
| // Initialize plugin state with provided parameter state |
| // Return true if initialization successful, false if |
| // initialization failed and plugin should not be enabled |
| virtual absl::Status Initialize(Proxy* proxy) = 0; |
| |
| void SetName(absl::string_view name) { name_ = name; } |
| absl::string_view Name() const { return name_; } |
| |
| private: |
| std::string name_; |
| }; |
| |
| constexpr absl::string_view VerbToString(RedfishPlugin::RequestVerb verb) { |
| switch (verb) { |
| case RedfishPlugin::RequestVerb::kGet: |
| return "GET"; |
| case RedfishPlugin::RequestVerb::kPost: |
| return "POST"; |
| case RedfishPlugin::RequestVerb::kDelete: |
| return "DELETE"; |
| case RedfishPlugin::RequestVerb::kPut: |
| return "PUT"; |
| case RedfishPlugin::RequestVerb::kPatch: |
| return "PATCH"; |
| case RedfishPlugin::RequestVerb::kSubscribe: |
| return "SUBSCRIBE"; |
| case RedfishPlugin::RequestVerb::kInternal: |
| return "INTERNAL"; |
| default: |
| return "UNKNOWN"; |
| } |
| } |
| |
| } // namespace milotic |