1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/fuchsia_component_support/annotations_manager.h"
7 #include <lib/fpromise/promise.h>
14 #include "base/check.h"
15 #include "base/fuchsia/fuchsia_logging.h"
16 #include "base/fuchsia/mem_buffer_util.h"
17 #include "base/logging.h"
18 #include "base/memory/raw_ref.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_piece.h"
22 namespace fuchsia_component_support {
25 using AnnotationKeySet =
26 std::set<fuchsia::element::AnnotationKey, AnnotationKeyCompare>;
29 fuchsia::element::Annotation MakeAnnotation(base::StringPiece key,
30 base::StringPiece value) {
31 fuchsia::element::Annotation result;
32 result.key.namespace_ = "global";
33 result.key.value = std::string(key);
35 constexpr size_t kArbitraryTextBufferThreshold = 128;
36 if (value.size() <= kArbitraryTextBufferThreshold) {
37 result.value.set_text(std::string(value));
39 result.value.set_buffer(base::MemBufferFromString(value, /*name=*/key));
45 fuchsia::element::Annotation MakeBoolAnnotation(base::StringPiece key,
47 static constexpr base::StringPiece kTrue("true");
48 static constexpr base::StringPiece kFalse("false");
49 return MakeAnnotation(key, value ? kTrue : kFalse);
52 fuchsia::element::Annotation MakeIntAnnotation(base::StringPiece key,
54 return MakeAnnotation(key, base::NumberToString(value));
57 bool AnnotationKeyCompare::operator()(
58 const fuchsia::element::AnnotationKey& key1,
59 const fuchsia::element::AnnotationKey& key2) const {
60 return std::tie(key1.namespace_, key1.value) <
61 std::tie(key2.namespace_, key2.value);
64 class AnnotationsManager::ControllerImpl
65 : public fuchsia::element::AnnotationController {
67 explicit ControllerImpl(AnnotationsManager& manager) : manager_(manager) {}
68 ~ControllerImpl() override = default;
70 // fuchsia::element::AnnotationController implementation.
71 void UpdateAnnotations(
72 std::vector<fuchsia::element::Annotation> annotations_to_set,
73 std::vector<fuchsia::element::AnnotationKey> annotations_to_delete,
74 UpdateAnnotationsCallback callback) override {
76 if (manager_->UpdateAnnotations(std::move(annotations_to_set),
77 std::move(annotations_to_delete))) {
78 callback(fpromise::ok());
80 callback(fpromise::error(
81 fuchsia::element::UpdateAnnotationsError::INVALID_ARGS));
84 void GetAnnotations(GetAnnotationsCallback callback) override {
86 callback(fpromise::ok(manager_->GetAnnotations()));
88 void WatchAnnotations(WatchAnnotationsCallback callback) override {
92 have_changes_ = false;
93 callback(fpromise::ok(manager_->GetAnnotations()));
97 if (on_annotations_changed_) {
98 manager_->bindings_.CloseBinding(this, ZX_ERR_BAD_STATE);
102 on_annotations_changed_ = std::move(callback);
105 void OnAnnotationsChanged() {
106 have_changes_ = true;
107 if (on_annotations_changed_) {
108 WatchAnnotations(std::exchange(on_annotations_changed_, {}));
113 const raw_ref<AnnotationsManager> manager_;
115 // Initially true so that the first call to WatchAnnotations() will
116 // return results immediately.
117 bool have_changes_ = true;
119 WatchAnnotationsCallback on_annotations_changed_;
122 AnnotationsManager::AnnotationsManager() = default;
124 AnnotationsManager::~AnnotationsManager() = default;
126 bool AnnotationsManager::UpdateAnnotations(
127 std::vector<fuchsia::element::Annotation> to_set,
128 std::vector<fuchsia::element::AnnotationKey> to_delete) {
129 AnnotationKeySet changed;
130 for (const auto& key : to_delete) {
131 annotations_.erase(key);
132 auto [it, inserted] = changed.insert(key);
137 for (auto& annotation : to_set) {
138 annotations_.insert_or_assign(
139 fuchsia::element::AnnotationKey(annotation.key),
140 std::move(annotation.value));
141 auto [it, inserted] = changed.insert(annotation.key);
147 if (!changed.empty()) {
148 for (auto& binding : bindings_.bindings()) {
149 binding->impl()->OnAnnotationsChanged();
156 std::vector<fuchsia::element::Annotation> AnnotationsManager::GetAnnotations()
158 std::vector<fuchsia::element::Annotation> result;
159 result.reserve(annotations_.size());
160 for (const auto& [key, value] : annotations_) {
161 result.push_back(fuchsia::element::Annotation{.key = key});
162 zx_status_t status = value.Clone(&result.back().value);
163 ZX_CHECK(status == ZX_OK, status);
168 void AnnotationsManager::Connect(
169 fidl::InterfaceRequest<fuchsia::element::AnnotationController> request) {
170 bindings_.AddBinding(std::make_unique<ControllerImpl>(*this),
174 } // namespace fuchsia_component_support