blob: 248dcb8d7f91fba405709dae4cb5e2fd4c129c42 [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 "base/memory/weak_ptr.h"
#include "base/time/clock.h"
#include "base/timer/timer.h"
#include "components/gcm_driver/gcm_app_handler.h"
#include "components/gcm_driver/instance_id/instance_id.h"
#include "components/ntp_snippets/breaking_news/breaking_news_listener.h"
#include "components/ntp_snippets/breaking_news/subscription_manager.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
class PrefRegistrySimple;
namespace gcm {
class GCMDriver;
namespace instance_id {
class InstanceIDDriver;
namespace ntp_snippets {
// Handler for pushed GCM breaking news and refresh requests. It retrieves a
// subscription token from the GCM server and registers/unregisters itself with
// the GCM service to be called upon received push breaking news or refresh
// requests. When there is a listener, the token is periodically validated. The
// validation may happen during StartListening if enough time has passed since
// the last validation.
class BreakingNewsGCMAppHandler : public BreakingNewsListener,
public gcm::GCMAppHandler {
// Callbacks for JSON parsing to allow injecting platform-dependent code.
using SuccessCallback =
base::Callback<void(std::unique_ptr<base::Value> result)>;
using ErrorCallback = base::Callback<void(const std::string& error)>;
using ParseJSONCallback =
base::Callback<void(const std::string& raw_json_string,
const SuccessCallback& success_callback,
const ErrorCallback& error_callback)>;
// When provided, |timer_task_runner| and |timer_tick_clock| are used inside
// internal validation timer (e.g. for testing).
gcm::GCMDriver* gcm_driver,
instance_id::InstanceIDDriver* instance_id_driver,
PrefService* pref_service_,
std::unique_ptr<SubscriptionManager> subscription_manager,
const ParseJSONCallback& parse_json_callback,
const base::Clock* clock,
std::unique_ptr<base::OneShotTimer> token_validation_timer,
std::unique_ptr<base::OneShotTimer> forced_subscription_timer);
// If still listening, calls StopListening().
~BreakingNewsGCMAppHandler() override;
// BreakingNewsListener overrides.
void StartListening(
OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback,
OnRefreshRequestedCallback on_refresh_requested_callback) override;
void StopListening() override;
bool IsListening() const override;
// GCMAppHandler overrides.
void ShutdownHandler() override;
void OnStoreReset() override;
void OnMessage(const std::string& app_id,
const gcm::IncomingMessage& message) override;
void OnMessagesDeleted(const std::string& app_id) override;
void OnSendError(const std::string& app_id,
const gcm::GCMClient::SendErrorDetails& details) override;
void OnSendAcknowledged(const std::string& app_id,
const std::string& message_id) override;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
static void ClearProfilePrefs(PrefService* pref_service);
// If there is no subscription token or |force_token_retrieval|, retrieves a
// GCM subscription token and subscribes to content suggestions server with
// it. Otherwise, subscribes to content suggestions server with the existing
// token.
void Subscribe(bool force_token_retrieval);
// Called when a subscription token is obtained from the GCM server.
void DidRetrieveToken(const std::string& subscription_token,
instance_id::InstanceID::Result result);
// Called periodically to validate the subscription token (it is stored on
// disk and may become corrupted) and resubscribe with the new token if the
// old one is invalid.
void ResubscribeIfInvalidToken();
// Called when token obtained from the GCM server for its validation.
void DidReceiveTokenForValidation(const std::string& new_token,
instance_id::InstanceID::Result result);
// If the validation is due, it may be scheduled immediately.
void ScheduleNextTokenValidation();
// Subscribe to content suggestions service using the existing token.
void ForceSubscribe();
// If the subscription is due, it may be scheduled immediately.
void ScheduleNextForcedSubscription();
// Called from OnMessage if the received message is push-by-value message.
void OnPushByValueMessage(const gcm::IncomingMessage& message);
// Called from OnMessage if the received message is push-to-refresh message.
void OnPushToRefreshMessage();
// Called after successfully parsing the received suggestion JSON.
void OnJsonSuccess(std::unique_ptr<base::Value> content);
// Called in case the received suggestion JSON inside the GCM has a parse
// error.
void OnJsonError(const std::string& json_str, const std::string& error);
gcm::GCMDriver* const gcm_driver_;
instance_id::InstanceIDDriver* const instance_id_driver_;
PrefService* const pref_service_;
const std::unique_ptr<SubscriptionManager> subscription_manager_;
const ParseJSONCallback parse_json_callback_;
const base::Clock* clock_;
// Called every time a push-by-value message is received to notify the
// observer.
OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback_;
// Called every time a push-to-refresh message is received to notify the
// observer.
OnRefreshRequestedCallback on_refresh_requested_callback_;
std::unique_ptr<base::OneShotTimer> token_validation_timer_;
std::unique_ptr<base::OneShotTimer> forced_subscription_timer_;
base::WeakPtrFactory<BreakingNewsGCMAppHandler> weak_ptr_factory_;
} // namespace ntp_snippets