| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "subscription.h" | |
| #include <functional> | |
| #include <string> | |
| #include <utility> | |
| #include "absl/container/flat_hash_map.h" | |
| #include "absl/container/flat_hash_set.h" | |
| #include "absl/hash/hash.h" | |
| #include "absl/status/status.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/string_view.h" | |
| #include "absl/time/time.h" | |
| #include <nlohmann/json.hpp> | |
| namespace ecclesia { | |
| // EventSourceId definitions | |
| nlohmann::json EventSourceId::ToJSON() const { | |
| nlohmann::json json; | |
| json["key"] = key; | |
| switch (type) { | |
| case Type::kDbusObjects: | |
| json["type"] = "kDbusObjects"; | |
| break; | |
| case Type::kSocketIO: | |
| json["type"] = "kSocketIO"; | |
| break; | |
| case Type::kFileIO: | |
| json["type"] = "kFileIO"; | |
| break; | |
| } | |
| return json; | |
| } | |
| std::string EventSourceId::ToString() const { return this->ToJSON().dump(); } | |
| // EventId definitions. | |
| EventId::EventId(const SubscriptionId& subscription_id_in, | |
| const EventSourceId& source_id_in, absl::Time timestamp_in) | |
| : source_id(source_id_in), | |
| timestamp(timestamp_in), | |
| subscription_id(subscription_id_in), | |
| redfish_event_id( | |
| absl::HashOf(timestamp_in, source_id_in, subscription_id_in)) {} | |
| nlohmann::json EventId::ToJSON() const { | |
| nlohmann::json json; | |
| json["source_id"] = source_id.ToJSON(); | |
| json["timestamp"] = | |
| absl::FormatTime(absl::RFC3339_full, timestamp, absl::UTCTimeZone()); | |
| json["uuid"] = redfish_event_id; | |
| return json; | |
| } | |
| std::string EventId::ToString() const { return this->ToJSON().dump(); } | |
| // SubscriptionContext definitions. | |
| SubscriptionContext::SubscriptionContext( | |
| const SubscriptionId& subscription_id_in, | |
| const absl::flat_hash_map<EventSourceId, absl::flat_hash_set<std::string>>& | |
| event_source_to_uris_in, | |
| absl::flat_hash_map<std::string, Trigger> id_to_triggers_in, | |
| std::function<void(const nlohmann::json&)>&& on_event_callback_in) | |
| : subscription_id(subscription_id_in), | |
| event_source_to_uri(event_source_to_uris_in), | |
| id_to_triggers(std::move(id_to_triggers_in)), | |
| on_event_callback(std::move(on_event_callback_in)) {} | |
| // Trigger definitions. | |
| absl::StatusOr<Trigger> Trigger::Create(const nlohmann::json& trigger_json) { | |
| // Check if json is valid. | |
| if (trigger_json.is_discarded()) { | |
| return absl::InvalidArgumentError("Trigger json is discarded"); | |
| } | |
| // Parse the JSON data | |
| auto find_id = trigger_json.find("Id"); | |
| if (find_id == trigger_json.end()) { | |
| return absl::InvalidArgumentError("Trigger Id not populated"); | |
| } | |
| if (!find_id->is_string()) { | |
| return absl::InvalidArgumentError("Trigger Id is not a string"); | |
| } | |
| // Extract trigger information from the JSON data | |
| const std::string id = find_id->get<std::string>(); | |
| auto find_origin_resources = trigger_json.find("OriginResources"); | |
| if (find_origin_resources == trigger_json.end()) { | |
| return absl::InvalidArgumentError("OriginResources not populated"); | |
| } | |
| if (!find_origin_resources->is_array()) { | |
| return absl::InvalidArgumentError("OriginResources is not an array"); | |
| } | |
| absl::flat_hash_set<std::string> origin_resources; | |
| for (const auto& origin_resource : *find_origin_resources) { | |
| if (!origin_resource.is_object()) { | |
| return absl::InvalidArgumentError( | |
| "OriginResource entry is not an object"); | |
| } | |
| auto find_odata_id = origin_resource.find("@odata.id"); | |
| if (find_odata_id == origin_resource.end()) { | |
| return absl::InvalidArgumentError( | |
| "@odata.id not populated in OriginResource"); | |
| } | |
| if (!find_odata_id->is_string()) { | |
| return absl::InvalidArgumentError("@odata.id is not a string"); | |
| } | |
| origin_resources.insert(find_odata_id->get<std::string>()); | |
| } | |
| std::string predicate; | |
| bool event_mask = false; | |
| auto find_predicate = trigger_json.find("Predicate"); | |
| if (find_predicate != trigger_json.end()) { | |
| if (!find_predicate->is_string()) { | |
| return absl::InvalidArgumentError("Predicate is not a string"); | |
| } | |
| predicate = find_predicate->get<std::string>(); | |
| } else { | |
| // If predicate is not provided, this trigger will be used to poll data. | |
| // TODO(rahulkpr): Handle the polling case after adding trigger associations | |
| event_mask = true; | |
| } | |
| // Create a Trigger object with the extracted information | |
| Trigger trigger(id, std::move(origin_resources), predicate, event_mask); | |
| return trigger; | |
| } | |
| Trigger::Trigger(absl::string_view id_in, | |
| absl::flat_hash_set<std::string> origin_resources_in, | |
| absl::string_view predicate_in, bool mask_in) | |
| : id(id_in), | |
| origin_resources(std::move(origin_resources_in)), | |
| predicate(predicate_in), | |
| mask(mask_in) {} | |
| nlohmann::json Trigger::ToJSON() const { | |
| nlohmann::json json; | |
| // Create json array and store all origin_resources | |
| nlohmann::json& origin_resources_json = json["origin_resources"]; | |
| origin_resources_json = nlohmann::json::array(); | |
| origin_resources_json.insert_iterator(origin_resources_json.end(), | |
| origin_resources.begin(), | |
| origin_resources.end()); | |
| json["predicate"] = predicate; | |
| json["mask"] = mask; | |
| return json; | |
| } | |
| std::string Trigger::ToString() const { return this->ToJSON().dump(); } | |
| } // namespace ecclesia |