1 /*
2  * Copyright (c) 2022 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 #define LOG_TAG "AssetChangeTimer"
16 #include "asset_change_timer.h"
17 
18 #include "client_adaptor.h"
19 #include "logger.h"
20 #include "objectstore_errors.h"
21 
22 namespace OHOS::ObjectStore {
23 std::mutex AssetChangeTimer::instanceMutex;
24 AssetChangeTimer *AssetChangeTimer::instance = nullptr;
25 
GetInstance(FlatObjectStore * flatObjectStore)26 AssetChangeTimer *AssetChangeTimer::GetInstance(FlatObjectStore *flatObjectStore)
27 {
28     if (instance == nullptr) {
29         std::lock_guard<decltype(instanceMutex)> lockGuard(instanceMutex);
30         if (instance == nullptr) {
31             instance = new (std::nothrow) AssetChangeTimer(flatObjectStore);
32         }
33     }
34     return instance;
35 }
36 
AssetChangeTimer(FlatObjectStore * flatObjectStore)37 AssetChangeTimer::AssetChangeTimer(FlatObjectStore *flatObjectStore)
38 {
39     flatObjectStore_ = flatObjectStore;
40     executor_ = std::make_shared<ExecutorPool>(MAX_THREADS, MIN_THREADS);
41 }
42 
OnAssetChanged(const std::string & sessionId,const std::string & assetKey,std::shared_ptr<ObjectWatcher> watcher)43 void AssetChangeTimer::OnAssetChanged(
44     const std::string &sessionId, const std::string &assetKey, std::shared_ptr<ObjectWatcher> watcher)
45 {
46     StartTimer(sessionId, assetKey, watcher);
47 }
48 
StartTimer(const std::string & sessionId,const std::string & assetKey,std::shared_ptr<ObjectWatcher> watcher)49 void AssetChangeTimer::StartTimer(
50     const std::string &sessionId, const std::string &assetKey, std::shared_ptr<ObjectWatcher> watcher)
51 {
52     std::string key = sessionId + ASSET_SEPARATOR + assetKey;
53     std::lock_guard<decltype(mutex_)> lockGuard(mutex_);
54     if (assetChangeTasks_.find(key) == assetChangeTasks_.end()) {
55         assetChangeTasks_[key] =
56             executor_->Schedule(std::chrono::milliseconds(WAIT_INTERVAL), ProcessTask(sessionId, assetKey, watcher));
57     } else {
58         assetChangeTasks_[key] = executor_->Reset(assetChangeTasks_[key], std::chrono::milliseconds(WAIT_INTERVAL));
59     }
60 }
61 
ProcessTask(const std::string & sessionId,const std::string & assetKey,std::shared_ptr<ObjectWatcher> watcher)62 std::function<void()> AssetChangeTimer::ProcessTask(
63     const std::string &sessionId, const std::string &assetKey, std::shared_ptr<ObjectWatcher> watcher)
64 {
65     return [=]() {
66         LOG_DEBUG("Start working on a task, sessionId: %{public}s, assetKey: %{public}s", sessionId.c_str(),
67             assetKey.c_str());
68         StopTimer(sessionId, assetKey);
69         uint32_t status = HandleAssetChanges(sessionId, assetKey);
70         if (status == SUCCESS) {
71             LOG_DEBUG("Asset change task end, start callback, sessionId: %{public}s, assetKey: %{public}s",
72                 sessionId.c_str(), assetKey.c_str());
73             watcher->OnChanged(sessionId, { assetKey });
74         }
75     };
76 }
77 
StopTimer(const std::string & sessionId,const std::string & assetKey)78 void AssetChangeTimer::StopTimer(const std::string &sessionId, const std::string &assetKey)
79 {
80     std::string key = sessionId + ASSET_SEPARATOR + assetKey;
81     std::lock_guard<decltype(mutex_)> lockGuard(mutex_);
82     executor_->Remove(assetChangeTasks_[key]);
83     assetChangeTasks_.erase(key);
84 }
85 
HandleAssetChanges(const std::string & sessionId,const std::string & assetKey)86 uint32_t AssetChangeTimer::HandleAssetChanges(const std::string &sessionId, const std::string &assetKey)
87 {
88     Asset assetValue;
89     if (!GetAssetValue(sessionId, assetKey, assetValue)) {
90         LOG_ERROR("GetAssetValue assetValue is not complete, sessionId: %{public}s, assetKey: %{public}s",
91             sessionId.c_str(), assetKey.c_str());
92         return ERR_DB_GET_FAIL;
93     }
94 
95     std::string deviceId;
96     uint32_t status = flatObjectStore_->GetString(sessionId, DEVICEID_KEY, deviceId);
97     if (status != SUCCESS) {
98         LOG_ERROR("get deviceId failed %{public}d", status);
99         return status;
100     }
101 
102     sptr<OHOS::DistributedObject::IObjectService> proxy = ClientAdaptor::GetObjectService();
103     if (proxy == nullptr) {
104         LOG_ERROR("proxy is nullptr.");
105         return ERR_NULL_PTR;
106     }
107     int32_t res = proxy->OnAssetChanged(flatObjectStore_->GetBundleName(), sessionId, deviceId, assetValue);
108     if (res != SUCCESS) {
109         LOG_ERROR("OnAssetChanged failed status: %{public}d, sessionId: %{public}s, assetKey: %{public}s", status,
110             sessionId.c_str(), assetKey.c_str());
111     }
112     return res;
113 }
114 
GetAssetValue(const std::string & sessionId,const std::string & assetKey,Asset & assetValue)115 bool AssetChangeTimer::GetAssetValue(const std::string &sessionId, const std::string &assetKey, Asset &assetValue)
116 {
117     double doubleStatus;
118     if (flatObjectStore_->GetDouble(sessionId, assetKey + STATUS_SUFFIX, doubleStatus) == SUCCESS) {
119         assetValue.status = static_cast<uint32_t>(doubleStatus);
120     }
121     bool isComplete = true;
122     isComplete = isComplete &&
123         (flatObjectStore_->GetString(sessionId, assetKey + NAME_SUFFIX, assetValue.name) == SUCCESS);
124     isComplete = isComplete &&
125         (flatObjectStore_->GetString(sessionId, assetKey + URI_SUFFIX, assetValue.uri) == SUCCESS);
126     isComplete = isComplete &&
127         (flatObjectStore_->GetString(sessionId, assetKey + PATH_SUFFIX, assetValue.path) == SUCCESS);
128     isComplete = isComplete &&
129         (flatObjectStore_->GetString(sessionId, assetKey + CREATE_TIME_SUFFIX, assetValue.createTime) == SUCCESS);
130     isComplete = isComplete &&
131         (flatObjectStore_->GetString(sessionId, assetKey + MODIFY_TIME_SUFFIX, assetValue.modifyTime) == SUCCESS);
132     isComplete = isComplete &&
133         (flatObjectStore_->GetString(sessionId, assetKey + SIZE_SUFFIX, assetValue.size) == SUCCESS);
134     if (isComplete) {
135         assetValue.name = assetValue.name.substr(STRING_PREFIX_LEN);
136         assetValue.uri = assetValue.uri.substr(STRING_PREFIX_LEN);
137         assetValue.path = assetValue.path.substr(STRING_PREFIX_LEN);
138         assetValue.createTime = assetValue.createTime.substr(STRING_PREFIX_LEN);
139         assetValue.modifyTime = assetValue.modifyTime.substr(STRING_PREFIX_LEN);
140         assetValue.size = assetValue.size.substr(STRING_PREFIX_LEN);
141         assetValue.hash = assetValue.modifyTime + "_" + assetValue.size;
142     }
143     return isComplete;
144 }
145 } // namespace OHOS::ObjectStore