Home | History | Annotate | Download | only in webui
      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