blob: 335b39a50d7d4e9c8ea9c47a626de6e78d719ff8 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/modular/bin/sessionmgr/story_runner/annotation_controller_impl.h"
#include <lib/syslog/cpp/macros.h>
#include <unordered_set>
#include "src/modular/bin/sessionmgr/annotations.h"
namespace modular {
AnnotationControllerImpl::AnnotationControllerImpl(std::string story_id,
SessionStorage* const session_storage)
: story_id_(std::move(story_id)), session_storage_(session_storage) {
FX_DCHECK(session_storage_ != nullptr);
}
void AnnotationControllerImpl::Connect(
fidl::InterfaceRequest<fuchsia::element::AnnotationController> request) {
bindings_.AddBinding(this, std::move(request));
}
void AnnotationControllerImpl::UpdateAnnotations(
std::vector<fuchsia::element::Annotation> annotations_to_set,
std::vector<fuchsia::element::AnnotationKey> annotations_to_delete,
UpdateAnnotationsCallback callback) {
fuchsia::element::AnnotationController_UpdateAnnotations_Result result;
// Ensure all keys, by themselves, are valid.
bool keys_to_set_are_valid{true};
for (const auto& annotation : annotations_to_set) {
if (!element::annotations::IsValidKey(annotation.key)) {
FX_LOGS(ERROR) << "Setting invalid key for story id: " << story_id_
<< " annotation key namespace: " << annotation.key.namespace_
<< " annotation key value: " << annotation.key.value;
keys_to_set_are_valid = false;
}
}
if (!keys_to_set_are_valid) {
result.set_err(fuchsia::element::UpdateAnnotationsError::INVALID_ARGS);
callback(std::move(result));
return;
}
bool keys_to_delete_are_valid{true};
for (const auto& annotation_key : annotations_to_delete) {
if (!element::annotations::IsValidKey(annotation_key)) {
FX_LOGS(ERROR) << "Deleting invalid key for story id: " << story_id_
<< " annotation key namespace: " << annotation_key.namespace_
<< " annotation key value: " << annotation_key.value;
keys_to_delete_are_valid = false;
}
}
if (!keys_to_delete_are_valid) {
result.set_err(fuchsia::element::UpdateAnnotationsError::INVALID_ARGS);
callback(std::move(result));
return;
}
// Ensure that there are no annotations being both set and deleted, i.e. that a key
// does not exist in both |annotations_to_set| and |annotations_to_delete|.
std::unordered_set<fuchsia::element::AnnotationKey> to_set_keys;
for (const auto& annotation : annotations_to_set) {
to_set_keys.insert(fidl::Clone(annotation.key));
}
bool is_same_key_set_delete{false};
for (const auto& annotation_key : annotations_to_delete) {
if (to_set_keys.count(annotation_key) > 0) {
FX_LOGS(ERROR) << "Setting and deleting the same annotation key for story id: " << story_id_
<< " annotation key namespace: " << annotation_key.namespace_
<< " annotation key value: " << annotation_key.value;
is_same_key_set_delete = true;
}
}
if (is_same_key_set_delete) {
result.set_err(fuchsia::element::UpdateAnnotationsError::INVALID_ARGS);
callback(std::move(result));
return;
}
auto modular_annotations = element::annotations::ToModularAnnotations(annotations_to_set);
// Add |annotations_to_delete| as Modular annotations with a null value.
// |MergeStoryAnnotations| removes annotations with a null value from the story.
for (const auto& key : annotations_to_delete) {
auto annotation = fuchsia::modular::Annotation{
.key = element::annotations::ToModularAnnotationKey(key), .value = nullptr};
modular_annotations.push_back(std::move(annotation));
}
auto merge_err =
session_storage_->MergeStoryAnnotations(story_id_, std::move(modular_annotations));
if (merge_err.has_value()) {
if (merge_err.value() == fuchsia::modular::AnnotationError::TOO_MANY_ANNOTATIONS) {
result.set_err(fuchsia::element::UpdateAnnotationsError::TOO_MANY_ANNOTATIONS);
} else {
result.set_err(fuchsia::element::UpdateAnnotationsError::INVALID_ARGS);
}
} else {
result.set_response({});
}
callback(std::move(result));
}
void AnnotationControllerImpl::GetAnnotations(GetAnnotationsCallback callback) {
auto story_data = session_storage_->GetStoryData(story_id_);
if (!story_data) {
fuchsia::element::AnnotationController_GetAnnotations_Result result;
result.set_response({});
callback(std::move(result));
return;
}
FX_DCHECK(story_data->has_story_info());
fuchsia::element::AnnotationController_GetAnnotations_Response response;
if (story_data->story_info().has_annotations()) {
response.annotations =
modular::annotations::ToElementAnnotations(story_data->story_info().annotations());
}
fuchsia::element::AnnotationController_GetAnnotations_Result result;
result.set_response(std::move(response));
callback(std::move(result));
}
void AnnotationControllerImpl::WatchAnnotations(WatchAnnotationsCallback callback) {
if (!watch_annotations_called_) {
watch_annotations_called_ = true;
GetAnnotations(std::move(reinterpret_cast<GetAnnotationsCallback&>(callback)));
return;
}
session_storage_->SubscribeAnnotationsUpdated(
[story_id = story_id_, callback = std::move(callback)](
std::string updated_story_id,
const std::vector<fuchsia::modular::Annotation>& annotations,
const std::set<std::string>& /*annotation_keys_added*/,
const std::set<std::string>& /*annotation_keys_deleted*/) {
if (updated_story_id != story_id) {
return WatchInterest::kContinue;
}
fuchsia::element::AnnotationController_WatchAnnotations_Response response{
modular::annotations::ToElementAnnotations(annotations)};
fuchsia::element::AnnotationController_WatchAnnotations_Result result{};
result.set_response(std::move(response));
callback(std::move(result));
return WatchInterest::kStop;
});
}
} // namespace modular