Upload upstream chromium 114.0.5735.31
[platform/framework/web/chromium-efl.git] / components / fuchsia_component_support / annotations_manager.cc
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.
4
5 #include "components/fuchsia_component_support/annotations_manager.h"
6
7 #include <lib/fpromise/promise.h>
8
9 #include <set>
10 #include <string>
11 #include <tuple>
12 #include <utility>
13
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"
21
22 namespace fuchsia_component_support {
23
24 namespace {
25 using AnnotationKeySet =
26     std::set<fuchsia::element::AnnotationKey, AnnotationKeyCompare>;
27 }  // namespace
28
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);
34
35   constexpr size_t kArbitraryTextBufferThreshold = 128;
36   if (value.size() <= kArbitraryTextBufferThreshold) {
37     result.value.set_text(std::string(value));
38   } else {
39     result.value.set_buffer(base::MemBufferFromString(value, /*name=*/key));
40   }
41
42   return result;
43 }
44
45 fuchsia::element::Annotation MakeBoolAnnotation(base::StringPiece key,
46                                                 bool value) {
47   static constexpr base::StringPiece kTrue("true");
48   static constexpr base::StringPiece kFalse("false");
49   return MakeAnnotation(key, value ? kTrue : kFalse);
50 }
51
52 fuchsia::element::Annotation MakeIntAnnotation(base::StringPiece key,
53                                                int value) {
54   return MakeAnnotation(key, base::NumberToString(value));
55 }
56
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);
62 }
63
64 class AnnotationsManager::ControllerImpl
65     : public fuchsia::element::AnnotationController {
66  public:
67   explicit ControllerImpl(AnnotationsManager& manager) : manager_(manager) {}
68   ~ControllerImpl() override = default;
69
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 {
75     DVLOG(2) << __func__;
76     if (manager_->UpdateAnnotations(std::move(annotations_to_set),
77                                     std::move(annotations_to_delete))) {
78       callback(fpromise::ok());
79     } else {
80       callback(fpromise::error(
81           fuchsia::element::UpdateAnnotationsError::INVALID_ARGS));
82     }
83   }
84   void GetAnnotations(GetAnnotationsCallback callback) override {
85     DVLOG(2) << __func__;
86     callback(fpromise::ok(manager_->GetAnnotations()));
87   }
88   void WatchAnnotations(WatchAnnotationsCallback callback) override {
89     DVLOG(2) << __func__;
90
91     if (have_changes_) {
92       have_changes_ = false;
93       callback(fpromise::ok(manager_->GetAnnotations()));
94       return;
95     }
96
97     if (on_annotations_changed_) {
98       manager_->bindings_.CloseBinding(this, ZX_ERR_BAD_STATE);
99       return;
100     }
101
102     on_annotations_changed_ = std::move(callback);
103   }
104
105   void OnAnnotationsChanged() {
106     have_changes_ = true;
107     if (on_annotations_changed_) {
108       WatchAnnotations(std::exchange(on_annotations_changed_, {}));
109     }
110   }
111
112  private:
113   const raw_ref<AnnotationsManager> manager_;
114
115   // Initially true so that the first call to WatchAnnotations() will
116   // return results immediately.
117   bool have_changes_ = true;
118
119   WatchAnnotationsCallback on_annotations_changed_;
120 };
121
122 AnnotationsManager::AnnotationsManager() = default;
123
124 AnnotationsManager::~AnnotationsManager() = default;
125
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);
133     if (!inserted) {
134       return false;
135     }
136   }
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);
142     if (!inserted) {
143       return false;
144     }
145   }
146
147   if (!changed.empty()) {
148     for (auto& binding : bindings_.bindings()) {
149       binding->impl()->OnAnnotationsChanged();
150     }
151   }
152
153   return true;
154 }
155
156 std::vector<fuchsia::element::Annotation> AnnotationsManager::GetAnnotations()
157     const {
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);
164   }
165   return result;
166 }
167
168 void AnnotationsManager::Connect(
169     fidl::InterfaceRequest<fuchsia::element::AnnotationController> request) {
170   bindings_.AddBinding(std::make_unique<ControllerImpl>(*this),
171                        std::move(request));
172 }
173
174 }  // namespace fuchsia_component_support