• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/ui/webui/sync_internals_message_handler.h"
6 
7 #include <vector>
8 
9 #include "base/logging.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/sync/about_sync_util.h"
12 #include "chrome/browser/sync/profile_sync_service.h"
13 #include "chrome/browser/sync/profile_sync_service_factory.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/web_ui.h"
16 #include "sync/internal_api/public/events/protocol_event.h"
17 #include "sync/internal_api/public/sessions/commit_counters.h"
18 #include "sync/internal_api/public/sessions/status_counters.h"
19 #include "sync/internal_api/public/sessions/update_counters.h"
20 #include "sync/internal_api/public/util/weak_handle.h"
21 #include "sync/js/js_event_details.h"
22 
23 using syncer::JsEventDetails;
24 using syncer::ModelTypeSet;
25 using syncer::WeakHandle;
26 
SyncInternalsMessageHandler()27 SyncInternalsMessageHandler::SyncInternalsMessageHandler()
28     : is_registered_(false),
29       is_registered_for_counters_(false),
30       weak_ptr_factory_(this) {
31 }
32 
~SyncInternalsMessageHandler()33 SyncInternalsMessageHandler::~SyncInternalsMessageHandler() {
34   if (js_controller_)
35     js_controller_->RemoveJsEventHandler(this);
36 
37   ProfileSyncService* service = GetProfileSyncService();
38   if (service && service->HasObserver(this)) {
39     service->RemoveObserver(this);
40     service->RemoveProtocolEventObserver(this);
41   }
42 
43   if (service && is_registered_for_counters_) {
44     service->RemoveTypeDebugInfoObserver(this);
45   }
46 }
47 
RegisterMessages()48 void SyncInternalsMessageHandler::RegisterMessages() {
49   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
50 
51   web_ui()->RegisterMessageCallback(
52       "registerForEvents",
53       base::Bind(&SyncInternalsMessageHandler::HandleRegisterForEvents,
54                  base::Unretained(this)));
55 
56   web_ui()->RegisterMessageCallback(
57       "registerForPerTypeCounters",
58       base::Bind(&SyncInternalsMessageHandler::HandleRegisterForPerTypeCounters,
59                  base::Unretained(this)));
60 
61   web_ui()->RegisterMessageCallback(
62       "requestUpdatedAboutInfo",
63       base::Bind(&SyncInternalsMessageHandler::HandleRequestUpdatedAboutInfo,
64                  base::Unretained(this)));
65 
66   web_ui()->RegisterMessageCallback(
67       "requestListOfTypes",
68       base::Bind(&SyncInternalsMessageHandler::HandleRequestListOfTypes,
69                  base::Unretained(this)));
70 
71   web_ui()->RegisterMessageCallback(
72       "getAllNodes",
73       base::Bind(&SyncInternalsMessageHandler::HandleGetAllNodes,
74                  base::Unretained(this)));
75 }
76 
HandleRegisterForEvents(const base::ListValue * args)77 void SyncInternalsMessageHandler::HandleRegisterForEvents(
78     const base::ListValue* args) {
79   DCHECK(args->empty());
80 
81   // is_registered_ flag protects us from double-registering.  This could
82   // happen on a page refresh, where the JavaScript gets re-run but the
83   // message handler remains unchanged.
84   ProfileSyncService* service = GetProfileSyncService();
85   if (service && !is_registered_) {
86     service->AddObserver(this);
87     service->AddProtocolEventObserver(this);
88     js_controller_ = service->GetJsController();
89     js_controller_->AddJsEventHandler(this);
90     is_registered_ = true;
91   }
92 }
93 
HandleRegisterForPerTypeCounters(const base::ListValue * args)94 void SyncInternalsMessageHandler::HandleRegisterForPerTypeCounters(
95     const base::ListValue* args) {
96   DCHECK(args->empty());
97 
98   ProfileSyncService* service = GetProfileSyncService();
99   if (service && !is_registered_for_counters_) {
100     service->AddTypeDebugInfoObserver(this);
101     is_registered_for_counters_ = true;
102   } else {
103     // Re-register to ensure counters get re-emitted.
104     service->RemoveTypeDebugInfoObserver(this);
105     service->AddTypeDebugInfoObserver(this);
106   }
107 }
108 
HandleRequestUpdatedAboutInfo(const base::ListValue * args)109 void SyncInternalsMessageHandler::HandleRequestUpdatedAboutInfo(
110     const base::ListValue* args) {
111   DCHECK(args->empty());
112   SendAboutInfo();
113 }
114 
HandleRequestListOfTypes(const base::ListValue * args)115 void SyncInternalsMessageHandler::HandleRequestListOfTypes(
116     const base::ListValue* args) {
117   DCHECK(args->empty());
118   base::DictionaryValue event_details;
119   scoped_ptr<base::ListValue> type_list(new base::ListValue());
120   ModelTypeSet protocol_types = syncer::ProtocolTypes();
121   for (ModelTypeSet::Iterator it = protocol_types.First();
122        it.Good(); it.Inc()) {
123     type_list->Append(new base::StringValue(ModelTypeToString(it.Get())));
124   }
125   event_details.Set("types", type_list.release());
126   web_ui()->CallJavascriptFunction(
127       "chrome.sync.dispatchEvent",
128       base::StringValue("onReceivedListOfTypes"),
129       event_details);
130 }
131 
HandleGetAllNodes(const base::ListValue * args)132 void SyncInternalsMessageHandler::HandleGetAllNodes(
133     const base::ListValue* args) {
134   DCHECK_EQ(1U, args->GetSize());
135   int request_id = 0;
136   bool success = args->GetInteger(0, &request_id);
137   DCHECK(success);
138 
139   ProfileSyncService* service = GetProfileSyncService();
140   if (service) {
141     service->GetAllNodes(
142         base::Bind(&SyncInternalsMessageHandler::OnReceivedAllNodes,
143                    weak_ptr_factory_.GetWeakPtr(), request_id));
144   }
145 }
146 
OnReceivedAllNodes(int request_id,scoped_ptr<base::ListValue> nodes)147 void SyncInternalsMessageHandler::OnReceivedAllNodes(
148     int request_id,
149     scoped_ptr<base::ListValue> nodes) {
150   base::FundamentalValue id(request_id);
151   web_ui()->CallJavascriptFunction("chrome.sync.getAllNodesCallback",
152                                    id, *nodes);
153 }
154 
OnStateChanged()155 void SyncInternalsMessageHandler::OnStateChanged() {
156   SendAboutInfo();
157 }
158 
OnProtocolEvent(const syncer::ProtocolEvent & event)159 void SyncInternalsMessageHandler::OnProtocolEvent(
160     const syncer::ProtocolEvent& event) {
161   scoped_ptr<base::DictionaryValue> value(
162       syncer::ProtocolEvent::ToValue(event));
163   web_ui()->CallJavascriptFunction(
164       "chrome.sync.dispatchEvent",
165       base::StringValue("onProtocolEvent"),
166       *value);
167 }
168 
OnCommitCountersUpdated(syncer::ModelType type,const syncer::CommitCounters & counters)169 void SyncInternalsMessageHandler::OnCommitCountersUpdated(
170     syncer::ModelType type,
171     const syncer::CommitCounters& counters) {
172   EmitCounterUpdate(type, "commit", counters.ToValue());
173 }
174 
OnUpdateCountersUpdated(syncer::ModelType type,const syncer::UpdateCounters & counters)175 void SyncInternalsMessageHandler::OnUpdateCountersUpdated(
176     syncer::ModelType type,
177     const syncer::UpdateCounters& counters) {
178   EmitCounterUpdate(type, "update", counters.ToValue());
179 }
180 
OnStatusCountersUpdated(syncer::ModelType type,const syncer::StatusCounters & counters)181 void SyncInternalsMessageHandler::OnStatusCountersUpdated(
182     syncer::ModelType type,
183     const syncer::StatusCounters& counters) {
184   EmitCounterUpdate(type, "status", counters.ToValue());
185 }
186 
EmitCounterUpdate(syncer::ModelType type,const std::string & counter_type,scoped_ptr<base::DictionaryValue> value)187 void SyncInternalsMessageHandler::EmitCounterUpdate(
188     syncer::ModelType type,
189     const std::string& counter_type,
190     scoped_ptr<base::DictionaryValue> value) {
191   scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
192   details->SetString("modelType", ModelTypeToString(type));
193   details->SetString("counterType", counter_type);
194   details->Set("counters", value.release());
195   web_ui()->CallJavascriptFunction("chrome.sync.dispatchEvent",
196                                    base::StringValue("onCountersUpdated"),
197                                    *details);
198 }
199 
HandleJsEvent(const std::string & name,const JsEventDetails & details)200 void SyncInternalsMessageHandler::HandleJsEvent(
201     const std::string& name,
202     const JsEventDetails& details) {
203   DVLOG(1) << "Handling event: " << name
204            << " with details " << details.ToString();
205   web_ui()->CallJavascriptFunction("chrome.sync.dispatchEvent",
206                                    base::StringValue(name),
207                                    details.Get());
208 }
209 
SendAboutInfo()210 void SyncInternalsMessageHandler::SendAboutInfo() {
211   scoped_ptr<base::DictionaryValue> value =
212       sync_ui_util::ConstructAboutInformation(GetProfileSyncService());
213   web_ui()->CallJavascriptFunction(
214       "chrome.sync.dispatchEvent",
215       base::StringValue("onAboutInfoUpdated"),
216       *value);
217 }
218 
219 // Gets the ProfileSyncService of the underlying original profile.
220 // May return NULL (e.g., if sync is disabled on the command line).
GetProfileSyncService()221 ProfileSyncService* SyncInternalsMessageHandler::GetProfileSyncService() {
222   Profile* profile = Profile::FromWebUI(web_ui());
223   ProfileSyncServiceFactory* factory = ProfileSyncServiceFactory::GetInstance();
224   return factory->GetForProfile(profile->GetOriginalProfile());
225 }
226