Home | History | Annotate | Download | only in storage
      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