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/local_discovery/storage/privet_filesystem_operations.h" 6 7 #include "chrome/browser/local_discovery/storage/privet_filesystem_constants.h" 8 9 namespace local_discovery { 10 11 PrivetFileSystemOperationFactory::PrivetFileSystemOperationFactory( 12 content::BrowserContext* browser_context) 13 : browser_context_(browser_context), weak_factory_(this) {} 14 15 PrivetFileSystemOperationFactory::~PrivetFileSystemOperationFactory() { 16 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 17 RemoveAllOperations(); 18 } 19 20 void PrivetFileSystemOperationFactory::GetFileInfo( 21 const fileapi::FileSystemURL& url, 22 const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) { 23 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 24 PrivetFileSystemAsyncOperation* operation = 25 new PrivetFileSystemDetailsOperation( 26 url.path(), browser_context_, this, &attribute_cache_, callback); 27 async_operations_.insert(operation); 28 operation->Start(); 29 } 30 31 void PrivetFileSystemOperationFactory::ReadDirectory( 32 const fileapi::FileSystemURL& url, 33 const fileapi::AsyncFileUtil::ReadDirectoryCallback& callback) { 34 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 35 PrivetFileSystemAsyncOperation* operation = new PrivetFileSystemListOperation( 36 url.path(), browser_context_, this, &attribute_cache_, callback); 37 async_operations_.insert(operation); 38 operation->Start(); 39 } 40 41 void PrivetFileSystemOperationFactory::RemoveOperation( 42 PrivetFileSystemAsyncOperation* operation) { 43 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 44 async_operations_.erase(operation); 45 delete operation; 46 } 47 48 void PrivetFileSystemOperationFactory::RemoveAllOperations() { 49 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 50 STLDeleteElements(&async_operations_); 51 } 52 53 PrivetFileSystemAsyncOperationUtil::PrivetFileSystemAsyncOperationUtil( 54 const base::FilePath& full_path, 55 content::BrowserContext* browser_context, 56 Delegate* delegate) 57 : parsed_path_(full_path), 58 browser_context_(browser_context), 59 delegate_(delegate), 60 weak_factory_(this) { 61 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 62 } 63 64 PrivetFileSystemAsyncOperationUtil::~PrivetFileSystemAsyncOperationUtil() { 65 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 66 } 67 68 void PrivetFileSystemAsyncOperationUtil::Start() { 69 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 70 request_context_ = browser_context_->GetRequestContext(); 71 service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance(); 72 privet_device_resolver_.reset(new PrivetDeviceResolver( 73 service_discovery_client_.get(), 74 parsed_path_.service_name, 75 base::Bind( 76 &PrivetFileSystemAsyncOperationUtil::OnGotDeviceDescription, 77 base::Unretained(this)))); 78 privet_device_resolver_->Start(); 79 } 80 81 void PrivetFileSystemAsyncOperationUtil::OnGotDeviceDescription( 82 bool success, const DeviceDescription& device_description) { 83 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 84 if (!success) { 85 delegate_->PrivetFileSystemResolved(NULL, parsed_path_.path); 86 return; 87 } 88 89 privet_async_factory_ = PrivetHTTPAsynchronousFactory::CreateInstance( 90 service_discovery_client_.get(), request_context_.get()); 91 privet_http_resolution_ = privet_async_factory_->CreatePrivetHTTP( 92 parsed_path_.service_name, 93 device_description.address, 94 base::Bind(&PrivetFileSystemAsyncOperationUtil::OnGotPrivetHTTP, 95 base::Unretained(this))); 96 privet_http_resolution_->Start(); 97 } 98 99 void PrivetFileSystemAsyncOperationUtil::OnGotPrivetHTTP( 100 scoped_ptr<PrivetHTTPClient> privet_http_client) { 101 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 102 privet_client_ = PrivetV1HTTPClient::CreateDefault(privet_http_client.Pass()); 103 delegate_->PrivetFileSystemResolved(privet_client_.get(), 104 parsed_path_.path); 105 } 106 107 PrivetFileSystemListOperation::PrivetFileSystemListOperation( 108 const base::FilePath& full_path, 109 content::BrowserContext* browser_context, 110 PrivetFileSystemAsyncOperationContainer* container, 111 PrivetFileSystemAttributeCache* attribute_cache, 112 const fileapi::AsyncFileUtil::ReadDirectoryCallback& callback) 113 : core_(full_path, browser_context, this), 114 full_path_(full_path), 115 container_(container), 116 attribute_cache_(attribute_cache), 117 callback_(callback) { 118 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 119 } 120 121 PrivetFileSystemListOperation::~PrivetFileSystemListOperation() { 122 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 123 } 124 125 void PrivetFileSystemListOperation::Start() { 126 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 127 core_.Start(); 128 } 129 130 void PrivetFileSystemListOperation::PrivetFileSystemResolved( 131 PrivetV1HTTPClient* http_client, 132 const std::string& path) { 133 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 134 if (!http_client) { 135 SignalError(); 136 return; 137 } 138 139 list_operation_ = http_client->CreateStorageListOperation( 140 path, 141 base::Bind(&PrivetFileSystemListOperation::OnStorageListResult, 142 base::Unretained(this))); 143 list_operation_->Start(); 144 } 145 146 void PrivetFileSystemListOperation::OnStorageListResult( 147 const base::DictionaryValue* value) { 148 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 149 list_operation_.reset(); 150 151 if (!value) { 152 SignalError(); 153 return; 154 } 155 156 attribute_cache_->AddFileInfoFromJSON(full_path_, value); 157 158 fileapi::AsyncFileUtil::EntryList entry_list; 159 160 const base::ListValue* entries; 161 if (!value->GetList(kPrivetListEntries, &entries)) { 162 SignalError(); 163 return; 164 } 165 166 for (size_t i = 0; i < entries->GetSize(); i++) { 167 const base::DictionaryValue* entry_value; 168 if (!entries->GetDictionary(i, &entry_value)) { 169 SignalError(); 170 return; 171 } 172 173 std::string name; 174 std::string type; 175 int size = 0; 176 177 entry_value->GetString(kPrivetListKeyName, &name); 178 entry_value->GetString(kPrivetListKeyType, &type); 179 entry_value->GetInteger(kPrivetListKeySize, &size); 180 181 fileapi::DirectoryEntry entry( 182 name, 183 (type == kPrivetListTypeDir) ? 184 fileapi::DirectoryEntry::DIRECTORY : fileapi::DirectoryEntry::FILE, 185 size, 186 base::Time() /* TODO(noamsml) */); 187 188 entry_list.push_back(entry); 189 } 190 191 TriggerCallbackAndDestroy(base::File::FILE_OK, entry_list, false); 192 } 193 194 void PrivetFileSystemListOperation::SignalError() { 195 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 196 TriggerCallbackAndDestroy(base::File::FILE_ERROR_FAILED, 197 fileapi::AsyncFileUtil::EntryList(), 198 false); 199 } 200 201 void PrivetFileSystemListOperation::TriggerCallbackAndDestroy( 202 base::File::Error result, 203 const fileapi::AsyncFileUtil::EntryList& file_list, 204 bool has_more) { 205 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 206 content::BrowserThread::PostTask( 207 content::BrowserThread::IO, 208 FROM_HERE, 209 base::Bind(callback_, result, file_list, has_more)); 210 container_->RemoveOperation(this); 211 } 212 213 PrivetFileSystemDetailsOperation::PrivetFileSystemDetailsOperation( 214 const base::FilePath& full_path, 215 content::BrowserContext* browser_context, 216 PrivetFileSystemAsyncOperationContainer* container, 217 PrivetFileSystemAttributeCache* attribute_cache, 218 const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) 219 : core_(full_path, browser_context, this), 220 full_path_(full_path), 221 container_(container), 222 attribute_cache_(attribute_cache), 223 callback_(callback) { 224 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 225 } 226 227 PrivetFileSystemDetailsOperation::~PrivetFileSystemDetailsOperation() { 228 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 229 } 230 231 void PrivetFileSystemDetailsOperation::Start() { 232 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 233 const base::File::Info* info = attribute_cache_->GetFileInfo(full_path_); 234 if (info) { 235 TriggerCallbackAndDestroy(base::File::FILE_OK, *info); 236 return; 237 } 238 239 core_.Start(); 240 } 241 242 void PrivetFileSystemDetailsOperation::PrivetFileSystemResolved( 243 PrivetV1HTTPClient* http_client, 244 const std::string& path) { 245 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 246 if (!http_client) { 247 SignalError(); 248 return; 249 } 250 251 list_operation_ = http_client->CreateStorageListOperation( 252 path, 253 base::Bind(&PrivetFileSystemDetailsOperation::OnStorageListResult, 254 base::Unretained(this))); 255 list_operation_->Start(); 256 } 257 258 void PrivetFileSystemDetailsOperation::OnStorageListResult( 259 const base::DictionaryValue* value) { 260 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 261 list_operation_.reset(); 262 263 attribute_cache_->AddFileInfoFromJSON(full_path_, value); 264 const base::File::Info* info = attribute_cache_->GetFileInfo(full_path_); 265 266 if (info) { 267 TriggerCallbackAndDestroy(base::File::FILE_OK, *info); 268 } else { 269 SignalError(); 270 } 271 } 272 273 void PrivetFileSystemDetailsOperation::SignalError() { 274 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 275 TriggerCallbackAndDestroy(base::File::FILE_ERROR_FAILED, base::File::Info()); 276 } 277 278 void PrivetFileSystemDetailsOperation::TriggerCallbackAndDestroy( 279 base::File::Error result, 280 const base::File::Info& info) { 281 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 282 content::BrowserThread::PostTask(content::BrowserThread::IO, 283 FROM_HERE, 284 base::Bind(callback_, result, info)); 285 container_->RemoveOperation(this); 286 } 287 288 } // namespace local_discovery 289