1 /*
2 * Copyright (C) 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 <chrono>
17 #include <vector>
18 #include <string>
19 #include <thread>
20
21 #include "cloud_sync_observer.h"
22
23 #include "cloud_media_asset_manager.h"
24 #include "cloud_sync_notify_handler.h"
25 #include "media_analysis_helper.h"
26 #include "media_file_utils.h"
27 #include "medialibrary_unistore_manager.h"
28 #include "media_column.h"
29 #include "media_log.h"
30 #include "result_set_utils.h"
31 #include "albums_refresh_manager.h"
32 #include "photo_album_column.h"
33 #include "albums_refresh_notify.h"
34 #include "notify_responsibility_chain_factory.h"
35 #include "post_event_utils.h"
36
37 using namespace std;
38
39 namespace OHOS {
40 namespace Media {
41 constexpr int32_t SYNC_INTERVAL = 10000;
HandleCloudNotify(AsyncTaskData * data)42 static void HandleCloudNotify(AsyncTaskData *data)
43 {
44 auto* taskData = static_cast<CloudSyncNotifyData*>(data);
45 shared_ptr<CloudSyncNotifyHandler> notifyHandler = make_shared<CloudSyncNotifyHandler>(taskData->notifyInfo_);
46 notifyHandler->MakeResponsibilityChain();
47 }
48
DealCloudSync(const ChangeInfo & changeInfo)49 void CloudSyncObserver::DealCloudSync(const ChangeInfo &changeInfo)
50 {
51 SyncNotifyInfo info;
52 info.uris = changeInfo.uris_;
53 std::string dataString = (const char *)changeInfo.data_;
54 CHECK_AND_RETURN_WARN_LOG(nlohmann::json::accept(dataString),
55 "Failed to verify the meataData format, metaData is: %{public}s", dataString.c_str());
56 nlohmann::json jsonData = nlohmann::json::parse(dataString);
57 CHECK_AND_EXECUTE(!jsonData.contains("taskType"), info.taskType = jsonData["taskType"]);
58 CHECK_AND_EXECUTE(!jsonData.contains("syncId"), info.syncId = jsonData["syncId"]);
59 CHECK_AND_EXECUTE(!jsonData.contains("syncType"), info.syncType = jsonData["syncType"]);
60 CHECK_AND_EXECUTE(!jsonData.contains("totalAssets"), info.totalAssets = jsonData["totalAssets"]);
61 CHECK_AND_EXECUTE(!jsonData.contains("totalAlbums"), info.totalAlbums = jsonData["totalAlbums"]);
62
63 if (info.taskType == TIME_BEGIN_SYNC) {
64 PostEventUtils::GetInstance().CreateCloudDownloadSyncStat(info.syncId);
65 VariantMap map = {
66 {KEY_START_DOWNLOAD_TIME, MediaFileUtils::UTCTimeMilliSeconds()}, {KEY_DOWNLOAD_TYPE, info.syncType}};
67 PostEventUtils::GetInstance().UpdateCloudDownloadSyncStat(map);
68 AlbumsRefreshManager::GetInstance().AddAlbumRefreshTask(info);
69 } else if (info.taskType == TIME_END_SYNC) {
70 AlbumsRefreshManager::GetInstance().AddAlbumRefreshTask(info);
71 }
72 }
73
DealAlbumGallery(CloudSyncNotifyInfo & notifyInfo)74 void CloudSyncObserver::DealAlbumGallery(CloudSyncNotifyInfo ¬ifyInfo)
75 {
76 SyncNotifyInfo info = AlbumsRefreshManager::GetInstance().GetSyncNotifyInfo(notifyInfo, ALBUM_URI_TYPE);
77 AlbumsRefreshManager::GetInstance().AddAlbumRefreshTask(info);
78 VariantMap map;
79 if (info.notifyType == NOTIFY_ADD) {
80 map = {{KEY_TOTAL_ALBUM_NUM, info.urisSize}, {KEY_ADD_ALBUM_NUM, info.urisSize}};
81 } else if (info.notifyType == NOTIFY_UPDATE) {
82 map = {{KEY_TOTAL_ALBUM_NUM, info.urisSize}, {KEY_UPDATE_ALBUM_NUM, info.urisSize}};
83 } else if (info.notifyType == NOTIFY_REMOVE) {
84 map = {{KEY_TOTAL_ALBUM_NUM, info.urisSize}, {KEY_DELETE_ALBUM_NUM, info.urisSize}};
85 }
86 PostEventUtils::GetInstance().UpdateCloudDownloadSyncStat(map);
87 }
88
DealPhotoGallery(CloudSyncNotifyInfo & notifyInfo)89 void CloudSyncObserver::DealPhotoGallery(CloudSyncNotifyInfo ¬ifyInfo)
90 {
91 if (notifyInfo.type == ChangeType::UPDATE || notifyInfo.type == ChangeType::OTHER ||
92 notifyInfo.type == ChangeType::DELETE) {
93 CloudSyncHandleData handleData;
94 handleData.orgInfo = notifyInfo;
95 shared_ptr<BaseHandler> chain = NotifyResponsibilityChainFactory::CreateChain(GALLERY_PHOTO_DELETE);
96 if (chain != nullptr) {
97 chain->Handle(handleData);
98 } else {
99 MEDIA_ERR_LOG("uri OR type is Invalid");
100 }
101 }
102 SyncNotifyInfo info = AlbumsRefreshManager::GetInstance().GetSyncNotifyInfo(notifyInfo, PHOTO_URI_TYPE);
103 AlbumsRefreshManager::GetInstance().AddAlbumRefreshTask(info);
104 VariantMap map;
105 if (info.notifyType == NOTIFY_ADD) {
106 map = {{KEY_TOTAL_ASSET_NUM, info.urisSize}, {KEY_ADD_ASSET_NUM, info.urisSize}};
107 } else if (info.notifyType == NOTIFY_UPDATE) {
108 map = {{KEY_TOTAL_ASSET_NUM, info.urisSize}, {KEY_UPDATE_ASSET_NUM, info.urisSize}};
109 } else if (info.notifyType == NOTIFY_REMOVE) {
110 map = {{KEY_TOTAL_ASSET_NUM, info.urisSize}, {KEY_DELETE_ASSET_NUM, info.urisSize}};
111 }
112 PostEventUtils::GetInstance().UpdateCloudDownloadSyncStat(map);
113 if (notifyInfo.type == ChangeType::DELETE) {
114 CloudMediaAssetManager::GetInstance().SetIsThumbnailUpdate();
115 }
116 }
117
DealGalleryDownload(CloudSyncNotifyInfo & notifyInfo)118 void CloudSyncObserver::DealGalleryDownload(CloudSyncNotifyInfo ¬ifyInfo)
119 {
120 if (notifyInfo.type == ChangeType::OTHER) {
121 CHECK_AND_RETURN_LOG(!notifyInfo.uris.empty(), "gallery download notify uri empty");
122 string uriString = notifyInfo.uris.front().ToString();
123 string downloadString = "gallery/download";
124 string::size_type pos = uriString.find(downloadString);
125 CHECK_AND_RETURN_LOG(pos != string::npos, "gallery download notify uri err");
126 auto it = notifyInfo.uris.begin();
127 *it = Uri(uriString.replace(pos, downloadString.length(), "Photo"));
128 notifyInfo.type = ChangeType::UPDATE;
129 CloudSyncHandleData handleData;
130 handleData.orgInfo = notifyInfo;
131 shared_ptr<BaseHandler> chain = NotifyResponsibilityChainFactory::CreateChain(TRANSPARENT);
132 CHECK_AND_EXECUTE(chain == nullptr, chain->Handle(handleData));
133 }
134 }
135
OnChange(const ChangeInfo & changeInfo)136 void CloudSyncObserver::OnChange(const ChangeInfo &changeInfo)
137 {
138 CloudSyncNotifyInfo notifyInfo = {changeInfo.uris_, changeInfo.changeType_, changeInfo.data_};
139 string uriString = notifyInfo.uris.front().ToString();
140 MEDIA_DEBUG_LOG("#uriString: %{public}s, #uriSize: %{public}zu changeType: %{public}d",
141 uriString.c_str(), changeInfo.uris_.size(), changeInfo.changeType_);
142
143 if (uriString.find(PhotoAlbumColumns::PHOTO_GALLERY_CLOUD_SYNC_INFO_URI_PREFIX) != string::npos) {
144 DealCloudSync(changeInfo);
145 return;
146 }
147
148 if (uriString.find(PhotoColumn::PHOTO_CLOUD_URI_PREFIX) != string::npos && notifyInfo.type == ChangeType::OTHER) {
149 lock_guard<mutex> lock(syncMutex_);
150 if (!isPending_) {
151 MEDIA_INFO_LOG("set timer handle index");
152 std::thread([this]() { this->HandleIndex(); }).detach();
153 isPending_ = true;
154 }
155 }
156
157 if (uriString.find(PhotoAlbumColumns::ALBUM_GALLERY_CLOUD_URI_PREFIX) != string::npos) {
158 DealAlbumGallery(notifyInfo);
159 return;
160 }
161
162 if (uriString.find(PhotoColumn::PHOTO_GALLERY_CLOUD_URI_PREFIX) != string::npos) {
163 DealPhotoGallery(notifyInfo);
164 return;
165 }
166
167 if (uriString.find(PhotoAlbumColumns::PHOTO_GALLERY_DOWNLOAD_URI_PREFIX) != string::npos) {
168 DealGalleryDownload(notifyInfo);
169 return;
170 }
171
172 auto *taskData = new (nothrow) CloudSyncNotifyData(notifyInfo);
173 CHECK_AND_RETURN_LOG(taskData != nullptr, "Failed to new taskData");
174 shared_ptr<MediaLibraryAsyncWorker> asyncWorker = MediaLibraryAsyncWorker::GetInstance();
175 if (asyncWorker == nullptr) {
176 MEDIA_ERR_LOG("Can not get asyncWorker");
177 delete taskData;
178 return;
179 }
180 shared_ptr<MediaLibraryAsyncTask> notifyHandleAsyncTask = make_shared<MediaLibraryAsyncTask>(
181 HandleCloudNotify, taskData);
182 CHECK_AND_EXECUTE(notifyHandleAsyncTask == nullptr, asyncWorker->AddTask(notifyHandleAsyncTask, true));
183 }
184
HandleIndex()185 void CloudSyncObserver::HandleIndex()
186 {
187 std::this_thread::sleep_for(std::chrono::milliseconds(SYNC_INTERVAL));
188 lock_guard<mutex> lock(syncMutex_);
189 std::vector<std::string> idToDeleteIndex;
190 MediaAnalysisHelper::AsyncStartMediaAnalysisService(
191 static_cast<int32_t>(MediaAnalysisProxy::ActivateServiceType::START_DELETE_INDEX), idToDeleteIndex);
192
193 //update index
194 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
195 CHECK_AND_RETURN_LOG(uniStore != nullptr, "uniStore is nullptr!");
196 const std::string queryIdToUpdateIndex = "SELECT file_id FROM tab_analysis_search_index WHERE photo_status = 2";
197 auto resultSetUpdateIndex = uniStore->QuerySql(queryIdToUpdateIndex);
198 CHECK_AND_RETURN_LOG(resultSetUpdateIndex != nullptr, "resultSetUpdateIndex is nullptr!");
199 std::vector<std::string> idToUpdateIndex;
200 while (resultSetUpdateIndex->GoToNextRow() == NativeRdb::E_OK) {
201 idToUpdateIndex.push_back(to_string(GetInt32Val("file_id", resultSetUpdateIndex)));
202 }
203
204 MEDIA_INFO_LOG("HandleIndex idToUpdateIndex size: %{public}zu", idToUpdateIndex.size());
205 CHECK_AND_EXECUTE(idToUpdateIndex.empty(), MediaAnalysisHelper::AsyncStartMediaAnalysisService(
206 static_cast<int32_t>(MediaAnalysisProxy::ActivateServiceType::START_UPDATE_INDEX), idToUpdateIndex));
207 isPending_ = false;
208 }
209 } // namespace Media
210 } // namespace OHOS
211