blob: 5737275695979fffad462cb41fd2e34ee3732370 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <algorithm>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_items_collection/core/offline_content_aggregator.h"
#include "components/offline_items_collection/core/offline_item.h"
namespace offline_items_collection {
namespace {
template <typename T, typename U>
bool MapContainsValue(const std::map<T, U>& map, U value) {
for (const auto& it : map) {
if (it.second == value)
return true;
}
return false;
}
} // namespace
OfflineContentAggregator::OfflineContentAggregator()
: weak_ptr_factory_(this) {}
OfflineContentAggregator::~OfflineContentAggregator() = default;
std::string OfflineContentAggregator::CreateUniqueNameSpace(
const std::string& prefix,
bool is_off_the_record) {
if (!is_off_the_record)
return prefix;
static int num_registrations = 0;
return prefix + "_" + base::NumberToString(++num_registrations);
}
void OfflineContentAggregator::RegisterProvider(
const std::string& name_space,
OfflineContentProvider* provider) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Validate that this is the first OfflineContentProvider registered that is
// associated with |name_space|.
DCHECK(providers_.find(name_space) == providers_.end());
// Only set up the connection to the provider if the provider isn't associated
// with any other namespace.
if (!MapContainsValue(providers_, provider))
provider->AddObserver(this);
providers_[name_space] = provider;
}
void OfflineContentAggregator::UnregisterProvider(
const std::string& name_space) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto provider_it = providers_.find(name_space);
OfflineContentProvider* provider = provider_it->second;
providers_.erase(provider_it);
pending_providers_.erase(provider);
// Only clean up the connection to the provider if the provider isn't
// associated with any other namespace.
if (!MapContainsValue(providers_, provider)) {
provider->RemoveObserver(this);
}
}
void OfflineContentAggregator::OpenItem(LaunchLocation location,
const ContentId& id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = providers_.find(id.name_space);
if (it == providers_.end())
return;
it->second->OpenItem(location, id);
}
void OfflineContentAggregator::RemoveItem(const ContentId& id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = providers_.find(id.name_space);
if (it == providers_.end())
return;
it->second->RemoveItem(id);
}
void OfflineContentAggregator::CancelDownload(const ContentId& id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = providers_.find(id.name_space);
if (it == providers_.end())
return;
it->second->CancelDownload(id);
}
void OfflineContentAggregator::PauseDownload(const ContentId& id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = providers_.find(id.name_space);
if (it == providers_.end())
return;
it->second->PauseDownload(id);
}
void OfflineContentAggregator::ResumeDownload(const ContentId& id,
bool has_user_gesture) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = providers_.find(id.name_space);
if (it == providers_.end())
return;
it->second->ResumeDownload(id, has_user_gesture);
}
void OfflineContentAggregator::GetItemById(const ContentId& id,
SingleItemCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = providers_.find(id.name_space);
if (it == providers_.end()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), base::nullopt));
return;
}
it->second->GetItemById(
id, base::BindOnce(&OfflineContentAggregator::OnGetItemByIdDone,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void OfflineContentAggregator::OnGetItemByIdDone(
SingleItemCallback callback,
const base::Optional<OfflineItem>& item) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::move(callback).Run(item);
}
void OfflineContentAggregator::GetAllItems(MultipleItemCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// If there is already a call in progress, queue up the callback and wait for
// the results.
if (!multiple_item_get_callbacks_.empty()) {
multiple_item_get_callbacks_.push_back(std::move(callback));
return;
}
DCHECK(aggregated_items_.empty());
for (auto provider_it : providers_) {
auto* provider = provider_it.second;
provider->GetAllItems(
base::BindOnce(&OfflineContentAggregator::OnGetAllItemsDone,
weak_ptr_factory_.GetWeakPtr(), provider));
pending_providers_.insert(provider);
}
if (pending_providers_.empty()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), OfflineItemList()));
return;
}
multiple_item_get_callbacks_.push_back(std::move(callback));
}
void OfflineContentAggregator::OnGetAllItemsDone(
OfflineContentProvider* provider,
const OfflineItemList& items) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
aggregated_items_.insert(aggregated_items_.end(), items.begin(), items.end());
pending_providers_.erase(provider);
if (!pending_providers_.empty()) {
return;
}
auto item_vec = std::move(aggregated_items_);
auto callbacks = std::move(multiple_item_get_callbacks_);
for (auto& callback : callbacks)
std::move(callback).Run(item_vec);
}
void OfflineContentAggregator::GetVisualsForItem(const ContentId& id,
VisualsCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = providers_.find(id.name_space);
if (it == providers_.end()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), id, nullptr));
return;
}
it->second->GetVisualsForItem(id, std::move(callback));
}
void OfflineContentAggregator::GetShareInfoForItem(const ContentId& id,
ShareCallback callback) {
auto it = providers_.find(id.name_space);
if (it == providers_.end()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), id, nullptr));
return;
}
it->second->GetShareInfoForItem(id, std::move(callback));
}
void OfflineContentAggregator::RenameItem(const ContentId& id,
const std::string& name,
RenameCallback callback) {
auto it = providers_.find(id.name_space);
if (it == providers_.end()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), RenameResult::FAILURE_UNAVAILABLE));
return;
}
it->second->RenameItem(id, name, std::move(callback));
}
void OfflineContentAggregator::AddObserver(
OfflineContentProvider::Observer* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(observer);
if (observers_.HasObserver(observer))
return;
observers_.AddObserver(observer);
}
void OfflineContentAggregator::RemoveObserver(
OfflineContentProvider::Observer* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(observer);
if (!observers_.HasObserver(observer))
return;
observers_.RemoveObserver(observer);
}
void OfflineContentAggregator::OnItemsAdded(const OfflineItemList& items) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto& observer : observers_)
observer.OnItemsAdded(items);
}
void OfflineContentAggregator::OnItemRemoved(const ContentId& id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto& observer : observers_)
observer.OnItemRemoved(id);
}
void OfflineContentAggregator::OnItemUpdated(const OfflineItem& item) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto& observer : observers_)
observer.OnItemUpdated(item);
}
} // namespace offline_items_collection