1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "core/common/recorder/node_data_cache.h"
16
17 #include <string>
18
19 #include "base/json/json_util.h"
20 #include "base/log/log_wrapper.h"
21 #include "core/common/container.h"
22 #include "core/common/recorder/event_recorder.h"
23
24 namespace OHOS::Ace::Recorder {
25 constexpr int32_t PAGE_URL_SUFFIX_LENGTH = 3;
26
GetCurrentPageUrl()27 const std::string GetCurrentPageUrl()
28 {
29 CHECK_RUN_ON(UI);
30 auto container = Container::Current();
31 CHECK_NULL_RETURN(container, "");
32 auto frontEnd = container->GetFrontend();
33 CHECK_NULL_RETURN(frontEnd, "");
34 auto pageUrl = frontEnd->GetCurrentPageUrl();
35 // remove .js suffix if exists
36 if (StringUtils::EndWith(pageUrl, ".js")) {
37 return pageUrl.substr(0, pageUrl.length() - PAGE_URL_SUFFIX_LENGTH);
38 }
39 return pageUrl;
40 }
41
Get()42 NodeDataCache& NodeDataCache::Get()
43 {
44 static NodeDataCache cache;
45 return cache;
46 }
47
NodeDataCache()48 NodeDataCache::NodeDataCache()
49 {
50 container_ = std::make_shared<NodeDataContainer>();
51 mergedConfig_ = std::make_shared<MergedConfig>();
52 }
53
OnPageReady()54 void NodeDataCache::OnPageReady()
55 {
56 prePageUrl_ = pageUrl_;
57 pageUrl_ = GetCurrentPageUrl();
58 }
59
OnPageShow(const std::string & pageUrl)60 void NodeDataCache::OnPageShow(const std::string& pageUrl)
61 {
62 prePageUrl_ = pageUrl_;
63 pageUrl_ = pageUrl;
64 }
65
OnBeforePagePop(bool destroy)66 void NodeDataCache::OnBeforePagePop(bool destroy)
67 {
68 if (destroy) {
69 Clear(prePageUrl_);
70 } else {
71 Clear(pageUrl_);
72 }
73 shouldCollectFull_ = false;
74 }
75
UpdateConfig(std::shared_ptr<MergedConfig> && mergedConfig)76 void NodeDataCache::UpdateConfig(std::shared_ptr<MergedConfig>&& mergedConfig)
77 {
78 std::unique_lock<std::mutex> lock(cacheLock_);
79 mergedConfig_ = mergedConfig;
80 shouldCollectFull_ = false;
81 }
82
PutString(const std::string & id,const std::string & value)83 bool NodeDataCache::PutString(const std::string& id, const std::string& value)
84 {
85 if (id.empty() || value.empty() || value.length() > MAX_DATA_LENGTH) {
86 return false;
87 }
88 std::unique_lock<std::mutex> lock(cacheLock_);
89 if (pageUrl_.empty()) {
90 pageUrl_ = GetCurrentPageUrl();
91 }
92 auto iter = mergedConfig_->shareNodes.find(pageUrl_);
93 if (!shouldCollectFull_ && iter == mergedConfig_->shareNodes.end()) {
94 return false;
95 }
96 if (shouldCollectFull_ || iter->second.find(id) != iter->second.end()) {
97 auto iter = container_->find(pageUrl_);
98 if (iter == container_->end()) {
99 auto pageContainer = std::unordered_map<std::string, std::string>();
100 pageContainer.emplace(id, value);
101 container_->emplace(pageUrl_, std::move(pageContainer));
102 } else {
103 if (iter->second.size() >= MAX_SIZE_PER_PAGE) {
104 return false;
105 }
106 iter->second[id] = value;
107 }
108 }
109 return true;
110 }
111
PutBool(const std::string & id,bool value)112 bool NodeDataCache::PutBool(const std::string& id, bool value)
113 {
114 std::string strVal = value ? "true" : "false";
115 return PutString(id, strVal);
116 }
117
PutInt(const std::string & id,int value)118 bool NodeDataCache::PutInt(const std::string& id, int value)
119 {
120 return PutString(id, std::to_string(value));
121 }
122
PutStringArray(const std::string & id,const std::vector<std::string> & value)123 bool NodeDataCache::PutStringArray(const std::string& id, const std::vector<std::string>& value)
124 {
125 auto jsonArray = JsonUtil::CreateArray(true);
126 for (size_t i = 0; i < value.size(); i++) {
127 jsonArray->Put(std::to_string(i).c_str(), value.at(i).c_str());
128 }
129 return PutString(id, jsonArray->ToString());
130 }
131
PutMultiple(const std::string & id,const std::string & name,bool value)132 bool NodeDataCache::PutMultiple(const std::string& id, const std::string& name, bool value)
133 {
134 auto json = JsonUtil::Create(true);
135 json->Put(KEY_TEXT, name.c_str());
136 json->Put(KEY_CHECKED, value);
137 return PutString(id, json->ToString());
138 }
139
PutMultiple(const std::string & id,const std::string & name,int index)140 bool NodeDataCache::PutMultiple(const std::string& id, const std::string& name, int index)
141 {
142 auto json = JsonUtil::Create(true);
143 json->Put(KEY_TEXT, name.c_str());
144 json->Put(KEY_INDEX, index);
145 return PutString(id, json->ToString());
146 }
147
PutMultiple(const std::string & id,const std::string & name,const std::vector<std::string> & value)148 bool NodeDataCache::PutMultiple(const std::string& id, const std::string& name, const std::vector<std::string>& value)
149 {
150 auto json = JsonUtil::Create(true);
151 json->Put(KEY_TEXT, name.c_str());
152 auto jsonArray = JsonUtil::CreateArray(false);
153 for (size_t i = 0; i < value.size(); i++) {
154 jsonArray->Put(std::to_string(i).c_str(), value.at(i).c_str());
155 }
156 json->Put(KEY_TEXT_ARRAY, jsonArray);
157 return PutString(id, json->ToString());
158 }
159
GetNodeData(const std::string & pageUrl,std::unordered_map<std::string,std::string> & nodes)160 void NodeDataCache::GetNodeData(const std::string& pageUrl, std::unordered_map<std::string, std::string>& nodes)
161 {
162 if (pageUrl.empty()) {
163 return;
164 }
165 std::unique_lock<std::mutex> lock(cacheLock_);
166 auto iter = container_->find(pageUrl);
167 if (iter == container_->end()) {
168 return;
169 }
170 lock.unlock();
171 for (auto nodeIter = nodes.begin(); nodeIter != nodes.end(); nodeIter++) {
172 auto it = iter->second.find(nodeIter->first);
173 if (it != iter->second.end()) {
174 nodes[it->first] = it->second;
175 }
176 }
177 }
178
Clear(const std::string & pageUrl)179 void NodeDataCache::Clear(const std::string& pageUrl)
180 {
181 if (pageUrl.empty()) {
182 return;
183 }
184 std::unique_lock<std::mutex> lock(cacheLock_);
185 auto iter = container_->find(pageUrl);
186 if (iter != container_->end()) {
187 container_->erase(iter);
188 }
189 }
190
Reset()191 void NodeDataCache::Reset()
192 {
193 std::unique_lock<std::mutex> lock(cacheLock_);
194 container_->clear();
195 pageUrl_ = "";
196 prePageUrl_ = "";
197 }
198
GetExposureCfg(const std::string & inspectId,ExposureCfg & cfg)199 void NodeDataCache::GetExposureCfg(const std::string& inspectId, ExposureCfg& cfg)
200 {
201 if (pageUrl_.empty()) {
202 pageUrl_ = GetCurrentPageUrl();
203 }
204 auto iter = mergedConfig_->exposureNodes.find(pageUrl_);
205 if (iter == mergedConfig_->exposureNodes.end()) {
206 return;
207 }
208 auto cfgIter = iter->second.find({ inspectId, 0.0, 0 });
209 if (cfgIter == iter->second.end()) {
210 return;
211 }
212 cfg.id = cfgIter->id;
213 cfg.ratio = cfgIter->ratio;
214 cfg.duration = cfgIter->duration;
215 }
216 } // namespace OHOS::Ace::Recorder
217