1 /*
2 * Copyright (c) 2023-2024 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
16 #include "listener/kv_data_change_listener.h"
17
18 #include <algorithm>
19 #include <cinttypes>
20
21 #include "datetime_ex.h"
22 #include "string_ex.h"
23
24 #include "distributed_device_profile_constants.h"
25 #include "distributed_device_profile_errors.h"
26 #include "device_profile_manager.h"
27 #include "profile_utils.h"
28 #include "profile_cache.h"
29 #include "subscribe_profile_manager.h"
30 #include "subscribe_profile_manager.h"
31 #include "distributed_device_profile_log.h"
32
33 #include "types.h"
34
35 namespace OHOS {
36 namespace DistributedDeviceProfile {
37 namespace {
38 const std::string TAG = "KvDataChangeListener";
39 const std::string STATIC_STORE_ID = "dp_kv_static_store";
40 }
41
KvDataChangeListener(const std::string & storeId)42 KvDataChangeListener::KvDataChangeListener(const std::string& storeId)
43 {
44 HILOGD("construct!");
45 storeId_ = storeId;
46 }
47
~KvDataChangeListener()48 KvDataChangeListener::~KvDataChangeListener()
49 {
50 HILOGD("destruct!");
51 }
52
OnChange(const DistributedKv::ChangeNotification & changeNotification)53 void KvDataChangeListener::OnChange(const DistributedKv::ChangeNotification& changeNotification)
54 {
55 HILOGI("storeId=%{public}s", storeId_.c_str());
56 if (storeId_ == STATIC_STORE_ID) {
57 return;
58 }
59 if (!changeNotification.GetInsertEntries().empty() &&
60 changeNotification.GetInsertEntries().size() <= MAX_DB_RECORD_SIZE) {
61 HandleAddChange(changeNotification.GetInsertEntries());
62 }
63 if (!changeNotification.GetUpdateEntries().empty() &&
64 changeNotification.GetUpdateEntries().size() <= MAX_DB_RECORD_SIZE) {
65 HandleUpdateChange(changeNotification.GetUpdateEntries());
66 }
67 if (!changeNotification.GetDeleteEntries().empty() &&
68 changeNotification.GetDeleteEntries().size() <= MAX_DB_RECORD_SIZE) {
69 HandleDeleteChange(changeNotification.GetDeleteEntries());
70 }
71 }
72
OnChange(const DistributedKv::DataOrigin & origin,Keys && keys)73 void KvDataChangeListener::OnChange(const DistributedKv::DataOrigin& origin, Keys&& keys)
74 {
75 HILOGI("Cloud data Change. store=%{public}s", origin.store.c_str());
76 if (origin.store == STATIC_STORE_ID) {
77 return;
78 }
79 std::vector<DistributedKv::Entry> insertRecords = DeviceProfileManager::GetInstance()
80 .GetEntriesByKeys(keys[ChangeOp::OP_INSERT]);
81 if (!insertRecords.empty() && insertRecords.size() <= MAX_DB_RECORD_SIZE) {
82 HandleAddChange(insertRecords);
83 }
84 std::vector<DistributedKv::Entry> updateRecords = DeviceProfileManager::GetInstance()
85 .GetEntriesByKeys(keys[ChangeOp::OP_UPDATE]);
86 if (!updateRecords.empty() && updateRecords.size() <= MAX_DB_RECORD_SIZE) {
87 HandleUpdateChange(updateRecords);
88 }
89 std::vector<std::string> delKeys = keys[ChangeOp::OP_DELETE];
90 if (!delKeys.empty() && delKeys.size() <= MAX_DB_RECORD_SIZE) {
91 std::vector<DistributedKv::Entry> deleteRecords;
92 for (const auto& key : delKeys) {
93 DistributedKv::Entry entry;
94 DistributedKv::Key kvKey(key);
95 entry.key = kvKey;
96 deleteRecords.emplace_back(entry);
97 }
98 HandleDeleteChange(deleteRecords);
99 }
100 }
101
OnSwitchChange(const DistributedKv::SwitchNotification & notification)102 void KvDataChangeListener::OnSwitchChange(const DistributedKv::SwitchNotification& notification)
103 {
104 HILOGI("Switch data change, deviceId: %{public}s", ProfileUtils::GetAnonyString(notification.deviceId).c_str());
105 if (notification.deviceId.empty()) {
106 HILOGE("params are valid");
107 return;
108 }
109 // is local or is online
110 std::string netWorkId = notification.deviceId;
111 std::string udid;
112 int32_t res = ProfileCache::GetInstance().GetUdidByNetWorkId(netWorkId, udid);
113 if (res != DP_SUCCESS || udid.empty()) {
114 HILOGD("get udid fail, netWorkId is invalid: %{public}s",
115 ProfileUtils::GetAnonyString(netWorkId).c_str());
116 return;
117 }
118 HandleSwitchUpdateChange(udid, notification.data.value);
119 }
120
FilterEntries(const std::vector<DistributedKv::Entry> & records,std::map<std::string,std::string> & entriesMap,bool isDelete)121 void KvDataChangeListener::FilterEntries(const std::vector<DistributedKv::Entry>& records,
122 std::map<std::string, std::string>& entriesMap, bool isDelete)
123 {
124 std::map<std::string, std::string> ohSuffix2NonMaps;
125 std::map<std::string, std::string> non2OhSuffixMaps;
126 for (const auto& item : records) {
127 std::string dbKey = item.key.ToString();
128 std::vector<std::string> res;
129 if (ProfileUtils::SplitString(dbKey, SEPARATOR, res) != DP_SUCCESS || res.size() < NUM_3) {
130 HILOGW("invalid dbkey(%{public}s)", ProfileUtils::GetDbKeyAnonyString(dbKey).c_str());
131 continue;
132 }
133 if (res[0] != DEV_PREFIX && res[0] != SVR_PREFIX && res[0] != CHAR_PREFIX) {
134 HILOGW("%{public}s is invalid dbKey", ProfileUtils::GetDbKeyAnonyString(dbKey).c_str());
135 continue;
136 }
137 if (res[0] == CHAR_PREFIX && res.back() == CHARACTERISTIC_KEY) {
138 HILOGW("%{public}s is charProfileKey", ProfileUtils::GetDbKeyAnonyString(dbKey).c_str());
139 continue;
140 }
141 entriesMap[dbKey] = item.value.ToString();
142 if (ProfileUtils::EndsWith(res[NUM_2], OH_PROFILE_SUFFIX)) {
143 res[NUM_2] = ProfileUtils::CheckAndRemoveOhSuffix(res[NUM_2]);
144 ohSuffix2NonMaps[dbKey] = ProfileUtils::JoinString(res, SEPARATOR);
145 continue;
146 }
147 if (ProfileUtils::IsNeedAddOhSuffix(res[NUM_2], res.front() == SVR_PREFIX)) {
148 res[NUM_2] = ProfileUtils::CheckAndAddOhSuffix(res[NUM_2], res.front() == SVR_PREFIX);
149 non2OhSuffixMaps[dbKey] = ProfileUtils::JoinString(res, SEPARATOR);
150 continue;
151 }
152 }
153 for (const auto& [ohSuffixKey, nonOhSuffixKey] : ohSuffix2NonMaps) {
154 entriesMap.erase(nonOhSuffixKey);
155 non2OhSuffixMaps.erase(nonOhSuffixKey);
156 }
157 ohSuffix2NonMaps.clear();
158 if (isDelete) { return; }
159 if (non2OhSuffixMaps.empty()) { return; }
160 std::vector<std::string> ohSuffixKeys;
161 for (const auto& [nonOhSuffixKey, ohSuffixKey] : non2OhSuffixMaps) {
162 ohSuffix2NonMaps[ohSuffixKey] = nonOhSuffixKey;
163 ohSuffixKeys.emplace_back(ohSuffixKey);
164 }
165 std::vector<DistributedKv::Entry> entries = DeviceProfileManager::GetInstance().GetEntriesByKeys(ohSuffixKeys);
166 if (entries.empty()) { return; }
167 for (const auto& item : entries) {
168 entriesMap.erase(ohSuffix2NonMaps[item.key.ToString()]);
169 }
170 }
171
HandleAddChange(const std::vector<DistributedKv::Entry> & insertRecords)172 void KvDataChangeListener::HandleAddChange(const std::vector<DistributedKv::Entry>& insertRecords)
173 {
174 HILOGD("Handle kv data add change!");
175 std::map<std::string, std::string> entries;
176 FilterEntries(insertRecords, entries, false);
177 for (const auto& [dbKey, dbValue] : entries) {
178 ProfileType profileType = ProfileUtils::GetProfileType(dbKey);
179 SubscribeProfileManager::GetInstance().NotifyProfileChange(profileType, ChangeType::ADD, dbKey, dbValue);
180 }
181 }
182
HandleUpdateChange(const std::vector<DistributedKv::Entry> & updateRecords)183 void KvDataChangeListener::HandleUpdateChange(const std::vector<DistributedKv::Entry>& updateRecords)
184 {
185 HILOGD("Handle kv data update change!");
186 std::map<std::string, std::string> entries;
187 FilterEntries(updateRecords, entries, false);
188 for (const auto& [dbKey, dbValue] : entries) {
189 ProfileType profileType = ProfileUtils::GetProfileType(dbKey);
190 SubscribeProfileManager::GetInstance().NotifyProfileChange(profileType, ChangeType::UPDATE, dbKey, dbValue);
191 }
192 }
193
HandleDeleteChange(const std::vector<DistributedKv::Entry> & deleteRecords)194 void KvDataChangeListener::HandleDeleteChange(const std::vector<DistributedKv::Entry>& deleteRecords)
195 {
196 HILOGD("Handle kv data delete change!");
197 std::map<std::string, std::string> entries;
198 FilterEntries(deleteRecords, entries, true);
199 for (const auto& [dbKey, dbValue] : entries) {
200 ProfileType profileType = ProfileUtils::GetProfileType(dbKey);
201 SubscribeProfileManager::GetInstance().NotifyProfileChange(profileType, ChangeType::DELETE, dbKey, dbValue);
202 }
203 }
204
HandleSwitchUpdateChange(const std::string udid,uint32_t switchValue)205 void KvDataChangeListener::HandleSwitchUpdateChange(const std::string udid, uint32_t switchValue)
206 {
207 HILOGI("udid: %{public}s, switch: %{public}u", ProfileUtils::GetAnonyString(udid).c_str(), switchValue);
208 std::string serviceName;
209
210 for (int32_t i = (int32_t)SwitchFlag::SWITCH_FLAG_MIN + NUM_1;
211 i < (int32_t)SwitchFlag::SWITCH_FLAG_MAX; ++i) {
212 std::string itemSwitchValue = std::to_string((switchValue >> i) & NUM_1);
213 int32_t res = ProfileCache::GetInstance().GetServiceNameByPos(i, SWITCH_SERVICE_MAP, serviceName);
214 if (res != DP_SUCCESS || serviceName.empty()) {
215 HILOGE("GetServiceNameByPos failed, pos:%{public}d", i);
216 return;
217 }
218 res = GenerateSwitchNotify(udid, serviceName, SWITCH_STATUS,
219 itemSwitchValue, ChangeType::UPDATE);
220 if (res != DP_SUCCESS) {
221 HILOGE("GenerateSwitchNotify failed, res: %{public}d", res);
222 return;
223 }
224 if (udid == ProfileCache::GetInstance().GetLocalUdid()) {
225 ProfileCache::GetInstance().SetCurSwitch(switchValue);
226 HILOGD("update curLocalSwitch: %{public}d", ProfileCache::GetInstance().GetSwitch());
227 }
228 }
229 }
230
GenerateSwitchNotify(const std::string & udid,const std::string & serviceName,const std::string & characteristicProfileKey,const std::string & characteristicProfileValue,ChangeType changeType)231 int32_t KvDataChangeListener::GenerateSwitchNotify(const std::string& udid, const std::string& serviceName,
232 const std::string& characteristicProfileKey, const std::string& characteristicProfileValue, ChangeType changeType)
233 {
234 if (!ProfileUtils::IsKeyValid(udid) ||
235 !ProfileUtils::IsKeyValid(serviceName) ||
236 !ProfileUtils::IsKeyValid(characteristicProfileKey) ||
237 !ProfileUtils::IsKeyValid(characteristicProfileValue)) {
238 HILOGE("Params are invalid!");
239 return DP_INVALID_PARAMS;
240 }
241
242 CharacteristicProfile newSwitchProfile = {udid, serviceName, characteristicProfileKey,
243 characteristicProfileValue};
244 HILOGI("Gen SwitchProfile :%{public}s", newSwitchProfile.dump().c_str());
245 if (ProfileCache::GetInstance().IsCharProfileExist(newSwitchProfile)) {
246 HILOGW("switch is not change");
247 return DP_SUCCESS;
248 }
249 const CharacteristicProfile cacheProfile = newSwitchProfile;
250 ProfileCache::GetInstance().AddCharProfile(cacheProfile);
251 std::string dbKey = ProfileUtils::GetDbKeyByProfile(newSwitchProfile);
252 ProfileType profileType = ProfileUtils::GetProfileType(dbKey);
253 int32_t res = SubscribeProfileManager::GetInstance().NotifyProfileChange(profileType, changeType, dbKey,
254 newSwitchProfile.GetCharacteristicValue());
255 if (res != DP_SUCCESS) {
256 HILOGE("NotifyProfileChange failed");
257 return DP_GENERATE_SWITCH_NOTIFY_FAIL;
258 }
259 return DP_SUCCESS;
260 }
261 } // namespace DeviceProfile
262 } // namespace OHOS
263