// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/ui/webui/chromeos/provided_file_systems_ui.h" #include #include #include "base/bind.h" #include "base/files/file.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/values.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/browser/chromeos/file_system_provider/request_manager.h" #include "chrome/browser/chromeos/file_system_provider/service.h" #include "chrome/browser/chromeos/file_system_provider/service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/url_constants.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" #include "content/public/browser/web_ui_message_handler.h" #include "grit/browser_resources.h" using content::BrowserThread; namespace chromeos { namespace { const char kKeyId[] = "id"; const char kKeyEventType[] = "eventType"; const char kKeyRequestType[] = "requestType"; const char kKeyTime[] = "time"; const char kKeyHasMore[] = "hasMore"; const char kKeyError[] = "error"; const char kKeyExecutionTime[] = "executionTime"; const char kKeyValueSize[] = "valueSize"; const char kKeyName[] = "name"; const char kKeyExtensionId[] = "extensionId"; const char kKeyMountPath[] = "mountPath"; const char kKeyActiveRequests[] = "activeRequests"; const char kRequestCreated[] = "created"; const char kRequestDestroyed[] = "destroyed"; const char kRequestExecuted[] = "executed"; const char kRequestFulfilled[] = "fulfilled"; const char kRequestRejected[] = "rejected"; const char kRequestTimeouted[] = "timeouted"; const char kFunctionOnRequestEvent[] = "onRequestEvent"; const char kFunctionUpdateFileSystems[] = "updateFileSystems"; const char kFunctionSelectFileSystem[] = "selectFileSystem"; // Creates a dictionary holding common fields for the onRequest* events. scoped_ptr CreateRequestEvent(const std::string& type, int request_id) { scoped_ptr event(new base::DictionaryValue); event->SetInteger(kKeyId, request_id); event->SetString(kKeyEventType, type); event->SetDouble(kKeyTime, base::Time::Now().ToJsTime()); return event.Pass(); } // Gets execution time from a RequestValue instance. If the |response| doesn't // have execution time, then returns 0. int GetExecutionTime(const file_system_provider::RequestValue& response) { { const extensions::api::file_system_provider_internal:: UnmountRequestedSuccess::Params* value = response.unmount_success_params(); if (value) return value->execution_time; } { const extensions::api::file_system_provider_internal:: GetMetadataRequestedSuccess::Params* value = response.get_metadata_success_params(); if (value) return value->execution_time; } { const extensions::api::file_system_provider_internal:: ReadDirectoryRequestedSuccess::Params* value = response.read_directory_success_params(); if (value) return value->execution_time; } { const extensions::api::file_system_provider_internal:: ReadFileRequestedSuccess::Params* value = response.read_file_success_params(); if (value) return value->execution_time; } { const extensions::api::file_system_provider_internal:: OperationRequestedSuccess::Params* value = response.operation_success_params(); if (value) return value->execution_time; } { const extensions::api::file_system_provider_internal:: OperationRequestedError::Params* value = response.operation_error_params(); if (value) return value->execution_time; } return 0; } // Gets value size in bytes from a RequestValue instance. If not available, // then returns 0. int GetValueSize(const file_system_provider::RequestValue& response) { const extensions::api::file_system_provider_internal:: ReadFileRequestedSuccess::Params* value = response.read_file_success_params(); if (value) return value->data.size(); return 0; } // Class to handle messages from chrome://provided-file-systems. class ProvidedFileSystemsWebUIHandler : public content::WebUIMessageHandler, public file_system_provider::RequestManager::Observer { public: ProvidedFileSystemsWebUIHandler() : weak_ptr_factory_(this) {} virtual ~ProvidedFileSystemsWebUIHandler(); // RequestManager::Observer overrides. virtual void OnRequestCreated( int request_id, file_system_provider::RequestType type) override; virtual void OnRequestDestroyed(int request_id) override; virtual void OnRequestExecuted(int request_id) override; virtual void OnRequestFulfilled( int request_id, const file_system_provider::RequestValue& result, bool has_more) override; virtual void OnRequestRejected( int request_id, const file_system_provider::RequestValue& result, base::File::Error error) override; virtual void OnRequestTimeouted(int request_id) override; private: // content::WebUIMessageHandler overrides. virtual void RegisterMessages() override; // Gets a file system provider service for the current profile. If not found, // then NULL. file_system_provider::Service* GetService(); // Invoked when updating file system list is requested. void UpdateFileSystems(const base::ListValue* args); // Invoked when a file system is selected from the list. void SelectFileSystem(const base::ListValue* args); std::string selected_extension_id; std::string selected_file_system_id; base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ProvidedFileSystemsWebUIHandler); }; ProvidedFileSystemsWebUIHandler::~ProvidedFileSystemsWebUIHandler() { // Stop observing the currently selected file system. file_system_provider::Service* const service = GetService(); if (!service) return; file_system_provider::ProvidedFileSystemInterface* const file_system = service->GetProvidedFileSystem(selected_extension_id, selected_file_system_id); if (file_system) { file_system_provider::RequestManager* const request_manager = file_system->GetRequestManager(); DCHECK(request_manager); request_manager->RemoveObserver(this); } } void ProvidedFileSystemsWebUIHandler::OnRequestCreated( int request_id, file_system_provider::RequestType type) { scoped_ptr const event = CreateRequestEvent(kRequestCreated, request_id); event->SetString(kKeyRequestType, file_system_provider::RequestTypeToString(type)); web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); } void ProvidedFileSystemsWebUIHandler::OnRequestDestroyed(int request_id) { scoped_ptr const event = CreateRequestEvent(kRequestDestroyed, request_id); web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); } void ProvidedFileSystemsWebUIHandler::OnRequestExecuted(int request_id) { scoped_ptr const event = CreateRequestEvent(kRequestExecuted, request_id); web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); } void ProvidedFileSystemsWebUIHandler::OnRequestFulfilled( int request_id, const file_system_provider::RequestValue& result, bool has_more) { scoped_ptr const event = CreateRequestEvent(kRequestFulfilled, request_id); event->SetBoolean(kKeyHasMore, has_more); event->SetInteger(kKeyExecutionTime, GetExecutionTime(result)); event->SetInteger(kKeyValueSize, GetValueSize(result)); web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); } void ProvidedFileSystemsWebUIHandler::OnRequestRejected( int request_id, const file_system_provider::RequestValue& result, base::File::Error error) { scoped_ptr const event = CreateRequestEvent(kRequestRejected, request_id); event->SetString(kKeyError, base::File::ErrorToString(error)); event->SetInteger(kKeyExecutionTime, GetExecutionTime(result)); event->SetInteger(kKeyValueSize, GetValueSize(result)); web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); } void ProvidedFileSystemsWebUIHandler::OnRequestTimeouted(int request_id) { scoped_ptr const event = CreateRequestEvent(kRequestTimeouted, request_id); web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); } void ProvidedFileSystemsWebUIHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( kFunctionUpdateFileSystems, base::Bind(&ProvidedFileSystemsWebUIHandler::UpdateFileSystems, weak_ptr_factory_.GetWeakPtr())); web_ui()->RegisterMessageCallback( kFunctionSelectFileSystem, base::Bind(&ProvidedFileSystemsWebUIHandler::SelectFileSystem, weak_ptr_factory_.GetWeakPtr())); } file_system_provider::Service* ProvidedFileSystemsWebUIHandler::GetService() { DCHECK_CURRENTLY_ON(BrowserThread::UI); Profile* const profile = Profile::FromWebUI(web_ui()); return file_system_provider::ServiceFactory::FindExisting(profile); } void ProvidedFileSystemsWebUIHandler::UpdateFileSystems( const base::ListValue* args) { DCHECK_CURRENTLY_ON(BrowserThread::UI); file_system_provider::Service* const service = GetService(); if (!service) return; base::ListValue items; const std::vector file_system_info_list = service->GetProvidedFileSystemInfoList(); for (size_t i = 0; i < file_system_info_list.size(); ++i) { const file_system_provider::ProvidedFileSystemInfo file_system_info = file_system_info_list[i]; file_system_provider::ProvidedFileSystemInterface* const file_system = service->GetProvidedFileSystem(file_system_info.extension_id(), file_system_info.file_system_id()); DCHECK(file_system); file_system_provider::RequestManager* const request_manager = file_system->GetRequestManager(); DCHECK(request_manager); base::DictionaryValue* item = new base::DictionaryValue(); item->SetString(kKeyId, file_system_info.file_system_id()); item->SetString(kKeyName, file_system_info.display_name()); item->SetString(kKeyExtensionId, file_system_info.extension_id()); item->SetString(kKeyMountPath, file_system_info.mount_path().AsUTF8Unsafe()); item->SetInteger(kKeyActiveRequests, request_manager->GetActiveRequestIds().size()); items.Append(item); } web_ui()->CallJavascriptFunction(kFunctionUpdateFileSystems, items); } void ProvidedFileSystemsWebUIHandler::SelectFileSystem( const base::ListValue* args) { DCHECK_CURRENTLY_ON(BrowserThread::UI); file_system_provider::Service* const service = GetService(); if (!service) return; std::string extension_id; if (!args->GetString(0, &extension_id)) return; std::string file_system_id; if (!args->GetString(1, &file_system_id)) return; // Stop observing the previously selected request manager. { file_system_provider::ProvidedFileSystemInterface* const file_system = service->GetProvidedFileSystem(selected_extension_id, selected_file_system_id); if (file_system) { file_system_provider::RequestManager* const request_manager = file_system->GetRequestManager(); DCHECK(request_manager); request_manager->RemoveObserver(this); } } // Observe the selected file system. file_system_provider::ProvidedFileSystemInterface* const file_system = service->GetProvidedFileSystem(extension_id, file_system_id); if (!file_system) return; file_system_provider::RequestManager* const request_manager = file_system->GetRequestManager(); DCHECK(request_manager); request_manager->AddObserver(this); selected_extension_id = extension_id; selected_file_system_id = file_system_id; } } // namespace ProvidedFileSystemsUI::ProvidedFileSystemsUI(content::WebUI* web_ui) : WebUIController(web_ui) { web_ui->AddMessageHandler(new ProvidedFileSystemsWebUIHandler()); content::WebUIDataSource* source = content::WebUIDataSource::Create( chrome::kChromeUIProvidedFileSystemsHost); source->AddResourcePath("provided_file_systems.css", IDR_PROVIDED_FILE_SYSTEMS_CSS); source->AddResourcePath("provided_file_systems.js", IDR_PROVIDED_FILE_SYSTEMS_JS); source->SetDefaultResource(IDR_PROVIDED_FILE_SYSTEMS_HTML); Profile* profile = Profile::FromWebUI(web_ui); content::WebUIDataSource::Add(profile, source); } } // namespace chromeos