// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_ #define CHROME_BROWSER_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_ #include #include #include #include #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "base/observer_list.h" #include "base/time/time.h" #include "chrome/browser/chromeos/drive/file_errors.h" #include "chrome/browser/google_apis/gdata_errorcode.h" class GURL; namespace base { class SequencedTaskRunner; } // namespace base namespace google_apis { class AboutResource; class ResourceList; } // namespace google_apis namespace drive { class DriveServiceInterface; class JobScheduler; class ResourceEntry; namespace internal { class ChangeList; class ChangeListLoaderObserver; class ChangeListProcessor; class DirectoryFetchInfo; class ResourceMetadata; // Callback run as a response to SearchFromServer. typedef base::Callback change_lists, FileError error)> LoadChangeListCallback; // ChangeListLoader is used to load the change list, the full resource list, // and directory contents, from WAPI (codename for Documents List API) // or Google Drive API. The class also updates the resource metadata with // the change list loaded from the server. // // Note that the difference between "resource list" and "change list" is // subtle hence the two words are often used interchangeably. To be precise, // "resource list" refers to metadata from the server when fetching the full // resource metadata, or fetching directory contents, whereas "change list" // refers to metadata from the server when fetching changes (delta). class ChangeListLoader { public: // Resource feed fetcher from the server. class FeedFetcher; ChangeListLoader(base::SequencedTaskRunner* blocking_task_runner, ResourceMetadata* resource_metadata, JobScheduler* scheduler, DriveServiceInterface* drive_service); ~ChangeListLoader(); // Indicates whether there is a request for full resource list or change // list fetching is in flight (i.e. directory contents fetching does not // count). bool IsRefreshing() const; // Adds and removes the observer. void AddObserver(ChangeListLoaderObserver* observer); void RemoveObserver(ChangeListLoaderObserver* observer); // Checks for updates on the server. Does nothing if the change list is now // being loaded or refreshed. |callback| must not be null. // Note: |callback| will be called if the check for updates actually // runs, i.e. it may NOT be called if the checking is ignored. void CheckForUpdates(const FileOperationCallback& callback); // Starts the change list loading first from the cache. If loading from the // cache is successful, runs |callback| immediately and starts checking // server for updates in background. If loading from the cache is // unsuccessful, starts loading from the server, and runs |callback| to tell // the result to the caller when it is finished. // // If |directory_fetch_info| is not empty, the directory will be fetched // first from the server, so the UI can show the directory contents // instantly before the entire change list loading is complete. // // |callback| must not be null. void LoadIfNeeded(const DirectoryFetchInfo& directory_fetch_info, const FileOperationCallback& callback); // Loads the directory content from the server, without comparing the // changestamps. The purpose of this function is to update thumbnail URLs // in the directory which can stale over time. void LoadDirectoryFromServer(const std::string& directory_resource_id, const FileOperationCallback& callback); private: // Starts the resource metadata loading and calls |callback| when it's // done. |directory_fetch_info| is used for fast fetch. If there is already // a loading job in-flight for |directory_fetch_info|, just append the // |callback| to the callback queue of the already running job. void Load(const DirectoryFetchInfo& directory_fetch_info, const FileOperationCallback& callback); // Part of Load(). DoInitialLoad() is called if it is the first time to Load. // Otherwise DoUpdateLoad() is used. The difference of two cases are: // - When we could load from cache, DoInitialLoad runs callback immediately // and further operations (check changestamp and load from server if needed) // in background. // - Even when |directory_fetch_info| is set, DoInitialLoad runs change list // loading after directory loading is finished. void DoInitialLoad(const DirectoryFetchInfo& directory_fetch_info, int64 local_changestamp); void DoUpdateLoad(const DirectoryFetchInfo& directory_fetch_info, int64 local_changestamp); // Part of Load(). // This function should be called when the change list load is complete. // Flushes the callbacks for change list loading and all directory loading. void OnChangeListLoadComplete(FileError error); // Part of Load(). // This function should be called when the directory load is complete. // Flushes the callbacks waiting for the directory to be loaded. void OnDirectoryLoadComplete(const DirectoryFetchInfo& directory_fetch_info, FileError error); // ================= Implementation for change list loading ================= // Initiates the change list loading from the server when |local_changestamp| // is older than the server changestamp. If |directory_fetch_info| is set, // do directory loading before change list loading. void LoadFromServerIfNeeded(const DirectoryFetchInfo& directory_fetch_info, int64 local_changestamp); // Part of LoadFromServerIfNeeded(). // Called after GetAboutResource() for getting remote changestamp is complete. void LoadFromServerIfNeededAfterGetAbout( const DirectoryFetchInfo& directory_fetch_info, int64 local_changestamp, google_apis::GDataErrorCode status, scoped_ptr about_resource); // Part of LoadFromServerIfNeeded(). // When LoadFromServerIfNeeded is called with |directory_fetch_info| for a // specific directory, it tries to load the directory before loading the // content of full filesystem. This method is called after directory loading // is finished, and proceeds to the normal pass: LoadChangeListServer. void LoadFromServerIfNeededAfterLoadDirectory( const DirectoryFetchInfo& directory_fetch_info, scoped_ptr about_resource, int64 start_changestamp, FileError error); // Part of LoadFromServerIfNeeded(). // Starts loading the change list since |start_changestamp|, or the full // resource list if |start_changestamp| is zero. For full update, the // largest_change_id and root_folder_id from |about_resource| will be used. void LoadChangeListFromServer( scoped_ptr about_resource, int64 start_changestamp); // Part of LoadChangeListFromServer(). // Called when the entire change list is loaded. void LoadChangeListFromServerAfterLoadChangeList( scoped_ptr about_resource, bool is_delta_update, FileError error, ScopedVector change_lists); // Part of LoadChangeListFromServer(). // Called when the resource metadata is updated. void LoadChangeListFromServerAfterUpdate(); // ================= Implementation for directory loading ================= // Part of LoadDirectoryFromServer(), called after the current remote // changestamp is obtained as |about_resource|. void LoadDirectoryFromServerAfterGetAbout( const std::string& directory_resource_id, const FileOperationCallback& callback, google_apis::GDataErrorCode status, scoped_ptr about_resource); // Compares the directory's changestamp and |last_known_remote_changestamp_|. // Starts DoLoadDirectoryFromServer() if the local data is old and runs // |callback| when finished. If it is up to date, calls back immediately. void CheckChangestampAndLoadDirectoryIfNeeded( const DirectoryFetchInfo& directory_fetch_info, int64 local_changestamp, const FileOperationCallback& callback); // Loads the directory contents from server, and updates the local metadata. // Runs |callback| when it is finished. void DoLoadDirectoryFromServer(const DirectoryFetchInfo& directory_fetch_info, const FileOperationCallback& callback); // Part of DoLoadDirectoryFromServer() for the grand root ("/drive"). void DoLoadGrandRootDirectoryFromServerAfterGetResourceEntryByPath( const DirectoryFetchInfo& directory_fetch_info, const FileOperationCallback& callback, FileError error, scoped_ptr entry); // Part of DoLoadDirectoryFromServer() for the grand root ("/drive"). void DoLoadGrandRootDirectoryFromServerAfterGetAboutResource( const DirectoryFetchInfo& directory_fetch_info, const FileOperationCallback& callback, google_apis::GDataErrorCode status, scoped_ptr about_resource); // Part of DoLoadDirectoryFromServer() for the grand root ("/drive"). void DoLoadDirectoryFromServerAfterAddMyDrive( const DirectoryFetchInfo& directory_fetch_info, const FileOperationCallback& callback, std::string* local_id, FileError error); // Part of DoLoadDirectoryFromServer() for a normal directory. void DoLoadDirectoryFromServerAfterLoad( const DirectoryFetchInfo& directory_fetch_info, const FileOperationCallback& callback, FeedFetcher* fetcher, FileError error, ScopedVector change_lists); // Part of DoLoadDirectoryFromServer(). void DoLoadDirectoryFromServerAfterRefresh( const DirectoryFetchInfo& directory_fetch_info, const FileOperationCallback& callback, const base::FilePath* directory_path, FileError error); // ================= Implementation for other stuff ================= // Updates from the whole change list collected in |change_lists|. // Record file statistics as UMA histograms. // // See comments at ChangeListProcessor::Apply() for // |about_resource| and |is_delta_update|. // |callback| must not be null. void UpdateFromChangeList( scoped_ptr about_resource, ScopedVector change_lists, bool is_delta_update, const base::Closure& callback); // Part of UpdateFromChangeList(). // Called when ChangeListProcessor::Apply() is complete. // Notifies directory changes per the result of the change list processing. void UpdateFromChangeListAfterApply( ChangeListProcessor* change_list_processor, bool should_notify, base::Time start_time, const base::Closure& callback); scoped_refptr blocking_task_runner_; ResourceMetadata* resource_metadata_; // Not owned. JobScheduler* scheduler_; // Not owned. DriveServiceInterface* drive_service_; // Not owned. ObserverList observers_; typedef std::map > LoadCallbackMap; LoadCallbackMap pending_load_callback_; FileOperationCallback pending_update_check_callback_; // Running feed fetcher. scoped_ptr change_feed_fetcher_; // Set of the running feed fetcher for the fast fetch. std::set fast_fetch_feed_fetcher_set_; // The last known remote changestamp. Used to check if a directory // changestamp is up-to-date for fast fetch. int64 last_known_remote_changestamp_; // The cache of the root_folder_id. std::string root_folder_id_; // True if the full resource list is loaded (i.e. the resource metadata is // stored locally). bool loaded_; // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed. base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ChangeListLoader); }; } // namespace internal } // namespace drive #endif // CHROME_BROWSER_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_