| // 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 <string> |
| #include <vector> |
| |
| #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<base::DictionaryValue> CreateRequestEvent(const std::string& type, |
| int request_id) { |
| scoped_ptr<base::DictionaryValue> 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) {} |
| |
| ~ProvidedFileSystemsWebUIHandler() override; |
| |
| // RequestManager::Observer overrides. |
| void OnRequestCreated(int request_id, |
| file_system_provider::RequestType type) override; |
| void OnRequestDestroyed(int request_id) override; |
| void OnRequestExecuted(int request_id) override; |
| void OnRequestFulfilled(int request_id, |
| const file_system_provider::RequestValue& result, |
| bool has_more) override; |
| void OnRequestRejected(int request_id, |
| const file_system_provider::RequestValue& result, |
| base::File::Error error) override; |
| void OnRequestTimeouted(int request_id) override; |
| |
| private: |
| // content::WebUIMessageHandler overrides. |
| 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<ProvidedFileSystemsWebUIHandler> 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<base::DictionaryValue> 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<base::DictionaryValue> const event = |
| CreateRequestEvent(kRequestDestroyed, request_id); |
| web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); |
| } |
| |
| void ProvidedFileSystemsWebUIHandler::OnRequestExecuted(int request_id) { |
| scoped_ptr<base::DictionaryValue> 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<base::DictionaryValue> 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<base::DictionaryValue> 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<base::DictionaryValue> 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_provider::ProvidedFileSystemInfo> |
| 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 |