Home | History | Annotate | Download | only in chromeos
      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/chromeos/provided_file_systems_ui.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/files/file.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/memory/weak_ptr.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
     16 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
     17 #include "chrome/browser/chromeos/file_system_provider/request_manager.h"
     18 #include "chrome/browser/chromeos/file_system_provider/service.h"
     19 #include "chrome/browser/chromeos/file_system_provider/service_factory.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/common/url_constants.h"
     22 #include "content/public/browser/browser_thread.h"
     23 #include "content/public/browser/web_ui.h"
     24 #include "content/public/browser/web_ui_data_source.h"
     25 #include "content/public/browser/web_ui_message_handler.h"
     26 #include "grit/browser_resources.h"
     27 
     28 using content::BrowserThread;
     29 
     30 namespace chromeos {
     31 
     32 namespace {
     33 
     34 const char kKeyId[] = "id";
     35 const char kKeyEventType[] = "eventType";
     36 const char kKeyRequestType[] = "requestType";
     37 const char kKeyTime[] = "time";
     38 const char kKeyHasMore[] = "hasMore";
     39 const char kKeyError[] = "error";
     40 const char kKeyExecutionTime[] = "executionTime";
     41 const char kKeyValueSize[] = "valueSize";
     42 
     43 const char kKeyName[] = "name";
     44 const char kKeyExtensionId[] = "extensionId";
     45 const char kKeyMountPath[] = "mountPath";
     46 const char kKeyActiveRequests[] = "activeRequests";
     47 
     48 const char kRequestCreated[] = "created";
     49 const char kRequestDestroyed[] = "destroyed";
     50 const char kRequestExecuted[] = "executed";
     51 const char kRequestFulfilled[] = "fulfilled";
     52 const char kRequestRejected[] = "rejected";
     53 const char kRequestTimeouted[] = "timeouted";
     54 
     55 const char kFunctionOnRequestEvent[] = "onRequestEvent";
     56 const char kFunctionUpdateFileSystems[] = "updateFileSystems";
     57 const char kFunctionSelectFileSystem[] = "selectFileSystem";
     58 
     59 // Creates a dictionary holding common fields for the onRequest* events.
     60 scoped_ptr<base::DictionaryValue> CreateRequestEvent(const std::string& type,
     61                                                      int request_id) {
     62   scoped_ptr<base::DictionaryValue> event(new base::DictionaryValue);
     63   event->SetInteger(kKeyId, request_id);
     64   event->SetString(kKeyEventType, type);
     65   event->SetDouble(kKeyTime, base::Time::Now().ToJsTime());
     66   return event.Pass();
     67 }
     68 
     69 // Gets execution time from a RequestValue instance. If the |response| doesn't
     70 // have execution time, then returns 0.
     71 int GetExecutionTime(const file_system_provider::RequestValue& response) {
     72   {
     73     const extensions::api::file_system_provider_internal::
     74         UnmountRequestedSuccess::Params* value =
     75             response.unmount_success_params();
     76     if (value)
     77       return value->execution_time;
     78   }
     79   {
     80     const extensions::api::file_system_provider_internal::
     81         GetMetadataRequestedSuccess::Params* value =
     82             response.get_metadata_success_params();
     83     if (value)
     84       return value->execution_time;
     85   }
     86   {
     87     const extensions::api::file_system_provider_internal::
     88         ReadDirectoryRequestedSuccess::Params* value =
     89             response.read_directory_success_params();
     90     if (value)
     91       return value->execution_time;
     92   }
     93   {
     94     const extensions::api::file_system_provider_internal::
     95         ReadFileRequestedSuccess::Params* value =
     96             response.read_file_success_params();
     97     if (value)
     98       return value->execution_time;
     99   }
    100   {
    101     const extensions::api::file_system_provider_internal::
    102         OperationRequestedSuccess::Params* value =
    103             response.operation_success_params();
    104     if (value)
    105       return value->execution_time;
    106   }
    107   {
    108     const extensions::api::file_system_provider_internal::
    109         OperationRequestedError::Params* value =
    110             response.operation_error_params();
    111     if (value)
    112       return value->execution_time;
    113   }
    114 
    115   return 0;
    116 }
    117 
    118 // Gets value size in bytes from a RequestValue instance. If not available,
    119 // then returns 0.
    120 int GetValueSize(const file_system_provider::RequestValue& response) {
    121   const extensions::api::file_system_provider_internal::
    122       ReadFileRequestedSuccess::Params* value =
    123           response.read_file_success_params();
    124   if (value)
    125     return value->data.size();
    126 
    127   return 0;
    128 }
    129 
    130 // Class to handle messages from chrome://provided-file-systems.
    131 class ProvidedFileSystemsWebUIHandler
    132     : public content::WebUIMessageHandler,
    133       public file_system_provider::RequestManager::Observer {
    134  public:
    135   ProvidedFileSystemsWebUIHandler() : weak_ptr_factory_(this) {}
    136 
    137   virtual ~ProvidedFileSystemsWebUIHandler();
    138 
    139   // RequestManager::Observer overrides.
    140   virtual void OnRequestCreated(
    141       int request_id,
    142       file_system_provider::RequestType type) OVERRIDE;
    143   virtual void OnRequestDestroyed(int request_id) OVERRIDE;
    144   virtual void OnRequestExecuted(int request_id) OVERRIDE;
    145   virtual void OnRequestFulfilled(
    146       int request_id,
    147       const file_system_provider::RequestValue& result,
    148       bool has_more) OVERRIDE;
    149   virtual void OnRequestRejected(
    150       int request_id,
    151       const file_system_provider::RequestValue& result,
    152       base::File::Error error) OVERRIDE;
    153   virtual void OnRequestTimeouted(int request_id) OVERRIDE;
    154 
    155  private:
    156   // content::WebUIMessageHandler overrides.
    157   virtual void RegisterMessages() OVERRIDE;
    158 
    159   // Gets a file system provider service for the current profile. If not found,
    160   // then NULL.
    161   file_system_provider::Service* GetService();
    162 
    163   // Invoked when updating file system list is requested.
    164   void UpdateFileSystems(const base::ListValue* args);
    165 
    166   // Invoked when a file system is selected from the list.
    167   void SelectFileSystem(const base::ListValue* args);
    168 
    169   std::string selected_extension_id;
    170   std::string selected_file_system_id;
    171   base::WeakPtrFactory<ProvidedFileSystemsWebUIHandler> weak_ptr_factory_;
    172 
    173   DISALLOW_COPY_AND_ASSIGN(ProvidedFileSystemsWebUIHandler);
    174 };
    175 
    176 ProvidedFileSystemsWebUIHandler::~ProvidedFileSystemsWebUIHandler() {
    177   // Stop observing the currently selected file system.
    178   file_system_provider::Service* const service = GetService();
    179   if (!service)
    180     return;
    181 
    182   file_system_provider::ProvidedFileSystemInterface* const file_system =
    183       service->GetProvidedFileSystem(selected_extension_id,
    184                                      selected_file_system_id);
    185 
    186   if (file_system) {
    187     file_system_provider::RequestManager* const request_manager =
    188         file_system->GetRequestManager();
    189     DCHECK(request_manager);
    190     request_manager->RemoveObserver(this);
    191   }
    192 }
    193 
    194 void ProvidedFileSystemsWebUIHandler::OnRequestCreated(
    195     int request_id,
    196     file_system_provider::RequestType type) {
    197   scoped_ptr<base::DictionaryValue> const event =
    198       CreateRequestEvent(kRequestCreated, request_id);
    199   event->SetString(kKeyRequestType,
    200                    file_system_provider::RequestTypeToString(type));
    201   web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event);
    202 }
    203 
    204 void ProvidedFileSystemsWebUIHandler::OnRequestDestroyed(int request_id) {
    205   scoped_ptr<base::DictionaryValue> const event =
    206       CreateRequestEvent(kRequestDestroyed, request_id);
    207   web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event);
    208 }
    209 
    210 void ProvidedFileSystemsWebUIHandler::OnRequestExecuted(int request_id) {
    211   scoped_ptr<base::DictionaryValue> const event =
    212       CreateRequestEvent(kRequestExecuted, request_id);
    213   web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event);
    214 }
    215 
    216 void ProvidedFileSystemsWebUIHandler::OnRequestFulfilled(
    217     int request_id,
    218     const file_system_provider::RequestValue& result,
    219     bool has_more) {
    220   scoped_ptr<base::DictionaryValue> const event =
    221       CreateRequestEvent(kRequestFulfilled, request_id);
    222   event->SetBoolean(kKeyHasMore, has_more);
    223   event->SetInteger(kKeyExecutionTime, GetExecutionTime(result));
    224   event->SetInteger(kKeyValueSize, GetValueSize(result));
    225   web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event);
    226 }
    227 
    228 void ProvidedFileSystemsWebUIHandler::OnRequestRejected(
    229     int request_id,
    230     const file_system_provider::RequestValue& result,
    231     base::File::Error error) {
    232   scoped_ptr<base::DictionaryValue> const event =
    233       CreateRequestEvent(kRequestRejected, request_id);
    234   event->SetString(kKeyError, base::File::ErrorToString(error));
    235   event->SetInteger(kKeyExecutionTime, GetExecutionTime(result));
    236   event->SetInteger(kKeyValueSize, GetValueSize(result));
    237   web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event);
    238 }
    239 
    240 void ProvidedFileSystemsWebUIHandler::OnRequestTimeouted(int request_id) {
    241   scoped_ptr<base::DictionaryValue> const event =
    242       CreateRequestEvent(kRequestTimeouted, request_id);
    243   web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event);
    244 }
    245 
    246 void ProvidedFileSystemsWebUIHandler::RegisterMessages() {
    247   web_ui()->RegisterMessageCallback(
    248       kFunctionUpdateFileSystems,
    249       base::Bind(&ProvidedFileSystemsWebUIHandler::UpdateFileSystems,
    250                  weak_ptr_factory_.GetWeakPtr()));
    251   web_ui()->RegisterMessageCallback(
    252       kFunctionSelectFileSystem,
    253       base::Bind(&ProvidedFileSystemsWebUIHandler::SelectFileSystem,
    254                  weak_ptr_factory_.GetWeakPtr()));
    255 }
    256 
    257 file_system_provider::Service* ProvidedFileSystemsWebUIHandler::GetService() {
    258   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    259 
    260   Profile* const profile = Profile::FromWebUI(web_ui());
    261   return file_system_provider::ServiceFactory::FindExisting(profile);
    262 }
    263 
    264 void ProvidedFileSystemsWebUIHandler::UpdateFileSystems(
    265     const base::ListValue* args) {
    266   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    267 
    268   file_system_provider::Service* const service = GetService();
    269   if (!service)
    270     return;
    271 
    272   base::ListValue items;
    273 
    274   const std::vector<file_system_provider::ProvidedFileSystemInfo>
    275       file_system_info_list = service->GetProvidedFileSystemInfoList();
    276 
    277   for (size_t i = 0; i < file_system_info_list.size(); ++i) {
    278     const file_system_provider::ProvidedFileSystemInfo file_system_info =
    279         file_system_info_list[i];
    280 
    281     file_system_provider::ProvidedFileSystemInterface* const file_system =
    282         service->GetProvidedFileSystem(file_system_info.extension_id(),
    283                                        file_system_info.file_system_id());
    284     DCHECK(file_system);
    285 
    286     file_system_provider::RequestManager* const request_manager =
    287         file_system->GetRequestManager();
    288     DCHECK(request_manager);
    289 
    290     base::DictionaryValue* item = new base::DictionaryValue();
    291     item->SetString(kKeyId, file_system_info.file_system_id());
    292     item->SetString(kKeyName, file_system_info.display_name());
    293     item->SetString(kKeyExtensionId, file_system_info.extension_id());
    294     item->SetString(kKeyMountPath,
    295                     file_system_info.mount_path().AsUTF8Unsafe());
    296     item->SetInteger(kKeyActiveRequests,
    297                      request_manager->GetActiveRequestIds().size());
    298 
    299     items.Append(item);
    300   }
    301 
    302   web_ui()->CallJavascriptFunction(kFunctionUpdateFileSystems, items);
    303 }
    304 
    305 void ProvidedFileSystemsWebUIHandler::SelectFileSystem(
    306     const base::ListValue* args) {
    307   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    308 
    309   file_system_provider::Service* const service = GetService();
    310   if (!service)
    311     return;
    312 
    313   std::string extension_id;
    314   if (!args->GetString(0, &extension_id))
    315     return;
    316 
    317   std::string file_system_id;
    318   if (!args->GetString(1, &file_system_id))
    319     return;
    320 
    321   // Stop observing the previously selected request manager.
    322   {
    323     file_system_provider::ProvidedFileSystemInterface* const file_system =
    324         service->GetProvidedFileSystem(selected_extension_id,
    325                                        selected_file_system_id);
    326     if (file_system) {
    327       file_system_provider::RequestManager* const request_manager =
    328           file_system->GetRequestManager();
    329       DCHECK(request_manager);
    330       request_manager->RemoveObserver(this);
    331     }
    332   }
    333 
    334   // Observe the selected file system.
    335   file_system_provider::ProvidedFileSystemInterface* const file_system =
    336       service->GetProvidedFileSystem(extension_id, file_system_id);
    337   if (!file_system)
    338     return;
    339 
    340   file_system_provider::RequestManager* const request_manager =
    341       file_system->GetRequestManager();
    342   DCHECK(request_manager);
    343 
    344   request_manager->AddObserver(this);
    345   selected_extension_id = extension_id;
    346   selected_file_system_id = file_system_id;
    347 }
    348 
    349 }  // namespace
    350 
    351 ProvidedFileSystemsUI::ProvidedFileSystemsUI(content::WebUI* web_ui)
    352     : WebUIController(web_ui) {
    353   web_ui->AddMessageHandler(new ProvidedFileSystemsWebUIHandler());
    354 
    355   content::WebUIDataSource* source = content::WebUIDataSource::Create(
    356       chrome::kChromeUIProvidedFileSystemsHost);
    357   source->AddResourcePath("provided_file_systems.css",
    358                           IDR_PROVIDED_FILE_SYSTEMS_CSS);
    359   source->AddResourcePath("provided_file_systems.js",
    360                           IDR_PROVIDED_FILE_SYSTEMS_JS);
    361   source->SetDefaultResource(IDR_PROVIDED_FILE_SYSTEMS_HTML);
    362 
    363   Profile* profile = Profile::FromWebUI(web_ui);
    364   content::WebUIDataSource::Add(profile, source);
    365 }
    366 
    367 }  // namespace chromeos
    368