Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(119)

Unified Diff: components/ntp_snippets/remote/remote_suggestions_provider.h

Issue 2557363002: [NTP Snippets] Refactor background scheduling for remote suggestions (Closed)
Patch Set: Fixing the last changes :) Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/ntp_snippets/remote/remote_suggestions_provider.h
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider.h b/components/ntp_snippets/remote/remote_suggestions_provider.h
index e743b42951a75c8322bf0bcf98ac7a4fd16d3fbb..8b818b5fb6a383f3a9cf318590e249706e8bda37 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider.h
+++ b/components/ntp_snippets/remote/remote_suggestions_provider.h
@@ -5,448 +5,56 @@
#ifndef COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_PROVIDER_H_
#define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_PROVIDER_H_
-#include <cstddef>
-#include <deque>
-#include <map>
#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
#include "base/callback_forward.h"
-#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/time/clock.h"
-#include "base/time/time.h"
-#include "components/image_fetcher/image_fetcher_delegate.h"
-#include "components/ntp_snippets/category.h"
-#include "components/ntp_snippets/category_status.h"
-#include "components/ntp_snippets/content_suggestion.h"
#include "components/ntp_snippets/content_suggestions_provider.h"
-#include "components/ntp_snippets/remote/ntp_snippet.h"
-#include "components/ntp_snippets/remote/ntp_snippets_fetcher.h"
-#include "components/ntp_snippets/remote/ntp_snippets_request_params.h"
-#include "components/ntp_snippets/remote/ntp_snippets_scheduler.h"
-#include "components/ntp_snippets/remote/remote_suggestions_status_service.h"
-#include "components/ntp_snippets/remote/request_throttler.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-namespace gfx {
-class Image;
-} // namespace gfx
-
-namespace image_fetcher {
-class ImageDecoder;
-class ImageFetcher;
-} // namespace image_fetcher
namespace ntp_snippets {
-class RemoteSuggestionsDatabase;
-class CategoryRanker;
-class UserClassifier;
-
-// CachedImageFetcher takes care of fetching images from the network and caching
-// them in the database.
-// TODO(tschumann): Move into a separate library and inject the
-// CachedImageFetcher into the RemoteSuggestionsProvider. This allows us to get
-// rid of exposing this member for testing and lets us test the caching logic
-// separately.
-class CachedImageFetcher : public image_fetcher::ImageFetcherDelegate {
- public:
- // |pref_service| and |database| need to outlive the created image fetcher
- // instance.
- CachedImageFetcher(std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
- PrefService* pref_service,
- RemoteSuggestionsDatabase* database);
- ~CachedImageFetcher() override;
-
- // Fetches the image for a suggestion. The fetcher will first issue a lookup
- // to the underlying cache with a fallback to the network.
- void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const GURL& image_url,
- const ImageFetchedCallback& callback);
-
- private:
- // image_fetcher::ImageFetcherDelegate implementation.
- void OnImageDataFetched(const std::string& id_within_category,
- const std::string& image_data) override;
- void OnImageDecodingDone(const ImageFetchedCallback& callback,
- const std::string& id_within_category,
- const gfx::Image& image);
- void OnSnippetImageFetchedFromDatabase(
- const ImageFetchedCallback& callback,
- const ContentSuggestion::ID& suggestion_id,
- const GURL& image_url,
- // SnippetImageCallback requires nonconst reference
- std::string data);
- void OnSnippetImageDecodedFromDatabase(
- const ImageFetchedCallback& callback,
- const ContentSuggestion::ID& suggestion_id,
- const GURL& url,
- const gfx::Image& image);
- void FetchSnippetImageFromNetwork(const ContentSuggestion::ID& suggestion_id,
- const GURL& url,
- const ImageFetchedCallback& callback);
-
- std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder_;
- RemoteSuggestionsDatabase* database_;
- // Request throttler for limiting requests to thumbnail images.
- RequestThrottler thumbnail_requests_throttler_;
-
- DISALLOW_COPY_AND_ASSIGN(CachedImageFetcher);
-};
+class NTPSnippetsFetcher;
// Retrieves fresh content data (articles) from the server, stores them and
// provides them as content suggestions.
-// This class is final because it does things in its constructor which make it
-// unsafe to derive from it.
-// TODO(treib): Introduce two-phase initialization and make the class not final?
-class RemoteSuggestionsProvider final : public ContentSuggestionsProvider {
+class RemoteSuggestionsProvider : public ContentSuggestionsProvider {
public:
- // |application_language_code| should be a ISO 639-1 compliant string, e.g.
- // 'en' or 'en-US'. Note that this code should only specify the language, not
- // the locale, so 'en_US' (English language with US locale) and 'en-GB_US'
- // (British English person in the US) are not language codes.
- RemoteSuggestionsProvider(
- Observer* observer,
- PrefService* pref_service,
- const std::string& application_language_code,
- CategoryRanker* category_ranker,
- const UserClassifier* user_classifier,
- NTPSnippetsScheduler* scheduler,
- std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
- std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
- std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
- std::unique_ptr<RemoteSuggestionsDatabase> database,
- std::unique_ptr<RemoteSuggestionsStatusService> status_service);
+ // TODO(jkrcal): Would be nice to get rid of this another level of statuses.
+ // Maybe possible while refactoring the RemoteSuggestionsStatusService? (and
+ // letting it notify both the SchedulingRemoteSuggestionsProvider and
+ // RemoteSuggestionsProviderImpl or just the scheduling one).
+ enum class ProviderStatus { ACTIVE, INACTIVE };
+ using ProviderStatusCallback =
+ base::RepeatingCallback<void(ProviderStatus status)>;
+
+ // Callback to notify with the result of a fetch.
+ // TODO(jkrcal): Change to OnceCallback? A OnceCallback does only have a
+ // move-constructor which seems problematic for google mock.
+ using FetchStatusCallback = base::Callback<void(Status status_code)>;
~RemoteSuggestionsProvider() override;
- static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
- // Returns whether the service is ready. While this is false, the list of
- // snippets will be empty, and all modifications to it (fetch, dismiss, etc)
- // will be ignored.
- bool ready() const { return state_ == State::READY; }
-
- // Returns whether the service is initialized. While this is false, some
- // calls may trigger DCHECKs.
- bool initialized() const { return ready() || state_ == State::DISABLED; }
-
- // Fetchs content suggestions from the Content Suggestions server for all
- // remote categories in the background.
- void FetchSnippetsInTheBackground();
-
- // Fetchs content suggestions from the Content Suggestions server for all
- // remote categories. The request to the server is performed as an interactive
- // request. Interactive requests are used for actions triggered by the user
- // and request lower latency processing.
- void FetchSnippetsForAllCategories();
-
- // Only used in tests and for debugging in snippets-internal/.
- // TODO(fhorschig): Remove this getter when there is an interface for the
- // fetcher that allows better mocks.
- const NTPSnippetsFetcher* snippets_fetcher() const {
- return snippets_fetcher_.get();
- }
-
- // (Re)schedules the periodic fetching of snippets. If |force| is true, the
- // tasks will be re-scheduled even if they already exist and have the correct
- // periods.
- void RescheduleFetching(bool force);
-
- // ContentSuggestionsProvider implementation
- CategoryStatus GetCategoryStatus(Category category) override;
- CategoryInfo GetCategoryInfo(Category category) override;
- void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
- void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- const ImageFetchedCallback& callback) override;
- void Fetch(const Category& category,
- const std::set<std::string>& known_suggestion_ids,
- const FetchDoneCallback& callback) override;
- void ClearHistory(
- base::Time begin,
- base::Time end,
- const base::Callback<bool(const GURL& url)>& filter) override;
- void ClearCachedSuggestions(Category category) override;
- void OnSignInStateChanged() override;
- void GetDismissedSuggestionsForDebugging(
- Category category,
- const DismissedSuggestionsCallback& callback) override;
- void ClearDismissedSuggestionsForDebugging(Category category) override;
-
- // Returns the maximum number of snippets that will be shown at once.
- static int GetMaxSnippetCountForTesting();
-
- // Available snippets, only for unit tests.
- // TODO(treib): Get rid of this. Tests should use a fake observer instead.
- const NTPSnippet::PtrVector& GetSnippetsForTesting(Category category) const {
- return category_contents_.find(category)->second.snippets;
- }
-
- // Dismissed snippets, only for unit tests.
- const NTPSnippet::PtrVector& GetDismissedSnippetsForTesting(
- Category category) const {
- return category_contents_.find(category)->second.dismissed;
- }
-
- // Overrides internal clock for testing purposes.
- void SetClockForTesting(std::unique_ptr<base::Clock> clock) {
- clock_ = std::move(clock);
- }
-
- // TODO(tschumann): remove this method as soon as we inject the fetcher into
- // the constructor.
- CachedImageFetcher& GetImageFetcherForTesting() { return image_fetcher_; }
-
- private:
- friend class RemoteSuggestionsProviderTest;
-
- FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsProviderTest,
- DontNotifyIfNotAvailable);
- FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsProviderTest,
- RemoveExpiredDismissedContent);
- FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsProviderTest,
- RescheduleOnStateChange);
- FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsProviderTest, StatusChanges);
- FRIEND_TEST_ALL_PREFIXES(RemoteSuggestionsProviderTest,
- SuggestionsFetchedOnSignInAndSignOut);
-
- // Possible state transitions:
- // NOT_INITED --------+
- // / \ |
- // v v |
- // READY <--> DISABLED |
- // \ / |
- // v v |
- // ERROR_OCCURRED <-----+
- enum class State {
- // The service has just been created. Can change to states:
- // - DISABLED: After the database is done loading,
- // GetStateForDependenciesStatus can identify the next state to
- // be DISABLED.
- // - READY: if GetStateForDependenciesStatus returns it, after the database
- // is done loading.
- // - ERROR_OCCURRED: when an unrecoverable error occurred.
- NOT_INITED,
-
- // The service registered observers, timers, etc. and is ready to answer to
- // queries, fetch snippets... Can change to states:
- // - DISABLED: when the global Chrome state changes, for example after
- // |OnStateChanged| is called and sync is disabled.
- // - ERROR_OCCURRED: when an unrecoverable error occurred.
- READY,
-
- // The service is disabled and unregistered the related resources.
- // Can change to states:
- // - READY: when the global Chrome state changes, for example after
- // |OnStateChanged| is called and sync is enabled.
- // - ERROR_OCCURRED: when an unrecoverable error occurred.
- DISABLED,
-
- // The service or one of its dependencies encountered an unrecoverable error
- // and the service can't be used anymore.
- ERROR_OCCURRED,
-
- COUNT
- };
-
- struct CategoryContent {
- // The current status of the category.
- CategoryStatus status = CategoryStatus::INITIALIZING;
-
- // The additional information about a category.
- CategoryInfo info;
-
- // True iff the server returned results in this category in the last fetch.
- // We never remove categories that the server still provides, but if the
- // server stops providing a category, we won't yet report it as NOT_PROVIDED
- // while we still have non-expired snippets in it.
- bool included_in_last_server_response = true;
-
- // All currently active suggestions (excl. the dismissed ones).
- NTPSnippet::PtrVector snippets;
-
- // All previous suggestions that we keep around in memory because they can
- // be on some open NTP. We do not persist this list so that on a new start
- // of Chrome, this is empty.
- // |archived| is a FIFO buffer with a maximum length.
- std::deque<std::unique_ptr<NTPSnippet>> archived;
-
- // Suggestions that the user dismissed. We keep these around until they
- // expire so we won't re-add them to |snippets| on the next fetch.
- NTPSnippet::PtrVector dismissed;
-
- // Returns a non-dismissed snippet with the given |id_within_category|, or
- // null if none exist.
- const NTPSnippet* FindSnippet(const std::string& id_within_category) const;
-
- explicit CategoryContent(const CategoryInfo& info);
- CategoryContent(CategoryContent&&);
- ~CategoryContent();
- CategoryContent& operator=(CategoryContent&&);
- };
-
- // Fetches snippets from the server and replaces old snippets by the new ones.
- // Requests can be marked more important by setting |interactive_request| to
- // true (such request might circumvent the daily quota for requests, etc.)
- // Useful for requests triggered by the user.
- void FetchSnippets(bool interactive_request);
-
- // Returns the URL of the image of a snippet if it is among the current or
- // among the archived snippets in the matching category. Returns an empty URL
- // otherwise.
- GURL FindSnippetImageUrl(const ContentSuggestion::ID& suggestion_id) const;
-
- // Callbacks for the RemoteSuggestionsDatabase.
- void OnDatabaseLoaded(NTPSnippet::PtrVector snippets);
- void OnDatabaseError();
-
- // Callback for fetch-more requests with the NTPSnippetsFetcher.
- void OnFetchMoreFinished(
- const FetchDoneCallback& fetching_callback,
- Status status,
- NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories);
-
- // Callback for regular fetch requests with the NTPSnippetsFetcher.
- void OnFetchFinished(
- bool interactive_request,
- Status status,
- NTPSnippetsFetcher::OptionalFetchedCategories fetched_categories);
-
- // Moves all snippets from |to_archive| into the archive of the |content|.
- // Clears |to_archive|. As the archive is a FIFO buffer of limited size, this
- // function will also delete images from the database in case the associated
- // snippet gets evicted from the archive.
- void ArchiveSnippets(CategoryContent* content,
- NTPSnippet::PtrVector* to_archive);
-
- // Sanitizes newly fetched snippets -- e.g. adding missing dates and filtering
- // out incomplete results or dismissed snippets (indicated by |dismissed|).
- void SanitizeReceivedSnippets(const NTPSnippet::PtrVector& dismissed,
- NTPSnippet::PtrVector* snippets);
-
- // Adds newly available suggestions to |content|.
- void IntegrateSnippets(CategoryContent* content,
- NTPSnippet::PtrVector new_snippets);
-
- // Dismisses a snippet within a given category content.
- // Note that this modifies the snippet datastructures of |content|
- // invalidating iterators.
- void DismissSuggestionFromCategoryContent(
- CategoryContent* content,
- const std::string& id_within_category);
-
- // Removes expired dismissed snippets from the service and the database.
- void ClearExpiredDismissedSnippets();
-
- // Removes images from the DB that are not referenced from any known snippet.
- // Needs to iterate the whole snippet database -- so do it often enough to
- // keep it small but not too often as it still iterates over the file system.
- void ClearOrphanedImages();
-
- // Clears all stored snippets and updates the observer.
- void NukeAllSnippets();
-
- // Completes the initialization phase of the service, registering the last
- // observers. This is done after construction, once the database is loaded.
- void FinishInitialization();
-
- // Triggers a state transition depending on the provided status. This method
- // is called when a change is detected by |status_service_|.
- void OnStatusChanged(RemoteSuggestionsStatus old_status,
- RemoteSuggestionsStatus new_status);
-
- // Verifies state transitions (see |State|'s documentation) and applies them.
- // Also updates the provider status. Does nothing except updating the provider
- // status if called with the current state.
- void EnterState(State state);
-
- // Enables the service. Do not call directly, use |EnterState| instead.
- void EnterStateReady();
-
- // Disables the service. Do not call directly, use |EnterState| instead.
- void EnterStateDisabled();
-
- // Disables the service permanently because an unrecoverable error occurred.
- // Do not call directly, use |EnterState| instead.
- void EnterStateError();
-
- // Converts the cached snippets in the given |category| to content suggestions
- // and notifies the observer.
- void NotifyNewSuggestions(Category category, const CategoryContent& content);
-
- // Updates the internal status for |category| to |category_status_| and
- // notifies the content suggestions observer if it changed.
- void UpdateCategoryStatus(Category category, CategoryStatus status);
- // Calls UpdateCategoryStatus() for all provided categories.
- void UpdateAllCategoryStatus(CategoryStatus status);
-
- // Updates the category info for |category|. If a corresponding
- // CategoryContent object does not exist, it will be created.
- // Returns the existing or newly created object.
- CategoryContent* UpdateCategoryInfo(Category category,
- const CategoryInfo& info);
-
- void RestoreCategoriesFromPrefs();
- void StoreCategoriesToPrefs();
-
- NTPSnippetsRequestParams BuildFetchParams() const;
-
- void MarkEmptyCategoriesAsLoading();
-
- State state_;
-
- PrefService* pref_service_;
-
- const Category articles_category_;
-
- std::map<Category, CategoryContent, Category::CompareByID> category_contents_;
-
- // The ISO 639-1 code of the language used by the application.
- const std::string application_language_code_;
-
- // Ranker that orders the categories. Not owned.
- CategoryRanker* category_ranker_;
-
- // Classifier that tells us how active the user is. Not owned.
- const UserClassifier* user_classifier_;
-
- // Scheduler for fetching snippets. Not owned.
- NTPSnippetsScheduler* scheduler_;
-
- // The snippets fetcher.
- std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher_;
-
- // The database for persisting snippets.
- std::unique_ptr<RemoteSuggestionsDatabase> database_;
- base::TimeTicks database_load_start_;
-
- // The image fetcher.
- CachedImageFetcher image_fetcher_;
-
- // The service that provides events and data about the signin and sync state.
- std::unique_ptr<RemoteSuggestionsStatusService> status_service_;
-
- // Set to true if FetchSnippets is called while the service isn't ready.
- // The fetch will be executed once the service enters the READY state.
- bool fetch_when_ready_;
-
- // Set to true if NukeAllSnippets is called while the service isn't ready.
- // The nuke will be executed once the service finishes initialization or
- // enters the READY state.
- bool nuke_when_initialized_;
-
- // A clock for getting the time. This allows to inject a clock in tests.
- std::unique_ptr<base::Clock> clock_;
-
- DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsProvider);
+ // Set a callback to be notified whenever the status of the provider changes.
+ // The initial change is also notified (switching from an initial undecided
+ // status). If the callback is set after the first change, it is called back
+ // immediately.
+ virtual void SetProviderStatusCallback(
+ std::unique_ptr<ProviderStatusCallback> callback) = 0;
+
+ // Fetches snippets from the server for all remote categories and replaces old
+ // snippets by the new ones. The request to the server is performed as an
+ // background request. Background requests are used for actions not triggered
+ // by the user and have lower priority on the server. After the fetch
+ // finished, the provided |callback| will be triggered with the status of the
+ // fetch (unless not nullptr).
+ virtual void RefetchInTheBackground(
+ std::unique_ptr<FetchStatusCallback> callback) = 0;
+
+ virtual const NTPSnippetsFetcher* snippets_fetcher_for_testing_and_debugging()
+ const = 0;
+
+ protected:
+ RemoteSuggestionsProvider(Observer* observer);
};
} // namespace ntp_snippets

Powered by Google App Engine
This is Rietveld 408576698