1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/sync/notifier/invalidation_notifier.h"
6
7#include "base/logging.h"
8#include "base/message_loop_proxy.h"
9#include "chrome/browser/sync/notifier/sync_notifier_observer.h"
10#include "chrome/browser/sync/protocol/service_constants.h"
11#include "chrome/browser/sync/syncable/model_type_payload_map.h"
12#include "jingle/notifier/base/const_communicator.h"
13#include "jingle/notifier/base/notifier_options_util.h"
14#include "jingle/notifier/communicator/connection_options.h"
15#include "net/base/host_port_pair.h"
16#include "net/url_request/url_request_context.h"
17#include "talk/xmpp/jid.h"
18#include "talk/xmpp/xmppclientsettings.h"
19
20namespace sync_notifier {
21
22InvalidationNotifier::InvalidationNotifier(
23    const notifier::NotifierOptions& notifier_options,
24    const std::string& client_info)
25    : state_(STOPPED),
26      notifier_options_(notifier_options),
27      client_info_(client_info) {
28  DCHECK_EQ(notifier::NOTIFICATION_SERVER,
29            notifier_options.notification_method);
30  DCHECK(notifier_options_.request_context_getter);
31  // TODO(akalin): Replace NonThreadSafe checks with IO thread checks.
32  DCHECK(notifier_options_.request_context_getter->GetIOMessageLoopProxy()->
33      BelongsToCurrentThread());
34}
35
36InvalidationNotifier::~InvalidationNotifier() {
37  DCHECK(non_thread_safe_.CalledOnValidThread());
38}
39
40void InvalidationNotifier::AddObserver(SyncNotifierObserver* observer) {
41  DCHECK(non_thread_safe_.CalledOnValidThread());
42  observers_.AddObserver(observer);
43}
44
45void InvalidationNotifier::RemoveObserver(SyncNotifierObserver* observer) {
46  DCHECK(non_thread_safe_.CalledOnValidThread());
47  observers_.RemoveObserver(observer);
48}
49
50void InvalidationNotifier::SetState(const std::string& state) {
51  DCHECK(non_thread_safe_.CalledOnValidThread());
52  invalidation_state_ = state;
53}
54
55void InvalidationNotifier::UpdateCredentials(
56    const std::string& email, const std::string& token) {
57  DCHECK(non_thread_safe_.CalledOnValidThread());
58  VLOG(1) << "Updating credentials for " << email;
59  buzz::XmppClientSettings xmpp_client_settings =
60      notifier::MakeXmppClientSettings(notifier_options_,
61                                       email, token, SYNC_SERVICE_NAME);
62  if (state_ >= CONNECTING) {
63    login_->UpdateXmppSettings(xmpp_client_settings);
64  } else {
65    notifier::ConnectionOptions options;
66    VLOG(1) << "First time updating credentials: connecting";
67    login_.reset(
68        new notifier::Login(this,
69                            xmpp_client_settings,
70                            notifier::ConnectionOptions(),
71                            notifier_options_.request_context_getter,
72                            notifier::GetServerList(notifier_options_),
73                            notifier_options_.try_ssltcp_first,
74                            notifier_options_.auth_mechanism));
75    login_->StartConnection();
76    state_ = CONNECTING;
77  }
78}
79
80void InvalidationNotifier::UpdateEnabledTypes(
81    const syncable::ModelTypeSet& types) {
82  DCHECK(non_thread_safe_.CalledOnValidThread());
83  invalidation_client_.RegisterTypes(types);
84}
85
86void InvalidationNotifier::SendNotification() {
87  DCHECK(non_thread_safe_.CalledOnValidThread());
88}
89
90void InvalidationNotifier::OnConnect(
91    base::WeakPtr<talk_base::Task> base_task) {
92  DCHECK(non_thread_safe_.CalledOnValidThread());
93  VLOG(1) << "OnConnect";
94  if (state_ >= STARTED) {
95    invalidation_client_.ChangeBaseTask(base_task);
96  } else {
97    VLOG(1) << "First time connecting: starting invalidation client";
98    // TODO(akalin): Make cache_guid() part of the client ID.  If we
99    // do so and we somehow propagate it up to the server somehow, we
100    // can make it so that we won't receive any notifications that
101    // were generated from our own changes.
102    const std::string kClientId = "invalidation_notifier";
103    invalidation_client_.Start(
104        kClientId, client_info_, invalidation_state_, this, this, base_task);
105    invalidation_state_.clear();
106    state_ = STARTED;
107  }
108}
109
110void InvalidationNotifier::OnDisconnect() {
111  DCHECK(non_thread_safe_.CalledOnValidThread());
112  VLOG(1) << "OnDisconnect";
113}
114
115void InvalidationNotifier::OnInvalidate(
116    const syncable::ModelTypePayloadMap& type_payloads) {
117  DCHECK(non_thread_safe_.CalledOnValidThread());
118  FOR_EACH_OBSERVER(SyncNotifierObserver, observers_,
119                    OnIncomingNotification(type_payloads));
120}
121
122void InvalidationNotifier::OnSessionStatusChanged(bool has_session) {
123  FOR_EACH_OBSERVER(SyncNotifierObserver, observers_,
124                    OnNotificationStateChange(has_session));
125}
126
127void InvalidationNotifier::WriteState(const std::string& state) {
128  DCHECK(non_thread_safe_.CalledOnValidThread());
129  VLOG(1) << "WriteState";
130  FOR_EACH_OBSERVER(SyncNotifierObserver, observers_, StoreState(state));
131}
132
133}  // namespace sync_notifier
134