12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/drive/change_list_loader.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <set> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h" 1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/callback_helpers.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/time/time.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/drive/change_list_loader_observer.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/drive/change_list_processor.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_system_util.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/drive/job_scheduler.h" 18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chrome/browser/chromeos/drive/resource_metadata.h" 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/drive/event_logger.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h" 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/drive_api_parser.h" 227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread; 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace drive { 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace internal { 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)typedef base::Callback<void(FileError, ScopedVector<ChangeList>)> 3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) FeedFetcherCallback; 3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class ChangeListLoader::FeedFetcher { 3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public: 3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual ~FeedFetcher() {} 3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual void Run(const FeedFetcherCallback& callback) = 0; 3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}; 3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace { 3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Fetches all the (currently available) resource entries from the server. 4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class FullFeedFetcher : public ChangeListLoader::FeedFetcher { 4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public: 4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) explicit FullFeedFetcher(JobScheduler* scheduler) 4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) : scheduler_(scheduler), 4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) weak_ptr_factory_(this) { 4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual ~FullFeedFetcher() { 4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual void Run(const FeedFetcherCallback& callback) OVERRIDE { 5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(!callback.is_null()); 5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Remember the time stamp for usage stats. 5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) start_time_ = base::TimeTicks::Now(); 5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // This is full resource list fetch. 5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) scheduler_->GetAllFileList( 6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Bind(&FullFeedFetcher::OnFileListFetched, 6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), callback)); 6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private: 6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) void OnFileListFetched(const FeedFetcherCallback& callback, 6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) google_apis::GDataErrorCode status, 6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) scoped_ptr<google_apis::FileList> file_list) { 6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(!callback.is_null()); 7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) FileError error = GDataToFileError(status); 7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (error != FILE_ERROR_OK) { 7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) callback.Run(error, ScopedVector<ChangeList>()); 7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) DCHECK(file_list); 7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) change_lists_.push_back(new ChangeList(*file_list)); 7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!file_list->next_link().is_empty()) { 8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // There is the remaining result so fetch it. 8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) scheduler_->GetRemainingFileList( 8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) file_list->next_link(), 8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Bind(&FullFeedFetcher::OnFileListFetched, 8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), callback)); 8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) UMA_HISTOGRAM_LONG_TIMES("Drive.FullFeedLoadTime", 90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::TimeTicks::Now() - start_time_); 9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Note: The fetcher is managed by ChangeListLoader, and the instance 9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // will be deleted in the callback. Do not touch the fields after this 9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // invocation. 9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) callback.Run(FILE_ERROR_OK, change_lists_.Pass()); 9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) JobScheduler* scheduler_; 9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ScopedVector<ChangeList> change_lists_; 10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::TimeTicks start_time_; 10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::WeakPtrFactory<FullFeedFetcher> weak_ptr_factory_; 10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(FullFeedFetcher); 10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}; 10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Fetches the delta changes since |start_change_id|. 10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class DeltaFeedFetcher : public ChangeListLoader::FeedFetcher { 10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public: 10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DeltaFeedFetcher(JobScheduler* scheduler, int64 start_change_id) 10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) : scheduler_(scheduler), 11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) start_change_id_(start_change_id), 11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) weak_ptr_factory_(this) { 11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual ~DeltaFeedFetcher() { 11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) virtual void Run(const FeedFetcherCallback& callback) OVERRIDE { 11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(!callback.is_null()); 12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) scheduler_->GetChangeList( 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) start_change_id_, 12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Bind(&DeltaFeedFetcher::OnChangeListFetched, 12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), callback)); 12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private: 12846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) void OnChangeListFetched(const FeedFetcherCallback& callback, 12946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) google_apis::GDataErrorCode status, 13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) scoped_ptr<google_apis::ChangeList> change_list) { 13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(!callback.is_null()); 13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) FileError error = GDataToFileError(status); 13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (error != FILE_ERROR_OK) { 13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) callback.Run(error, ScopedVector<ChangeList>()); 13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) DCHECK(change_list); 14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) change_lists_.push_back(new ChangeList(*change_list)); 14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!change_list->next_link().is_empty()) { 14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // There is the remaining result so fetch it. 14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) scheduler_->GetRemainingChangeList( 14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) change_list->next_link(), 14758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Bind(&DeltaFeedFetcher::OnChangeListFetched, 14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), callback)); 14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 15158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Note: The fetcher is managed by ChangeListLoader, and the instance 15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // will be deleted in the callback. Do not touch the fields after this 15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // invocation. 15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) callback.Run(FILE_ERROR_OK, change_lists_.Pass()); 15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) JobScheduler* scheduler_; 15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) int64 start_change_id_; 16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ScopedVector<ChangeList> change_lists_; 16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::WeakPtrFactory<DeltaFeedFetcher> weak_ptr_factory_; 16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DeltaFeedFetcher); 16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}; 16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} // namespace 16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)LoaderController::LoaderController() 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : lock_count_(0), 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_(this) { 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)LoaderController::~LoaderController() { 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<base::ScopedClosureRunner> LoaderController::GetLock() { 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++lock_count_; 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return make_scoped_ptr(new base::ScopedClosureRunner( 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&LoaderController::Unlock, 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr()))); 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void LoaderController::ScheduleRun(const base::Closure& task) { 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(!task.is_null()); 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (lock_count_ > 0) { 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pending_tasks_.push_back(task); 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) task.Run(); 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void LoaderController::Unlock() { 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK_LT(0, lock_count_); 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (--lock_count_ > 0) 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<base::Closure> tasks; 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tasks.swap(pending_tasks_); 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < tasks.size(); ++i) 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) tasks[i].Run(); 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AboutResourceLoader::AboutResourceLoader(JobScheduler* scheduler) 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : scheduler_(scheduler), 2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_update_task_id_(-1), 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_(this) { 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AboutResourceLoader::~AboutResourceLoader() {} 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AboutResourceLoader::GetAboutResource( 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const google_apis::AboutResourceCallback& callback) { 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(!callback.is_null()); 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If the latest UpdateAboutResource task is still running. Wait for it, 2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (pending_callbacks_.count(current_update_task_id_)) { 2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pending_callbacks_[current_update_task_id_].push_back(callback); 2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (cached_about_resource_) { 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::MessageLoopProxy::current()->PostTask( 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind( 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback, 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) google_apis::HTTP_NO_CONTENT, 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Passed(scoped_ptr<google_apis::AboutResource>( 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) new google_apis::AboutResource(*cached_about_resource_))))); 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UpdateAboutResource(callback); 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AboutResourceLoader::UpdateAboutResource( 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const google_apis::AboutResourceCallback& callback) { 2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(!callback.is_null()); 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++current_update_task_id_; 2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pending_callbacks_[current_update_task_id_].push_back(callback); 2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scheduler_->GetAboutResource( 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&AboutResourceLoader::UpdateAboutResourceAfterGetAbout, 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) current_update_task_id_)); 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AboutResourceLoader::UpdateAboutResourceAfterGetAbout( 2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int task_id, 2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) google_apis::GDataErrorCode status, 2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<google_apis::AboutResource> about_resource) { 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FileError error = GDataToFileError(status); 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::vector<google_apis::AboutResourceCallback> callbacks = 2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pending_callbacks_[task_id]; 2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pending_callbacks_.erase(task_id); 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (error != FILE_ERROR_OK) { 2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < callbacks.size(); ++i) 2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) callbacks[i].Run(status, scoped_ptr<google_apis::AboutResource>()); 2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Updates the cache when the resource is successfully obtained. 2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (cached_about_resource_ && 2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cached_about_resource_->largest_change_id() > 2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) about_resource->largest_change_id()) { 2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(WARNING) << "Local cached about resource is fresher than server, " 2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << "local = " << cached_about_resource_->largest_change_id() 2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << ", server = " << about_resource->largest_change_id(); 2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) cached_about_resource_.reset(new google_apis::AboutResource(*about_resource)); 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < callbacks.size(); ++i) { 2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) callbacks[i].Run( 2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) status, 2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) make_scoped_ptr(new google_apis::AboutResource(*about_resource))); 2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ChangeListLoader::ChangeListLoader( 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EventLogger* logger, 29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::SequencedTaskRunner* blocking_task_runner, 29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ResourceMetadata* resource_metadata, 29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) JobScheduler* scheduler, 2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AboutResourceLoader* about_resource_loader, 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LoaderController* loader_controller) 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : logger_(logger), 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) blocking_task_runner_(blocking_task_runner), 29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) resource_metadata_(resource_metadata), 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scheduler_(scheduler), 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) about_resource_loader_(about_resource_loader), 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) loader_controller_(loader_controller), 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) loaded_(false), 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_(this) { 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChangeListLoader::~ChangeListLoader() { 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ChangeListLoader::IsRefreshing() const { 311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Callback for change list loading is stored in pending_load_callback_. 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // It is non-empty if and only if there is an in-flight loading operation. 313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return !pending_load_callback_.empty(); 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChangeListLoader::AddObserver(ChangeListLoaderObserver* observer) { 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChangeListLoader::RemoveObserver(ChangeListLoaderObserver* observer) { 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ChangeListLoader::CheckForUpdates(const FileOperationCallback& callback) { 327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!callback.is_null()); 329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // We only start to check for updates iff the load is done. 3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // I.e., we ignore checking updates if not loaded to avoid starting the 3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // load without user's explicit interaction (such as opening Drive). 3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!loaded_ && !IsRefreshing()) 3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // For each CheckForUpdates() request, always refresh the changestamp info. 3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) about_resource_loader_->UpdateAboutResource( 3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&ChangeListLoader::OnAboutResourceUpdated, 3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (IsRefreshing()) { 34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // There is in-flight loading. So keep the callback here, and check for 34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // updates when the in-flight loading is completed. 34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pending_update_check_callback_ = callback; 34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(loaded_); 3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) logger_->Log(logging::LOG_INFO, "Checking for updates"); 3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Load(callback); 3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ChangeListLoader::LoadIfNeeded(const FileOperationCallback& callback) { 3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(!callback.is_null()); 3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If the metadata is not yet loaded, start loading. 3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!loaded_ && !IsRefreshing()) 359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Load(callback); 360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 362a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ChangeListLoader::Load(const FileOperationCallback& callback) { 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!callback.is_null()); 365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Check if this is the first time this ChangeListLoader do loading. 367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Note: IsRefreshing() depends on pending_load_callback_ so check in advance. 368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const bool is_initial_load = (!loaded_ && !IsRefreshing()); 369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Register the callback function to be called when it is loaded. 371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pending_load_callback_.push_back(callback); 372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If loading task is already running, do nothing. 374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (pending_load_callback_.size() > 1) 375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Check the current status of local metadata, and start loading if needed. 378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int64* local_changestamp = new int64(0); 379d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::PostTaskAndReplyWithResult( 3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci blocking_task_runner_.get(), 381d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) FROM_HERE, 382d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Bind(&ResourceMetadata::GetLargestChangestamp, 383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Unretained(resource_metadata_), 384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) local_changestamp), 3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&ChangeListLoader::LoadAfterGetLargestChangestamp, 386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) is_initial_load, 388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Owned(local_changestamp))); 389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ChangeListLoader::LoadAfterGetLargestChangestamp( 392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool is_initial_load, 393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int64* local_changestamp, 394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FileError error) { 395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (error != FILE_ERROR_OK) { 398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) OnChangeListLoadComplete(error); 399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (is_initial_load && *local_changestamp > 0) { 403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The local data is usable. Flush callbacks to tell loading was successful. 404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OnChangeListLoadComplete(FILE_ERROR_OK); 405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Continues to load from server in background. 407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Put dummy callbacks to indicate that fetching is still continuing. 408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pending_load_callback_.push_back( 409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::Bind(&util::EmptyFileOperationCallback)); 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) about_resource_loader_->GetAboutResource( 413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Bind(&ChangeListLoader::LoadAfterGetAboutResource, 414a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *local_changestamp)); 4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChangeListLoader::LoadAfterGetAboutResource( 4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int64 local_changestamp, 4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) google_apis::GDataErrorCode status, 4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<google_apis::AboutResource> about_resource) { 4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FileError error = GDataToFileError(status); 4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (error != FILE_ERROR_OK) { 426a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OnChangeListLoadComplete(error); 4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(about_resource); 4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int64 remote_changestamp = about_resource->largest_change_id(); 4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int64 start_changestamp = local_changestamp > 0 ? local_changestamp + 1 : 0; 434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (local_changestamp >= remote_changestamp) { 435a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (local_changestamp > remote_changestamp) { 436a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) LOG(WARNING) << "Local resource metadata is fresher than server, " 437a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << "local = " << local_changestamp 438a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << ", server = " << remote_changestamp; 4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 441a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // No changes detected, tell the client that the loading was successful. 442a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OnChangeListLoadComplete(FILE_ERROR_OK); 4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 444a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Start loading the change list. 4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LoadChangeListFromServer(start_changestamp); 446a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ChangeListLoader::OnChangeListLoadComplete(FileError error) { 450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!loaded_ && error == FILE_ERROR_OK) { 453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) loaded_ = true; 454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FOR_EACH_OBSERVER(ChangeListLoaderObserver, 455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) observers_, 456868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) OnInitialLoadComplete()); 457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 459a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 0; i < pending_load_callback_.size(); ++i) { 460a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::MessageLoopProxy::current()->PostTask( 461a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FROM_HERE, 462a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Bind(pending_load_callback_[i], error)); 463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) pending_load_callback_.clear(); 46590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 46690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // If there is pending update check, try to load the change from the server 46790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // again, because there may exist an update during the completed loading. 46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!pending_update_check_callback_.is_null()) { 469a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Load(base::ResetAndReturn(&pending_update_check_callback_)); 470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChangeListLoader::OnAboutResourceUpdated( 4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) google_apis::GDataErrorCode error, 4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_ptr<google_apis::AboutResource> resource) { 4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (drive::GDataToFileError(error) != drive::FILE_ERROR_OK) { 4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) logger_->Log(logging::LOG_ERROR, 4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "Failed to update the about resource: %s", 4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) google_apis::GDataErrorCodeToString(error).c_str()); 4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return; 4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) logger_->Log(logging::LOG_INFO, 4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "About resource updated to: %s", 4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Int64ToString(resource->largest_change_id()).c_str()); 4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChangeListLoader::LoadChangeListFromServer(int64 start_changestamp) { 4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 49158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(!change_feed_fetcher_); 4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(about_resource_loader_->cached_about_resource()); 493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 494868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool is_delta_update = start_changestamp != 0; 49558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 49658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Set up feed fetcher. 497868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (is_delta_update) { 49858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) change_feed_fetcher_.reset( 49958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) new DeltaFeedFetcher(scheduler_, start_changestamp)); 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 50158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) change_feed_fetcher_.reset(new FullFeedFetcher(scheduler_)); 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Make a copy of cached_about_resource_ to remember at which changestamp we 5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // are fetching change list. 50658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) change_feed_fetcher_->Run( 50758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Bind(&ChangeListLoader::LoadChangeListFromServerAfterLoadChangeList, 50858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Passed(make_scoped_ptr(new google_apis::AboutResource( 5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *about_resource_loader_->cached_about_resource()))), 51158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) is_delta_update)); 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ChangeListLoader::LoadChangeListFromServerAfterLoadChangeList( 515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<google_apis::AboutResource> about_resource, 516868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool is_delta_update, 51758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) FileError error, 51858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ScopedVector<ChangeList> change_lists) { 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 5204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK(about_resource); 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Delete the fetcher first. 52358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) change_feed_fetcher_.reset(); 52458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (error != FILE_ERROR_OK) { 526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OnChangeListLoadComplete(error); 527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ChangeListProcessor* change_list_processor = 5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) new ChangeListProcessor(resource_metadata_); 5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Don't send directory content change notification while performing 5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // the initial content retrieval. 5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const bool should_notify_changed_directories = is_delta_update; 5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) logger_->Log(logging::LOG_INFO, 5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Apply change lists (is delta: %d)", 5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) is_delta_update); 5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) loader_controller_->ScheduleRun(base::Bind( 5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::IgnoreResult( 5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &base::PostTaskAndReplyWithResult<FileError, FileError>), 5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) blocking_task_runner_, 5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&ChangeListProcessor::Apply, 5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(change_list_processor), 5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Passed(&about_resource), 5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Passed(&change_lists), 5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) is_delta_update), 549868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Bind(&ChangeListLoader::LoadChangeListFromServerAfterUpdate, 5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Owned(change_list_processor), 5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) should_notify_changed_directories, 5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Time::Now()))); 5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChangeListLoader::LoadChangeListFromServerAfterUpdate( 5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ChangeListProcessor* change_list_processor, 5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool should_notify_changed_directories, 5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Time& start_time, 5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FileError error) { 5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeDelta elapsed = base::Time::Now() - start_time; 5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) logger_->Log(logging::LOG_INFO, 5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Change lists applied (elapsed time: %sms)", 5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Int64ToString(elapsed.InMilliseconds()).c_str()); 5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (should_notify_changed_directories) { 569116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch FOR_EACH_OBSERVER(ChangeListLoaderObserver, 570116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch observers_, 571116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch OnFileChanged(change_list_processor->changed_files())); 5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OnChangeListLoadComplete(error); 575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FOR_EACH_OBSERVER(ChangeListLoaderObserver, 577c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) observers_, 578868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) OnLoadFromServerComplete()); 5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 58190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace internal 5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace drive 583