blob: 519f2b2b5d4b495a48fabc5d5295eef4c143d850 [file] [log] [blame]
// Copyright 2016 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.
#ifndef COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_MODEL_IMPL_H_
#define COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_MODEL_IMPL_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/offline_pages/offline_page_archiver.h"
#include "components/offline_pages/offline_page_metadata_store.h"
#include "components/offline_pages/offline_page_model.h"
#include "components/offline_pages/offline_page_model_event_logger.h"
#include "components/offline_pages/offline_page_storage_manager.h"
#include "components/offline_pages/offline_page_types.h"
#include "components/offline_pages/offline_store_types.h"
class GURL;
namespace base {
class Clock;
class SequencedTaskRunner;
class TimeDelta;
class TimeTicks;
} // namespace base
namespace offline_pages {
static const int64_t kInvalidOfflineId = 0;
struct ClientId;
struct OfflinePageItem;
class ArchiveManager;
class ClientPolicyController;
class OfflinePageStorageManager;
// Implementation of service for saving pages offline, storing the offline
// copy and metadata, and retrieving them upon request.
class OfflinePageModelImpl : public OfflinePageModel, public KeyedService {
public:
// All blocking calls/disk access will happen on the provided |task_runner|.
OfflinePageModelImpl(
std::unique_ptr<OfflinePageMetadataStore> store,
const base::FilePath& archives_dir,
const scoped_refptr<base::SequencedTaskRunner>& task_runner);
~OfflinePageModelImpl() override;
// Implemented methods:
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
void SavePage(const GURL& url,
const ClientId& client_id,
int64_t proposed_offline_id,
std::unique_ptr<OfflinePageArchiver> archiver,
const SavePageCallback& callback) override;
void MarkPageAccessed(int64_t offline_id) override;
void DeletePagesByOfflineId(const std::vector<int64_t>& offline_ids,
const DeletePageCallback& callback) override;
void DeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
const DeletePageCallback& callback) override;
void CheckPagesExistOffline(
const std::set<GURL>& urls,
const CheckPagesExistOfflineCallback& callback) override;
void GetAllPages(const MultipleOfflinePageItemCallback& callback) override;
void GetAllPagesWithExpired(
const MultipleOfflinePageItemCallback& callback) override;
void GetOfflineIdsForClientId(
const ClientId& client_id,
const MultipleOfflineIdCallback& callback) override;
const std::vector<int64_t> MaybeGetOfflineIdsForClientId(
const ClientId& client_id) const override;
void GetPageByOfflineId(
int64_t offline_id,
const SingleOfflinePageItemCallback& callback) override;
const OfflinePageItem* MaybeGetPageByOfflineId(
int64_t offline_id) const override;
void GetPageByOfflineURL(
const GURL& offline_url,
const SingleOfflinePageItemCallback& callback) override;
const OfflinePageItem* MaybeGetPageByOfflineURL(
const GURL& offline_url) const override;
void GetPagesByOnlineURL(
const GURL& online_url,
const MultipleOfflinePageItemCallback& callback) override;
const OfflinePageItem* MaybeGetBestPageForOnlineURL(
const GURL& online_url) const override;
void ExpirePages(const std::vector<int64_t>& offline_ids,
const base::Time& expiration_time,
const base::Callback<void(bool)>& callback) override;
ClientPolicyController* GetPolicyController() override;
// Methods for testing only:
OfflinePageMetadataStore* GetStoreForTesting();
void set_testing_clock(base::Clock* clock) { testing_clock_ = clock; }
OfflinePageStorageManager* GetStorageManager();
bool is_loaded() const override;
OfflineEventLogger* GetLogger() override;
protected:
// Adding a protected constructor for testing-only purposes in
// offline_page_storage_manager_unittest.cc
OfflinePageModelImpl();
private:
FRIEND_TEST_ALL_PREFIXES(OfflinePageModelImplTest, MarkPageForDeletion);
enum class GetAllPageMode {
ALL, // Get all active page entries.
ALL_WITH_EXPIRED, // Get all pages entries including expired ones.
};
typedef ScopedVector<OfflinePageArchiver> PendingArchivers;
// Callback for ensuring archive directory is created.
void OnEnsureArchivesDirCreatedDone(const base::TimeTicks& start_time);
void GetAllPagesAfterLoadDone(
GetAllPageMode mode,
const MultipleOfflinePageItemCallback& callback) const;
void CheckPagesExistOfflineAfterLoadDone(
const std::set<GURL>& urls,
const CheckPagesExistOfflineCallback& callback);
void GetOfflineIdsForClientIdWhenLoadDone(
const ClientId& client_id,
const MultipleOfflineIdCallback& callback) const;
void GetPageByOfflineIdWhenLoadDone(
int64_t offline_id,
const SingleOfflinePageItemCallback& callback) const;
void GetPagesByOnlineURLWhenLoadDone(
const GURL& offline_url,
const MultipleOfflinePageItemCallback& callback) const;
void GetPageByOfflineURLWhenLoadDone(
const GURL& offline_url,
const SingleOfflinePageItemCallback& callback) const;
void MarkPageAccessedWhenLoadDone(int64_t offline_id);
void CheckMetadataConsistency();
// Callback for loading pages from the offline page metadata store.
void OnLoadDone(const base::TimeTicks& start_time,
OfflinePageMetadataStore::LoadStatus load_status,
const std::vector<OfflinePageItem>& offline_pages);
// Steps for saving a page offline.
void OnCreateArchiveDone(const GURL& requested_url,
int64_t offline_id,
const ClientId& client_id,
const base::Time& start_time,
const SavePageCallback& callback,
OfflinePageArchiver* archiver,
OfflinePageArchiver::ArchiverResult result,
const GURL& url,
const base::FilePath& file_path,
const base::string16& title,
int64_t file_size);
void OnAddOfflinePageDone(OfflinePageArchiver* archiver,
const SavePageCallback& callback,
const OfflinePageItem& offline_page,
ItemActionStatus status);
void InformSavePageDone(const SavePageCallback& callback,
SavePageResult result,
const ClientId& client_id,
int64_t offline_id);
void DeletePendingArchiver(OfflinePageArchiver* archiver);
// Steps for deleting files and data for an offline page.
void OnDeleteArchiveFilesDone(const std::vector<int64_t>& offline_ids,
const DeletePageCallback& callback,
bool success);
void OnRemoveOfflinePagesDone(
const DeletePageCallback& callback,
std::unique_ptr<OfflinePagesUpdateResult> result);
void InformDeletePageDone(const DeletePageCallback& callback,
DeletePageResult result);
void OnMarkPageAccesseDone(const OfflinePageItem& offline_page_item,
std::unique_ptr<OfflinePagesUpdateResult> result);
// Callbacks for checking metadata consistency.
void CheckMetadataConsistencyForArchivePaths(
const std::set<base::FilePath>& archive_paths);
// Callback called after headless archives deleted. Orphaned archives are
// archives files on disk which are not pointed to by any of the page items
// in metadata store.
void ExpirePagesMissingArchiveFile(
const std::set<base::FilePath>& archive_paths);
void OnExpirePagesMissingArchiveFileDone(
const std::vector<int64_t>& offline_ids,
bool success);
void DeleteOrphanedArchives(const std::set<base::FilePath>& archive_paths);
void OnDeleteOrphanedArchivesDone(const std::vector<base::FilePath>& archives,
bool success);
// Callbacks for deleting pages with same URL when saving pages.
void DeleteExistingPagesWithSameURL(const OfflinePageItem& offline_page);
void OnPagesFoundWithSameURL(const OfflinePageItem& offline_page,
size_t pages_allowed,
const MultipleOfflinePageItemResult& items);
void OnDeleteOldPagesWithSameURL(DeletePageResult result);
void CacheLoadedData(const std::vector<OfflinePageItem>& offline_pages);
// Actually does the work of deleting, requires the model is loaded.
void DoDeletePagesByOfflineId(const std::vector<int64_t>& offline_ids,
const DeletePageCallback& callback);
// Similar to DoDeletePagesByOfflineId, does actual work of deleting, and
// requires that the model is loaded.
void DoDeleteCachedPagesByURLPredicate(const UrlPredicate& predicate,
const DeletePageCallback& callback);
// Callback completing page expiration.
void OnExpirePageDone(const base::Time& expiration_time,
std::unique_ptr<OfflinePagesUpdateResult> result);
// Clears expired pages if there are any.
void ClearStorageIfNeeded(
const OfflinePageStorageManager::ClearStorageCallback& callback);
// Callback completing storage clearing.
void OnStorageCleared(size_t expired_page_count,
OfflinePageStorageManager::ClearStorageResult result);
// Post task to clear storage.
void PostClearStorageIfNeededTask();
// Check if |offline_page| is user-requested.
bool IsUserRequestedPage(const OfflinePageItem& offline_page) const;
void RunWhenLoaded(const base::Closure& job);
base::Time GetCurrentTime() const;
// Persistent store for offline page metadata.
std::unique_ptr<OfflinePageMetadataStore> store_;
// Location where all of the archive files will be stored.
base::FilePath archives_dir_;
// The observers.
base::ObserverList<Observer> observers_;
bool is_loaded_;
// In memory copy of the offline page metadata, keyed by offline IDs.
std::map<int64_t, OfflinePageItem> offline_pages_;
// Pending archivers owned by this model.
PendingArchivers pending_archivers_;
// Delayed tasks that should be invoked after the loading is done.
std::vector<base::Closure> delayed_tasks_;
// Controller of the client policies.
std::unique_ptr<ClientPolicyController> policy_controller_;
// Manager for the storage consumed by archives and responsible for
// automatic page clearing.
std::unique_ptr<OfflinePageStorageManager> storage_manager_;
// Manager for the offline archive files and directory.
std::unique_ptr<ArchiveManager> archive_manager_;
// Logger to facilitate recording of events.
OfflinePageModelEventLogger offline_event_logger_;
// Clock for getting time in testing code. The setter is responsible to reset
// it once it is not longer needed.
base::Clock* testing_clock_;
base::WeakPtrFactory<OfflinePageModelImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(OfflinePageModelImpl);
};
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_MODEL_IMPL_H_