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 27 SyncInternalsMessageHandler::SyncInternalsMessageHandler() 28 : is_registered_(false), 29 is_registered_for_counters_(false), 30 weak_ptr_factory_(this) { 31 } 32 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 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 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 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 109 void SyncInternalsMessageHandler::HandleRequestUpdatedAboutInfo( 110 const base::ListValue* args) { 111 DCHECK(args->empty()); 112 SendAboutInfo(); 113 } 114 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 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 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 155 void SyncInternalsMessageHandler::OnStateChanged() { 156 SendAboutInfo(); 157 } 158 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 169 void SyncInternalsMessageHandler::OnCommitCountersUpdated( 170 syncer::ModelType type, 171 const syncer::CommitCounters& counters) { 172 EmitCounterUpdate(type, "commit", counters.ToValue()); 173 } 174 175 void SyncInternalsMessageHandler::OnUpdateCountersUpdated( 176 syncer::ModelType type, 177 const syncer::UpdateCounters& counters) { 178 EmitCounterUpdate(type, "update", counters.ToValue()); 179 } 180 181 void SyncInternalsMessageHandler::OnStatusCountersUpdated( 182 syncer::ModelType type, 183 const syncer::StatusCounters& counters) { 184 EmitCounterUpdate(type, "status", counters.ToValue()); 185 } 186 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 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 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). 221 ProfileSyncService* SyncInternalsMessageHandler::GetProfileSyncService() { 222 Profile* profile = Profile::FromWebUI(web_ui()); 223 ProfileSyncServiceFactory* factory = ProfileSyncServiceFactory::GetInstance(); 224 return factory->GetForProfile(profile->GetOriginalProfile()); 225 } 226