910e62b5创建于 1月15日历史提交
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_DRIVE_DRIVE_UPLOADER_H_
#define COMPONENTS_DRIVE_DRIVE_UPLOADER_H_

#include <stdint.h>

#include <memory>
#include <optional>
#include <string>

#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "components/drive/drive_export.h"
#include "components/drive/service/drive_service_interface.h"
#include "google_apis/common/api_error_codes.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h"

class GURL;

namespace base {
class FilePath;
class TaskRunner;
}  // namespace base

namespace google_apis {
struct UploadRangeResponse;
}

namespace drive {
class DriveServiceInterface;

// Callback to be invoked once the upload has completed.
// |upload_location| will be returned when the uploading process is started but
// terminated before the completion due to some errors. It can be used to
// resume it.
using UploadCompletionCallback = base::OnceCallback<void(
    google_apis::ApiErrorCode error,
    const GURL& upload_location,
    std::unique_ptr<google_apis::FileResource> resource_entry)>;

class COMPONENTS_DRIVE_EXPORT DriveUploaderInterface {
 public:
  virtual ~DriveUploaderInterface() = default;

  // Starts batch processing for upload requests. All requests which upload
  // small files (less than kMaxMultipartUploadSize) between
  // |StartBatchProcessing| and |StopBatchProcessing| are sent as a single batch
  // request.
  virtual void StartBatchProcessing() = 0;

  // Stops batch processing. Must be called after calling |StartBatchProcessing|
  // to commit requests.
  virtual void StopBatchProcessing() = 0;

  // Uploads a new file to a directory specified by |upload_location|.
  // Returns a callback for cancelling the uploading job.
  //
  // parent_resource_id:
  //   resource id of the destination directory.
  //
  // local_file_path:
  //   The path to the local file to be uploaded.
  //
  // title:
  //   The title (file name) of the file to be uploaded.
  //
  // content_type:
  //   The content type of the file to be uploaded.
  //
  // callback:
  //   Called when an upload is done regardless of it was successful or not.
  //   Must not be null.
  //
  // progress_callback:
  //   Periodically called back with the total number of bytes sent so far.
  //   May be null if the information is not needed.
  virtual google_apis::CancelCallbackOnce UploadNewFile(
      const std::string& parent_resource_id,
      const base::FilePath& local_file_path,
      const std::string& title,
      const std::string& content_type,
      const UploadNewFileOptions& options,
      UploadCompletionCallback callback,
      google_apis::ProgressCallback progress_callback) = 0;

  // Uploads an existing file (a file that already exists on Drive).
  //
  // See comments at UploadNewFile about common parameters and the return value.
  //
  // resource_id:
  //   resource id of the existing file to be overwritten.
  //
  // etag:
  //   Expected ETag for the destination file. If it does not match, the upload
  //   fails with UPLOAD_ERROR_CONFLICT.
  //   If |etag| is empty, the test is skipped.
  virtual google_apis::CancelCallbackOnce UploadExistingFile(
      const std::string& resource_id,
      const base::FilePath& local_file_path,
      const std::string& content_type,
      const UploadExistingFileOptions& options,
      UploadCompletionCallback callback,
      google_apis::ProgressCallback progress_callback) = 0;

  // Resumes the uploading process terminated before the completion.
  // |upload_location| should be the one returned via UploadCompletionCallback
  // for previous invocation. |drive_file_path|, |local_file_path| and
  // |content_type| must be set to the same ones for previous invocation.
  //
  // See comments at UploadNewFile about common parameters and the return value.
  virtual google_apis::CancelCallbackOnce ResumeUploadFile(
      const GURL& upload_location,
      const base::FilePath& local_file_path,
      const std::string& content_type,
      UploadCompletionCallback callback,
      google_apis::ProgressCallback progress_callback) = 0;
};

class COMPONENTS_DRIVE_EXPORT DriveUploader : public DriveUploaderInterface {
 public:
  // In unittest, the |wake_lock_provider| is set as nullptr.
  DriveUploader(
      DriveServiceInterface* drive_service,
      const scoped_refptr<base::TaskRunner>& blocking_task_runner,
      mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider);

  DriveUploader(const DriveUploader&) = delete;
  DriveUploader& operator=(const DriveUploader&) = delete;

  ~DriveUploader() override;

  // DriveUploaderInterface overrides.
  void StartBatchProcessing() override;
  void StopBatchProcessing() override;
  google_apis::CancelCallbackOnce UploadNewFile(
      const std::string& parent_resource_id,
      const base::FilePath& local_file_path,
      const std::string& title,
      const std::string& content_type,
      const UploadNewFileOptions& options,
      UploadCompletionCallback callback,
      google_apis::ProgressCallback progress_callback) override;
  google_apis::CancelCallbackOnce UploadExistingFile(
      const std::string& resource_id,
      const base::FilePath& local_file_path,
      const std::string& content_type,
      const UploadExistingFileOptions& options,
      UploadCompletionCallback callback,
      google_apis::ProgressCallback progress_callback) override;
  google_apis::CancelCallbackOnce ResumeUploadFile(
      const GURL& upload_location,
      const base::FilePath& local_file_path,
      const std::string& content_type,
      UploadCompletionCallback callback,
      google_apis::ProgressCallback progress_callback) override;

 private:
  class RefCountedBatchRequest;
  struct UploadFileInfo;
  typedef base::OnceCallback<void(
      std::unique_ptr<UploadFileInfo> upload_file_info)>
      StartInitiateUploadCallback;

  // Starts uploading a file with |upload_file_info|.
  google_apis::CancelCallbackOnce StartUploadFile(
      std::unique_ptr<UploadFileInfo> upload_file_info,
      StartInitiateUploadCallback start_initiate_upload_callback);
  void StartUploadFileAfterGetFileSize(
      std::unique_ptr<UploadFileInfo> upload_file_info,
      StartInitiateUploadCallback start_initiate_upload_callback,
      std::optional<int64_t> maybe_file_size);

  // Checks file size and call InitiateUploadNewFile or MultipartUploadNewFile
  // API.  Upon completion, OnUploadLocationReceived (for InitiateUploadNewFile)
  // or OnMultipartUploadComplete (for MultipartUploadNewFile) should be called.
  // If |batch_request| is non-null, it calls the API function on the batch
  // request.
  void CallUploadServiceAPINewFile(
      const std::string& parent_resource_id,
      const std::string& title,
      const UploadNewFileOptions& options,
      const scoped_refptr<RefCountedBatchRequest>& batch_request,
      std::unique_ptr<UploadFileInfo> upload_file_info);

  // Checks file size and call InitiateUploadExistingFile or
  // MultipartUploadExistingFile API.  Upon completion, OnUploadLocationReceived
  // (for InitiateUploadExistingFile) or OnMultipartUploadComplete (for
  // MultipartUploadExistingFile) should be called.
  // If |batch_request| is non-null, it calls the API function on the batch
  // request.
  void CallUploadServiceAPIExistingFile(
      const std::string& resource_id,
      const UploadExistingFileOptions& options,
      const scoped_refptr<RefCountedBatchRequest>& batch_request,
      std::unique_ptr<UploadFileInfo> upload_file_info);

  // DriveService callback for InitiateUpload.
  void OnUploadLocationReceived(
      std::unique_ptr<UploadFileInfo> upload_file_info,
      google_apis::ApiErrorCode code,
      const GURL& upload_location);

  // Starts to get the current upload status for the file uploading.
  // Upon completion, OnUploadRangeResponseReceived should be called.
  void StartGetUploadStatus(std::unique_ptr<UploadFileInfo> upload_file_info);

  // Uploads the next chunk of data from the file.
  void UploadNextChunk(std::unique_ptr<UploadFileInfo> upload_file_info);

  // DriveService callback for ResumeUpload.
  void OnUploadRangeResponseReceived(
      std::unique_ptr<UploadFileInfo> upload_file_info,
      const google_apis::UploadRangeResponse& response,
      std::unique_ptr<google_apis::FileResource> entry);
  void OnUploadProgress(google_apis::ProgressCallback callback,
                        int64_t start_position,
                        int64_t total_size,
                        int64_t progress_of_chunk,
                        int64_t total_of_chunk);

  // Handles failed uploads.
  void UploadFailed(std::unique_ptr<UploadFileInfo> upload_file_info,
                    google_apis::ApiErrorCode error);

  // Handles completion/error of multipart uploading.
  void OnMultipartUploadComplete(
      std::unique_ptr<UploadFileInfo> upload_file_info,
      google_apis::ApiErrorCode error,
      std::unique_ptr<google_apis::FileResource> entry);

  device::mojom::WakeLockProvider* GetWakeLockProvider();

  // The class is expected to run on UI thread.
  base::ThreadChecker thread_checker_;

  // The lifetime of this object should be guaranteed to exceed that of the
  // DriveUploader instance.
  raw_ptr<DriveServiceInterface, DanglingUntriaged>
      drive_service_;  // Not owned by this class.

  scoped_refptr<base::TaskRunner> blocking_task_runner_;
  scoped_refptr<RefCountedBatchRequest> current_batch_request_;

  mojo::Remote<device::mojom::WakeLockProvider> wake_lock_provider_;

  // 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<DriveUploader> weak_ptr_factory_{this};
};

}  // namespace drive

#endif  // COMPONENTS_DRIVE_DRIVE_UPLOADER_H_