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