|  | // 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. | 
|  |  | 
|  | #include "components/invalidation/impl/per_user_topic_invalidation_client.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/strings/string_number_conversions.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "components/invalidation/impl/invalidation_listener.h" | 
|  | #include "components/invalidation/impl/logger.h" | 
|  | #include "components/invalidation/impl/network_channel.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const char kPrivatTopicName[] = "/topics"; | 
|  | const int kPrivatTopicNameSize = 7; | 
|  | } | 
|  |  | 
|  | namespace syncer { | 
|  |  | 
|  | std::unique_ptr<InvalidationClient> CreatePerUserTopicInvalidationClient( | 
|  | NetworkChannel* network, | 
|  | Logger* logger, | 
|  | InvalidationListener* listener) { | 
|  | return std::make_unique<PerUserTopicInvalidationClient>(network, logger, | 
|  | listener); | 
|  | } | 
|  |  | 
|  | PerUserTopicInvalidationClient::PerUserTopicInvalidationClient( | 
|  | NetworkChannel* network, | 
|  | Logger* logger, | 
|  | InvalidationListener* listener) | 
|  | : network_(network), | 
|  | logger_(logger), | 
|  | listener_(listener), | 
|  | weak_factory_(this) { | 
|  | RegisterWithNetwork(); | 
|  | TLOG(logger_, INFO, "Created client"); | 
|  | } | 
|  |  | 
|  | PerUserTopicInvalidationClient::~PerUserTopicInvalidationClient() {} | 
|  |  | 
|  | void PerUserTopicInvalidationClient::RegisterWithNetwork() { | 
|  | // Install ourselves as a receiver for server messages. | 
|  | network_->SetMessageReceiver( | 
|  | base::BindRepeating(&PerUserTopicInvalidationClient::MessageReceiver, | 
|  | weak_factory_.GetWeakPtr())); | 
|  | network_->SetTokenReceiver( | 
|  | base::BindRepeating(&PerUserTopicInvalidationClient::TokenReceiver, | 
|  | weak_factory_.GetWeakPtr())); | 
|  | } | 
|  |  | 
|  | void PerUserTopicInvalidationClient::Start() { | 
|  | if (ticl_protocol_started_) { | 
|  | TLOG(logger_, SEVERE, "Ignoring start call since already started"); | 
|  | return; | 
|  | } | 
|  | FinishStartingTiclAndInformListener(); | 
|  | } | 
|  |  | 
|  | void PerUserTopicInvalidationClient::Stop() { | 
|  | TLOG(logger_, INFO, "Ticl being stopped"); | 
|  | ticl_protocol_started_ = false; | 
|  | } | 
|  |  | 
|  | void PerUserTopicInvalidationClient::FinishStartingTiclAndInformListener() { | 
|  | DCHECK(!ticl_protocol_started_); | 
|  | ticl_protocol_started_ = true; | 
|  | GetListener()->Ready(this); | 
|  | TLOG(logger_, INFO, "Ticl started"); | 
|  | } | 
|  |  | 
|  | void PerUserTopicInvalidationClient::MessageReceiver( | 
|  | const std::string& payload, | 
|  | const std::string& private_topic, | 
|  | const std::string& public_topic, | 
|  | const std::string& version) { | 
|  | std::string private_topic_name = private_topic; | 
|  | if (base::StartsWith(private_topic, kPrivatTopicName, | 
|  | base::CompareCase::INSENSITIVE_ASCII)) { | 
|  | // FCM protocol requires topic to start with"/topics" to topic name. | 
|  | // Reason why it is necessary to strip the prefix is that later the shorter | 
|  | // topic name is used for indexing into maps. | 
|  | private_topic_name = private_topic.substr(kPrivatTopicNameSize); | 
|  | } | 
|  | int64_t v = 0; | 
|  | if (!base::StringToInt64(version, &v)) { | 
|  | // Version must always be in the message and | 
|  | // in addition version must be number. | 
|  | // TODO(melandory): Report Error to listener; | 
|  | } | 
|  | GetListener()->Invalidate(this, payload, private_topic_name, public_topic, v); | 
|  | } | 
|  |  | 
|  | void PerUserTopicInvalidationClient::TokenReceiver(const std::string& token) { | 
|  | GetListener()->InformTokenRecieved(this, token); | 
|  | if (!ticl_protocol_started_) | 
|  | FinishStartingTiclAndInformListener(); | 
|  | } | 
|  |  | 
|  | }  // namespace invalidation |