153c3577eSopenharmony_ci/*
253c3577eSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
353c3577eSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
453c3577eSopenharmony_ci * you may not use this file except in compliance with the License.
553c3577eSopenharmony_ci * You may obtain a copy of the License at
653c3577eSopenharmony_ci *
753c3577eSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
853c3577eSopenharmony_ci *
953c3577eSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1053c3577eSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1153c3577eSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1253c3577eSopenharmony_ci * See the License for the specific language governing permissions and
1353c3577eSopenharmony_ci * limitations under the License.
1453c3577eSopenharmony_ci */
1553c3577eSopenharmony_ci
1653c3577eSopenharmony_ci#define LOG_TAG "UserDelegate"
1753c3577eSopenharmony_ci#include "user_delegate.h"
1853c3577eSopenharmony_ci
1953c3577eSopenharmony_ci#include <chrono>
2053c3577eSopenharmony_ci#include <cinttypes>
2153c3577eSopenharmony_ci#include <thread>
2253c3577eSopenharmony_ci
2353c3577eSopenharmony_ci#include "communicator/device_manager_adapter.h"
2453c3577eSopenharmony_ci#include "log_print.h"
2553c3577eSopenharmony_ci#include "metadata/meta_data_manager.h"
2653c3577eSopenharmony_ci#include "utils/anonymous.h"
2753c3577eSopenharmony_ci
2853c3577eSopenharmony_cinamespace OHOS::DistributedData {
2953c3577eSopenharmony_ciusing namespace OHOS::DistributedKv;
3053c3577eSopenharmony_ciusing namespace std::chrono;
3153c3577eSopenharmony_cistd::string GetLocalDeviceId()
3253c3577eSopenharmony_ci{
3353c3577eSopenharmony_ci    return DeviceManagerAdapter::GetInstance().GetLocalDevice().uuid;
3453c3577eSopenharmony_ci}
3553c3577eSopenharmony_ci
3653c3577eSopenharmony_cistd::vector<UserStatus> UserDelegate::GetLocalUserStatus()
3753c3577eSopenharmony_ci{
3853c3577eSopenharmony_ci    ZLOGI("begin");
3953c3577eSopenharmony_ci    auto deviceId = GetLocalDeviceId();
4053c3577eSopenharmony_ci    if (deviceId.empty()) {
4153c3577eSopenharmony_ci        ZLOGE("failed to get local device id");
4253c3577eSopenharmony_ci        return {};
4353c3577eSopenharmony_ci    }
4453c3577eSopenharmony_ci    return GetUsers(deviceId);
4553c3577eSopenharmony_ci}
4653c3577eSopenharmony_ci
4753c3577eSopenharmony_cistd::set<std::string> UserDelegate::GetLocalUsers()
4853c3577eSopenharmony_ci{
4953c3577eSopenharmony_ci    auto deviceId = GetLocalDeviceId();
5053c3577eSopenharmony_ci    if (deviceId.empty()) {
5153c3577eSopenharmony_ci        ZLOGE("failed to get local device id");
5253c3577eSopenharmony_ci        return {};
5353c3577eSopenharmony_ci    }
5453c3577eSopenharmony_ci    std::set<std::string> users;
5553c3577eSopenharmony_ci    deviceUser_.Compute(deviceId, [&users](const auto &key, auto &value) {
5653c3577eSopenharmony_ci        if (value.empty()) {
5753c3577eSopenharmony_ci            UserMetaData userMetaData;
5853c3577eSopenharmony_ci            MetaDataManager::GetInstance().LoadMeta(UserMetaRow::GetKeyFor(key), userMetaData);
5953c3577eSopenharmony_ci            for (const auto &user : userMetaData.users) {
6053c3577eSopenharmony_ci                value[user.id] = user.isActive;
6153c3577eSopenharmony_ci            }
6253c3577eSopenharmony_ci        }
6353c3577eSopenharmony_ci        for (const auto [user, active] : value) {
6453c3577eSopenharmony_ci            users.emplace(std::to_string(user));
6553c3577eSopenharmony_ci        }
6653c3577eSopenharmony_ci        return !value.empty();
6753c3577eSopenharmony_ci    });
6853c3577eSopenharmony_ci    return users;
6953c3577eSopenharmony_ci}
7053c3577eSopenharmony_ci
7153c3577eSopenharmony_cistd::vector<DistributedData::UserStatus> UserDelegate::GetRemoteUserStatus(const std::string &deviceId)
7253c3577eSopenharmony_ci{
7353c3577eSopenharmony_ci    if (deviceId.empty()) {
7453c3577eSopenharmony_ci        ZLOGE("error input device id");
7553c3577eSopenharmony_ci        return {};
7653c3577eSopenharmony_ci    }
7753c3577eSopenharmony_ci    return GetUsers(deviceId);
7853c3577eSopenharmony_ci}
7953c3577eSopenharmony_ci
8053c3577eSopenharmony_cistd::vector<UserStatus> UserDelegate::GetUsers(const std::string &deviceId)
8153c3577eSopenharmony_ci{
8253c3577eSopenharmony_ci    std::vector<UserStatus> userStatus;
8353c3577eSopenharmony_ci    deviceUser_.Compute(deviceId, [&userStatus](const auto &key, auto &users) {
8453c3577eSopenharmony_ci        if (users.empty()) {
8553c3577eSopenharmony_ci            UserMetaData userMetaData;
8653c3577eSopenharmony_ci            MetaDataManager::GetInstance().LoadMeta(UserMetaRow::GetKeyFor(key), userMetaData);
8753c3577eSopenharmony_ci            for (const auto &user : userMetaData.users) {
8853c3577eSopenharmony_ci                users[user.id] = user.isActive;
8953c3577eSopenharmony_ci            }
9053c3577eSopenharmony_ci        }
9153c3577eSopenharmony_ci        for (const auto [key, value] : users) {
9253c3577eSopenharmony_ci            userStatus.emplace_back(key, value);
9353c3577eSopenharmony_ci        }
9453c3577eSopenharmony_ci        return !users.empty();
9553c3577eSopenharmony_ci    });
9653c3577eSopenharmony_ci    auto time = static_cast<uint64_t>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count());
9753c3577eSopenharmony_ci    ZLOGI("device:%{public}s, users:%{public}s times %{public}" PRIu64 ".", Anonymous::Change(deviceId).c_str(),
9853c3577eSopenharmony_ci        Serializable::Marshall(userStatus).c_str(), time);
9953c3577eSopenharmony_ci    return userStatus;
10053c3577eSopenharmony_ci}
10153c3577eSopenharmony_ci
10253c3577eSopenharmony_civoid UserDelegate::DeleteUsers(const std::string &deviceId)
10353c3577eSopenharmony_ci{
10453c3577eSopenharmony_ci    deviceUser_.Erase(deviceId);
10553c3577eSopenharmony_ci}
10653c3577eSopenharmony_ci
10753c3577eSopenharmony_civoid UserDelegate::UpdateUsers(const std::string &deviceId, const std::vector<UserStatus> &userStatus)
10853c3577eSopenharmony_ci{
10953c3577eSopenharmony_ci    ZLOGI("begin, device:%{public}s, users:%{public}zu", Anonymous::Change(deviceId).c_str(), userStatus.size());
11053c3577eSopenharmony_ci    deviceUser_.Compute(deviceId, [&userStatus](const auto &key, std::map<int, bool> &users) {
11153c3577eSopenharmony_ci        users = {};
11253c3577eSopenharmony_ci        for (const auto &user : userStatus) {
11353c3577eSopenharmony_ci            users[user.id] = user.isActive;
11453c3577eSopenharmony_ci        }
11553c3577eSopenharmony_ci        ZLOGI("end, device:%{public}s, users:%{public}zu", Anonymous::Change(key).c_str(), users.size());
11653c3577eSopenharmony_ci        return true;
11753c3577eSopenharmony_ci    });
11853c3577eSopenharmony_ci}
11953c3577eSopenharmony_ci
12053c3577eSopenharmony_cibool UserDelegate::InitLocalUserMeta()
12153c3577eSopenharmony_ci{
12253c3577eSopenharmony_ci    std::vector<int> users;
12353c3577eSopenharmony_ci    auto ret = AccountDelegate::GetInstance()->QueryUsers(users);
12453c3577eSopenharmony_ci    if (!ret || users.empty()) {
12553c3577eSopenharmony_ci        ZLOGE("failed to query os accounts, ret:%{public}d", ret);
12653c3577eSopenharmony_ci        return false;
12753c3577eSopenharmony_ci    }
12853c3577eSopenharmony_ci    std::vector<UserStatus> userStatus = { { 0, true } };
12953c3577eSopenharmony_ci    for (const auto &user : users) {
13053c3577eSopenharmony_ci        userStatus.emplace_back(user, true);
13153c3577eSopenharmony_ci    }
13253c3577eSopenharmony_ci    UserMetaData userMetaData;
13353c3577eSopenharmony_ci    userMetaData.deviceId = GetLocalDeviceId();
13453c3577eSopenharmony_ci    UpdateUsers(userMetaData.deviceId, userStatus);
13553c3577eSopenharmony_ci    deviceUser_.ComputeIfPresent(userMetaData.deviceId, [&userMetaData](const auto &, std::map<int, bool> &users) {
13653c3577eSopenharmony_ci        for (const auto &[key, value] : users) {
13753c3577eSopenharmony_ci            userMetaData.users.emplace_back(key, value);
13853c3577eSopenharmony_ci        }
13953c3577eSopenharmony_ci        return true;
14053c3577eSopenharmony_ci    });
14153c3577eSopenharmony_ci    ZLOGI("put user meta data save meta data");
14253c3577eSopenharmony_ci    return MetaDataManager::GetInstance().SaveMeta(UserMetaRow::GetKeyFor(userMetaData.deviceId), userMetaData);
14353c3577eSopenharmony_ci}
14453c3577eSopenharmony_ci
14553c3577eSopenharmony_ciUserDelegate &UserDelegate::GetInstance()
14653c3577eSopenharmony_ci{
14753c3577eSopenharmony_ci    static UserDelegate instance;
14853c3577eSopenharmony_ci    return instance;
14953c3577eSopenharmony_ci}
15053c3577eSopenharmony_ci
15153c3577eSopenharmony_civoid UserDelegate::Init(const std::shared_ptr<ExecutorPool> &executors)
15253c3577eSopenharmony_ci{
15353c3577eSopenharmony_ci    auto ret = AccountDelegate::GetInstance()->Subscribe(std::make_shared<LocalUserObserver>(*this));
15453c3577eSopenharmony_ci    MetaDataManager::GetInstance().Subscribe(
15553c3577eSopenharmony_ci        UserMetaRow::KEY_PREFIX, [this](const std::string &key, const std::string &value, int32_t flag) -> auto {
15653c3577eSopenharmony_ci            UserMetaData metaData;
15753c3577eSopenharmony_ci            if (value.empty()) {
15853c3577eSopenharmony_ci                MetaDataManager::GetInstance().LoadMeta(key, metaData);
15953c3577eSopenharmony_ci            } else {
16053c3577eSopenharmony_ci                UserMetaData::Unmarshall(value, metaData);
16153c3577eSopenharmony_ci            }
16253c3577eSopenharmony_ci            ZLOGD("flag:%{public}d, value:%{public}s", flag, Anonymous::Change(metaData.deviceId).c_str());
16353c3577eSopenharmony_ci            if (metaData.deviceId == GetLocalDeviceId()) {
16453c3577eSopenharmony_ci                ZLOGD("ignore local device user meta change");
16553c3577eSopenharmony_ci                return false;
16653c3577eSopenharmony_ci            }
16753c3577eSopenharmony_ci            if (flag == MetaDataManager::INSERT || flag == MetaDataManager::UPDATE) {
16853c3577eSopenharmony_ci                UpdateUsers(metaData.deviceId, metaData.users);
16953c3577eSopenharmony_ci            } else if (flag == MetaDataManager::DELETE) {
17053c3577eSopenharmony_ci                DeleteUsers(metaData.deviceId);
17153c3577eSopenharmony_ci            } else {
17253c3577eSopenharmony_ci                ZLOGD("ignored operation");
17353c3577eSopenharmony_ci            }
17453c3577eSopenharmony_ci            return true;
17553c3577eSopenharmony_ci        });
17653c3577eSopenharmony_ci    if (!executors_) {
17753c3577eSopenharmony_ci        executors_ = executors;
17853c3577eSopenharmony_ci    }
17953c3577eSopenharmony_ci    executors_->Execute(GeTask());
18053c3577eSopenharmony_ci    ZLOGD("subscribe os account ret:%{public}d", ret);
18153c3577eSopenharmony_ci}
18253c3577eSopenharmony_ci
18353c3577eSopenharmony_ciExecutorPool::Task UserDelegate::GeTask()
18453c3577eSopenharmony_ci{
18553c3577eSopenharmony_ci    return [this] {
18653c3577eSopenharmony_ci        auto ret = InitLocalUserMeta();
18753c3577eSopenharmony_ci        if (ret) {
18853c3577eSopenharmony_ci            return;
18953c3577eSopenharmony_ci        }
19053c3577eSopenharmony_ci        executors_->Schedule(std::chrono::milliseconds(RETRY_INTERVAL), GeTask());
19153c3577eSopenharmony_ci    };
19253c3577eSopenharmony_ci}
19353c3577eSopenharmony_ci
19453c3577eSopenharmony_cibool UserDelegate::NotifyUserEvent(const UserDelegate::UserEvent &userEvent)
19553c3577eSopenharmony_ci{
19653c3577eSopenharmony_ci    // update all local user status
19753c3577eSopenharmony_ci    (void)userEvent;
19853c3577eSopenharmony_ci    return InitLocalUserMeta();
19953c3577eSopenharmony_ci}
20053c3577eSopenharmony_ci
20153c3577eSopenharmony_ciUserDelegate::LocalUserObserver::LocalUserObserver(UserDelegate &userDelegate) : userDelegate_(userDelegate) {}
20253c3577eSopenharmony_ci
20353c3577eSopenharmony_civoid UserDelegate::LocalUserObserver::OnAccountChanged(const DistributedKv::AccountEventInfo &eventInfo)
20453c3577eSopenharmony_ci{
20553c3577eSopenharmony_ci    ZLOGI("event info:%{public}s, %{public}d", eventInfo.userId.c_str(), eventInfo.status);
20653c3577eSopenharmony_ci    userDelegate_.NotifyUserEvent({}); // just notify
20753c3577eSopenharmony_ci}
20853c3577eSopenharmony_ci
20953c3577eSopenharmony_cistd::string UserDelegate::LocalUserObserver::Name()
21053c3577eSopenharmony_ci{
21153c3577eSopenharmony_ci    return "user_delegate";
21253c3577eSopenharmony_ci}
21353c3577eSopenharmony_ci} // namespace OHOS::DistributedData