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 41 const char kKeyName[] = "name"; 42 const char kKeyExtensionId[] = "extensionId"; 43 const char kKeyMountPath[] = "mountPath"; 44 const char kKeyActiveRequests[] = "activeRequests"; 45 46 const char kRequestCreated[] = "created"; 47 const char kRequestDestroyed[] = "destroyed"; 48 const char kRequestExecuted[] = "executed"; 49 const char kRequestFulfilled[] = "fulfilled"; 50 const char kRequestRejected[] = "rejected"; 51 const char kRequestTimeouted[] = "timeouted"; 52 53 const char kFunctionOnRequestEvent[] = "onRequestEvent"; 54 const char kFunctionUpdateFileSystems[] = "updateFileSystems"; 55 const char kFunctionSelectFileSystem[] = "selectFileSystem"; 56 57 // Creates a dictionary holding common fields for the onRequest* events. 58 scoped_ptr<base::DictionaryValue> CreateRequestEvent(const std::string& type, 59 int request_id) { 60 scoped_ptr<base::DictionaryValue> event(new base::DictionaryValue); 61 event->SetInteger(kKeyId, request_id); 62 event->SetString(kKeyEventType, type); 63 event->SetDouble(kKeyTime, base::Time::Now().ToJsTime()); 64 return event.Pass(); 65 } 66 67 // Class to handle messages from chrome://provided-file-systems. 68 class ProvidedFileSystemsWebUIHandler 69 : public content::WebUIMessageHandler, 70 public file_system_provider::RequestManager::Observer { 71 public: 72 ProvidedFileSystemsWebUIHandler() : weak_ptr_factory_(this) {} 73 74 virtual ~ProvidedFileSystemsWebUIHandler(); 75 76 // RequestManager::Observer overrides. 77 virtual void OnRequestCreated( 78 int request_id, 79 file_system_provider::RequestType type) OVERRIDE; 80 virtual void OnRequestDestroyed(int request_id) OVERRIDE; 81 virtual void OnRequestExecuted(int request_id) OVERRIDE; 82 virtual void OnRequestFulfilled(int request_id, bool has_more) OVERRIDE; 83 virtual void OnRequestRejected(int request_id, 84 base::File::Error error) OVERRIDE; 85 virtual void OnRequestTimeouted(int request_id) OVERRIDE; 86 87 private: 88 // content::WebUIMessageHandler overrides. 89 virtual void RegisterMessages() OVERRIDE; 90 91 // Gets a file system provider service for the current profile. If not found, 92 // then NULL. 93 file_system_provider::Service* GetService(); 94 95 // Invoked when updating file system list is requested. 96 void UpdateFileSystems(const base::ListValue* args); 97 98 // Invoked when a file system is selected from the list. 99 void SelectFileSystem(const base::ListValue* args); 100 101 std::string selected_extension_id; 102 std::string selected_file_system_id; 103 base::WeakPtrFactory<ProvidedFileSystemsWebUIHandler> weak_ptr_factory_; 104 105 DISALLOW_COPY_AND_ASSIGN(ProvidedFileSystemsWebUIHandler); 106 }; 107 108 ProvidedFileSystemsWebUIHandler::~ProvidedFileSystemsWebUIHandler() { 109 // Stop observing the currently selected file system. 110 file_system_provider::Service* const service = GetService(); 111 if (!service) 112 return; 113 114 file_system_provider::ProvidedFileSystemInterface* const file_system = 115 service->GetProvidedFileSystem(selected_extension_id, 116 selected_file_system_id); 117 118 if (file_system) { 119 file_system_provider::RequestManager* const request_manager = 120 file_system->GetRequestManager(); 121 DCHECK(request_manager); 122 request_manager->RemoveObserver(this); 123 } 124 } 125 126 void ProvidedFileSystemsWebUIHandler::OnRequestCreated( 127 int request_id, 128 file_system_provider::RequestType type) { 129 scoped_ptr<base::DictionaryValue> const event = 130 CreateRequestEvent(kRequestCreated, request_id); 131 event->SetString(kKeyRequestType, 132 file_system_provider::RequestTypeToString(type)); 133 web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); 134 } 135 136 void ProvidedFileSystemsWebUIHandler::OnRequestDestroyed(int request_id) { 137 scoped_ptr<base::DictionaryValue> const event = 138 CreateRequestEvent(kRequestDestroyed, request_id); 139 web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); 140 } 141 142 void ProvidedFileSystemsWebUIHandler::OnRequestExecuted(int request_id) { 143 scoped_ptr<base::DictionaryValue> const event = 144 CreateRequestEvent(kRequestExecuted, request_id); 145 web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); 146 } 147 148 void ProvidedFileSystemsWebUIHandler::OnRequestFulfilled(int request_id, 149 bool has_more) { 150 scoped_ptr<base::DictionaryValue> const event = 151 CreateRequestEvent(kRequestFulfilled, request_id); 152 event->SetBoolean(kKeyHasMore, has_more); 153 web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); 154 } 155 156 void ProvidedFileSystemsWebUIHandler::OnRequestRejected( 157 int request_id, 158 base::File::Error error) { 159 scoped_ptr<base::DictionaryValue> const event = 160 CreateRequestEvent(kRequestRejected, request_id); 161 event->SetString(kKeyError, base::File::ErrorToString(error)); 162 web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); 163 } 164 165 void ProvidedFileSystemsWebUIHandler::OnRequestTimeouted(int request_id) { 166 scoped_ptr<base::DictionaryValue> const event = 167 CreateRequestEvent(kRequestTimeouted, request_id); 168 web_ui()->CallJavascriptFunction(kFunctionOnRequestEvent, *event); 169 } 170 171 void ProvidedFileSystemsWebUIHandler::RegisterMessages() { 172 web_ui()->RegisterMessageCallback( 173 kFunctionUpdateFileSystems, 174 base::Bind(&ProvidedFileSystemsWebUIHandler::UpdateFileSystems, 175 weak_ptr_factory_.GetWeakPtr())); 176 web_ui()->RegisterMessageCallback( 177 kFunctionSelectFileSystem, 178 base::Bind(&ProvidedFileSystemsWebUIHandler::SelectFileSystem, 179 weak_ptr_factory_.GetWeakPtr())); 180 } 181 182 file_system_provider::Service* ProvidedFileSystemsWebUIHandler::GetService() { 183 DCHECK_CURRENTLY_ON(BrowserThread::UI); 184 185 Profile* const profile = Profile::FromWebUI(web_ui()); 186 return file_system_provider::ServiceFactory::FindExisting(profile); 187 } 188 189 void ProvidedFileSystemsWebUIHandler::UpdateFileSystems( 190 const base::ListValue* args) { 191 DCHECK_CURRENTLY_ON(BrowserThread::UI); 192 193 file_system_provider::Service* const service = GetService(); 194 if (!service) 195 return; 196 197 base::ListValue items; 198 199 const std::vector<file_system_provider::ProvidedFileSystemInfo> 200 file_system_info_list = service->GetProvidedFileSystemInfoList(); 201 202 for (size_t i = 0; i < file_system_info_list.size(); ++i) { 203 const file_system_provider::ProvidedFileSystemInfo file_system_info = 204 file_system_info_list[i]; 205 206 file_system_provider::ProvidedFileSystemInterface* const file_system = 207 service->GetProvidedFileSystem(file_system_info.extension_id(), 208 file_system_info.file_system_id()); 209 DCHECK(file_system); 210 211 file_system_provider::RequestManager* const request_manager = 212 file_system->GetRequestManager(); 213 DCHECK(request_manager); 214 215 base::DictionaryValue* item = new base::DictionaryValue(); 216 item->SetString(kKeyId, file_system_info.file_system_id()); 217 item->SetString(kKeyName, file_system_info.file_system_name()); 218 item->SetString(kKeyExtensionId, file_system_info.extension_id()); 219 item->SetString(kKeyMountPath, 220 file_system_info.mount_path().AsUTF8Unsafe()); 221 item->SetInteger(kKeyActiveRequests, 222 request_manager->GetActiveRequestsForLogging()); 223 224 items.Append(item); 225 } 226 227 web_ui()->CallJavascriptFunction(kFunctionUpdateFileSystems, items); 228 } 229 230 void ProvidedFileSystemsWebUIHandler::SelectFileSystem( 231 const base::ListValue* args) { 232 DCHECK_CURRENTLY_ON(BrowserThread::UI); 233 234 file_system_provider::Service* const service = GetService(); 235 if (!service) 236 return; 237 238 std::string extension_id; 239 if (!args->GetString(0, &extension_id)) 240 return; 241 242 std::string file_system_id; 243 if (!args->GetString(1, &file_system_id)) 244 return; 245 246 // Stop observing the previously selected request manager. 247 { 248 file_system_provider::ProvidedFileSystemInterface* const file_system = 249 service->GetProvidedFileSystem(selected_extension_id, 250 selected_file_system_id); 251 if (file_system) { 252 file_system_provider::RequestManager* const request_manager = 253 file_system->GetRequestManager(); 254 DCHECK(request_manager); 255 request_manager->RemoveObserver(this); 256 } 257 } 258 259 // Observe the selected file system. 260 file_system_provider::ProvidedFileSystemInterface* const file_system = 261 service->GetProvidedFileSystem(extension_id, file_system_id); 262 if (!file_system) 263 return; 264 265 file_system_provider::RequestManager* const request_manager = 266 file_system->GetRequestManager(); 267 DCHECK(request_manager); 268 269 request_manager->AddObserver(this); 270 selected_extension_id = extension_id; 271 selected_file_system_id = file_system_id; 272 } 273 274 } // namespace 275 276 ProvidedFileSystemsUI::ProvidedFileSystemsUI(content::WebUI* web_ui) 277 : WebUIController(web_ui) { 278 web_ui->AddMessageHandler(new ProvidedFileSystemsWebUIHandler()); 279 280 content::WebUIDataSource* source = content::WebUIDataSource::Create( 281 chrome::kChromeUIProvidedFileSystemsHost); 282 source->AddResourcePath("provided_file_systems.css", 283 IDR_PROVIDED_FILE_SYSTEMS_CSS); 284 source->AddResourcePath("provided_file_systems.js", 285 IDR_PROVIDED_FILE_SYSTEMS_JS); 286 source->SetDefaultResource(IDR_PROVIDED_FILE_SYSTEMS_HTML); 287 288 Profile* profile = Profile::FromWebUI(web_ui); 289 content::WebUIDataSource::Add(profile, source); 290 } 291 292 } // namespace chromeos 293