blob: c72a1ccfd17c3f74d7170107cc8c9d514323dd0f [file] [log] [blame]
// Copyright 2018 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_FEED_CONTENT_FEED_OFFLINE_HOST_H_
#define COMPONENTS_FEED_CONTENT_FEED_OFFLINE_HOST_H_
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "components/feed/core/content_metadata.h"
#include "components/offline_pages/core/offline_page_model.h"
#include "components/offline_pages/core/prefetch/suggestions_provider.h"
class GURL;
namespace offline_pages {
class PrefetchService;
} // namespace offline_pages
namespace feed {
// Responsible for wiring up connections for Feed operations pertaining to
// articles that can be loaded from Offline Pages component. Most significantly
// this class connects Prefetch and the Feed, and tracks offlined articles the
// Feed may have badged for this user. This knowledge is later used when Feed
// articles are opened to populate load params.
class FeedOfflineHost : public offline_pages::SuggestionsProvider,
public offline_pages::OfflinePageModel::Observer {
public:
using GetKnownContentCallback =
base::OnceCallback<void(std::vector<ContentMetadata>)>;
using NotifyStatusChangeCallback =
base::RepeatingCallback<void(const std::string&, bool)>;
FeedOfflineHost(offline_pages::OfflinePageModel* offline_page_model,
offline_pages::PrefetchService* prefetch_service,
base::RepeatingClosure on_suggestion_consumed,
base::RepeatingClosure on_suggestions_shown);
~FeedOfflineHost() override;
// Initialize with callbacks to call into bridge/Java side. Should only be
// called once, and done as soon as the bridge is ready. The FeedOfflineHost
// will not be fully ready to perform its function without these dependencies.
// Neither of these callbacks will be invoked until after this method exits.
void Initialize(const base::RepeatingClosure& trigger_get_known_content,
const NotifyStatusChangeCallback& notify_status_change);
// Called during initialization make ourselves known to |prefetch_service_|.
// This method is used to wrap PrefetchService::SetSuggestionProvider() to let
// our weak pointer guarantee everyone is still alive.
void SetSuggestionProvider();
// Synchronously returns the offline id of the given page. The host will only
// have knowledge of the page if it had previously returned status about it
// through GetOfflineState() or as a notification. Otherwise the caller will
// receive a false negative. Additionally, since the host tracks pages by
// hashing, there's also a small chance that the host erroneously returns an
// id for a page that is not offlined.
base::Optional<int64_t> GetOfflineId(const std::string& url);
// Asynchronously fetches offline status for the given URLs. Any pages that
// are currently offlined will be remembered by the FeedOfflineHost.
void GetOfflineStatus(
std::vector<std::string> urls,
base::OnceCallback<void(std::vector<std::string>)> callback);
// Should be called from Feed any time the user manually removes articles or
// groupings of articles. Propagates the signal to Prefetch.
void OnContentRemoved(std::vector<std::string> urls);
// Should be called from Feed any time new articles are fetched.
void OnNewContentReceived();
// Should be called from Feed side any time there are no active surfaces
// displaying articles and listening to our notifications. This signal is used
// to clear local tracking of offlined items.
void OnNoListeners();
// Should be called when async GetKnownContent is completed. Broadcasts to all
// waiting consumers in |pending_known_content_callbacks_|.
void OnGetKnownContentDone(std::vector<ContentMetadata> suggestions);
// offline_pages::SuggestionsProvider:
void GetCurrentArticleSuggestions(
offline_pages::SuggestionsProvider::SuggestionCallback
suggestions_callback) override;
void ReportArticleListViewed() override;
void ReportArticleViewed(GURL article_url) override;
// offline_pages::OfflinePageModel::Observer:
void OfflinePageModelLoaded(offline_pages::OfflinePageModel* model) override;
void OfflinePageAdded(
offline_pages::OfflinePageModel* model,
const offline_pages::OfflinePageItem& added_page) override;
void OfflinePageDeleted(
const offline_pages::OfflinePageModel::DeletedPageInfo& page_info)
override;
private:
// Stores the given record in |url_hash_to_id_|. If there's a conflict, the
// new id will overwrite the old value.
void CacheOfflinePageUrlAndId(const std::string& url, int64_t id);
// Removes a previously cached |id| for the given |url| if there was one.
void EvictOfflinePageUrl(const std::string& url);
// The following objects all outlive us, so it is safe to hold raw pointers to
// them. This is guaranteed by the FeedHostServiceFactory.
offline_pages::OfflinePageModel* offline_page_model_;
offline_pages::PrefetchService* prefetch_service_;
base::RepeatingClosure on_suggestion_consumed_;
base::RepeatingClosure on_suggestions_shown_;
// Only offlined pages that have passed through the host are stored. If there
// are ever no listeners to the offline host logic and OnNoListeners() is
// called this map is cleared. The key is the hash of the url, and the value
// is the offline id for the given page.
base::flat_map<uint32_t, int64_t> url_hash_to_id_;
// Starts an the async request for ContentMetadata through KnownContentApi's
// GetKnownContent(). Will only be invoked when there isn't already an
// outstanding GetKnownContent().
base::RepeatingClosure trigger_get_known_content_;
// Holds all consumers of GetKnownContent(). It is assumed that there's an
// outstanding GetKnownContent() if and only if this vector is not empty.
std::vector<GetKnownContentCallback> pending_known_content_callbacks_;
// Calls all OfflineStatusListeners with the updated status.
NotifyStatusChangeCallback notify_status_change_;
base::WeakPtrFactory<FeedOfflineHost> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FeedOfflineHost);
};
} // namespace feed
#endif // COMPONENTS_FEED_CONTENT_FEED_OFFLINE_HOST_H_