blob: 04314eae0c34670bf6b64c59e76488c995ee63c3 [file] [log] [blame]
#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