146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/invalidation/push_client_channel.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/invalidation/notifier_reason_util.h"
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "google/cacheinvalidation/client_gateway.pb.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "google/cacheinvalidation/types.pb.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "jingle/notifier/listener/push_client.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kBotJid[] = "tango@bot.talk.google.com";
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kChannelName[] = "tango_raw";
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushClientChannel::PushClientChannel(
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<notifier::PushClient> push_client)
2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    : push_client_(push_client.Pass()),
2523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      scheduling_hash_(0),
2623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      sent_messages_count_(0) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->AddObserver(this);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier::Subscription subscription;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subscription.channel = kChannelName;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subscription.from = "";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier::SubscriptionList subscriptions;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subscriptions.push_back(subscription);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->UpdateSubscriptions(subscriptions);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushClientChannel::~PushClientChannel() {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->RemoveObserver(this);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushClientChannel::UpdateCredentials(
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& email, const std::string& token) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->UpdateCredentials(email, token);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)int PushClientChannel::GetInvalidationClientType() {
46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if defined(OS_IOS)
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return ipc::invalidation::ClientType::CHROME_SYNC_IOS;
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#else
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return ipc::invalidation::ClientType::CHROME_SYNC;
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void PushClientChannel::RequestDetailedStatus(
5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    base::Callback<void(const base::DictionaryValue&)> callback) {
5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  callback.Run(*CollectDebugData());
5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PushClientChannel::SendMessage(const std::string& message) {
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string encoded_message;
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EncodeMessage(&encoded_message, message, service_context_, scheduling_hash_);
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  notifier::Recipient recipient;
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  recipient.to = kBotJid;
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  notifier::Notification notification;
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  notification.channel = kChannelName;
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  notification.recipients.push_back(recipient);
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  notification.data = encoded_message;
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  push_client_->SendNotification(notification);
6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  sent_messages_count_++;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushClientChannel::OnNotificationsEnabled() {
736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  NotifyNetworkStatusChange(true);
746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  NotifyChannelStateChange(INVALIDATIONS_ENABLED);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushClientChannel::OnNotificationsDisabled(
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notifier::NotificationsDisabledReason reason) {
796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  NotifyNetworkStatusChange(false);
806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  NotifyChannelStateChange(FromNotifierReason(reason));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushClientChannel::OnIncomingNotification(
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const notifier::Notification& notification) {
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string message;
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string service_context;
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int64 scheduling_hash;
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!DecodeMessage(
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)           notification.data, &message, &service_context, &scheduling_hash)) {
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DLOG(ERROR) << "Could not parse ClientGatewayMessage";
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (DeliverIncomingMessage(message)) {
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    service_context_ = service_context;
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scheduling_hash_ = scheduling_hash;
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const std::string& PushClientChannel::GetServiceContextForTest() const {
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return service_context_;
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int64 PushClientChannel::GetSchedulingHashForTest() const {
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return scheduling_hash_;
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string PushClientChannel::EncodeMessageForTest(
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& message,
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& service_context,
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int64 scheduling_hash) {
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string encoded_message;
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EncodeMessage(&encoded_message, message, service_context, scheduling_hash);
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return encoded_message;
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool PushClientChannel::DecodeMessageForTest(const std::string& data,
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                             std::string* message,
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                             std::string* service_context,
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                             int64* scheduling_hash) {
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return DecodeMessage(data, message, service_context, scheduling_hash);
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PushClientChannel::EncodeMessage(std::string* encoded_message,
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      const std::string& message,
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      const std::string& service_context,
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      int64 scheduling_hash) {
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ipc::invalidation::ClientGatewayMessage envelope;
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  envelope.set_is_client_to_server(true);
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!service_context.empty()) {
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    envelope.set_service_context(service_context);
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    envelope.set_rpc_scheduling_hash(scheduling_hash);
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  envelope.set_network_message(message);
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  envelope.SerializeToString(encoded_message);
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool PushClientChannel::DecodeMessage(const std::string& data,
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      std::string* message,
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      std::string* service_context,
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      int64* scheduling_hash) {
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ipc::invalidation::ClientGatewayMessage envelope;
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!envelope.ParseFromString(data)) {
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  *message = envelope.network_message();
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (envelope.has_service_context()) {
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *service_context = envelope.service_context();
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (envelope.has_rpc_scheduling_hash()) {
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    *scheduling_hash = envelope.rpc_scheduling_hash();
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)scoped_ptr<base::DictionaryValue> PushClientChannel::CollectDebugData() const {
15623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> status(new base::DictionaryValue);
15723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  status->SetString("PushClientChannel.NetworkChannel", "Push Client");
15823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  status->SetInteger("PushClientChannel.SentMessages", sent_messages_count_);
15923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  status->SetInteger("PushClientChannel.ReceivedMessages",
16023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                     SyncNetworkChannel::GetReceivedMessagesCount());
16123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return status.Pass();
16223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
16323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncer
165