// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_POLICY_SKYVAULT_ODFS_SKYVAULT_UPLOADER_H_
#define CHROME_BROWSER_ASH_POLICY_SKYVAULT_ODFS_SKYVAULT_UPLOADER_H_
#include <optional>
#include "base/callback_list.h"
#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/file_manager/io_task_controller.h"
#include "chrome/browser/ash/policy/skyvault/policy_utils.h"
#include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_util.h"
namespace ash::cloud_upload {
using policy::local_user_files::MigrationUploadError;
// Uploads the file to Microsoft OneDrive and calls the `upload_callback_` with
// the result of the file upload, which is when `OdfsSkyvaultUploader` goes out
// of scope. Instantiated by the static `Upload` method. Runs
// `progress_callback` by the upload progress if possible.
class OdfsSkyvaultUploader
: public base::RefCounted<OdfsSkyvaultUploader>,
::file_manager::io_task::IOTaskController::Observer {
public:
using UploadDoneCallback =
base::OnceCallback<void(storage::FileSystemURL,
std::optional<MigrationUploadError>)>;
// Type of the file to be uploaded to OneDrive whether it's a downloaded file
// or a screencapture file, ...etc.
enum class FileType {
kDownload = 0,
kScreenCapture = 1,
kMigration = 2,
kMaxValue = kMigration,
};
// Uploads the file at `path` to the OneDrive root directory.
//
// Upon completion, invokes `upload_callback` with the following:
// * `bool success` - Indicates whether the upload was successful.
// * `storage::FileSystemURL url` - (If successful) The URL of the uploaded
// file on OneDrive.
//
// Optionally, periodically invokes the `progress_callback` during the upload
// to provide progress updates in bytes transferred.
//
// Returns a weak pointer to the `OdfsSkyvaultUploader` object. This can be
// used to cancel the upload before it completes.
static base::WeakPtr<OdfsSkyvaultUploader> Upload(
Profile* profile,
const base::FilePath& path,
FileType file_type,
base::RepeatingCallback<void(int64_t)> progress_callback,
base::OnceCallback<void(bool, storage::FileSystemURL)> upload_callback);
// Uploads the file at `file_system_url` to OneDrive, placing it at the
// specified `target_path`.
//
// Upon completion, invokes `upload_callback` with the following:
// * `MigrationUploadError error` - Indicates the type of error encountered
// during the upload, if any. See the `MigrationUploadError` enum for possible
// values.
// * `storage::FileSystemURL url` - The URL of the uploaded file on OneDrive.
// This will be empty if the upload failed.
//
// Optionally, periodically invokes the `progress_callback` during the upload
// to provide progress updates in bytes transferred.
//
// Returns a weak pointer to the `OdfsSkyvaultUploader` object. This can be
// used to cancel the upload before it completes.
//
// Example: Uploading "example.txt" with a `target_path` of "Documents/Files"
// results in
// "<ODFS ROOT>/Documents/Files/example.txt" on OneDrive.
static base::WeakPtr<OdfsSkyvaultUploader> Upload(
Profile* profile,
const base::FilePath& path,
FileType file_type,
base::RepeatingCallback<void(int64_t)> progress_callback,
UploadDoneCallback upload_callback,
const base::FilePath& target_path);
OdfsSkyvaultUploader(const OdfsSkyvaultUploader&) = delete;
OdfsSkyvaultUploader& operator=(const OdfsSkyvaultUploader&) = delete;
// Returns a weak pointer to this instance.
base::WeakPtr<OdfsSkyvaultUploader> GetWeakPtr();
// Should cancel the whole upload, if possible.
void Cancel();
protected:
OdfsSkyvaultUploader(
Profile* profile,
int64_t id,
const storage::FileSystemURL& file_system_url,
FileType file_type,
base::RepeatingCallback<void(int64_t)> progress_callback);
~OdfsSkyvaultUploader() override;
// Returns the path to upload the file to.
virtual base::FilePath GetDestinationFolderPath(
file_system_provider::ProvidedFileSystemInterface* file_system);
// Requests the sign in to OneDrive.
virtual void RequestSignIn(
base::OnceCallback<void(base::File::Error)> on_sign_in_cb);
raw_ptr<Profile> profile_;
private:
friend base::RefCounted<OdfsSkyvaultUploader>;
// Starts the upload flow.
void Run(UploadDoneCallback upload_callback);
void OnEndUpload(storage::FileSystemURL url,
std::optional<MigrationUploadError> error = std::nullopt);
void GetODFSMetadataAndStartIOTask();
void CheckReauthenticationAndStartIOTask(
base::expected<ODFSMetadata, base::File::Error> metadata_or_error);
// IOTaskController::Observer:
void OnIOTaskStatus(
const ::file_manager::io_task::ProgressStatus& status) override;
// Called when the mount response is received.
void OnMountResponse(base::File::Error result);
// Starts the IOTask to upload the file to OneDrive.
void StartIOTask();
scoped_refptr<storage::FileSystemContext> file_system_context_;
raw_ptr<::file_manager::io_task::IOTaskController> io_task_controller_;
// The Id of the OdfsSkyvaultUploader instance. Used for notifications.
const int64_t id_;
// The Id of the move IOTask.
std::optional<::file_manager::io_task::IOTaskId> observed_task_id_ =
std::nullopt;
// The url of the file to be uploaded.
storage::FileSystemURL file_system_url_;
// The type of the file to be uploaded.
FileType file_type_;
// Progress callback repeatedly run with progress updates.
base::RepeatingCallback<void(int64_t)> progress_callback_;
// Upload callback run once with upload success/failure and the file url (if
// successfully uploaded).
UploadDoneCallback upload_callback_;
// Set to `true` if upload is explicitly cancelled by owner. Forces every step
// to exit early.
bool cancelled_ = false;
base::WeakPtrFactory<OdfsSkyvaultUploader> weak_ptr_factory_{this};
};
// Similar to OdfsSkyvaultUploader, but specialized for the migration flow:
// - doesn't require the file to first be moved to tmp
// - doesn't require progress updates
// - uploads file to a dedicated folder on OneDrive, and not to root
// - invokes different sign-in process, that ensures only one notification is
// TODO(aidazolic): Fix the instantiation.
class OdfsMigrationUploader : public OdfsSkyvaultUploader {
public:
static scoped_refptr<OdfsMigrationUploader> Create(
Profile* profile,
int64_t id,
const storage::FileSystemURL& file_system_url,
const base::FilePath& target_path);
private:
OdfsMigrationUploader(Profile* profile,
int64_t id,
const storage::FileSystemURL& file_system_url,
const base::FilePath& target_path);
~OdfsMigrationUploader() override;
// OdfsSkyvaultUploader:
base::FilePath GetDestinationFolderPath(
file_system_provider::ProvidedFileSystemInterface* file_system) override;
void RequestSignIn(
base::OnceCallback<void(base::File::Error)> on_sign_in_cb) override;
// Path in OneDrive to upload the file to.
base::FilePath target_path_;
base::CallbackListSubscription subscription_;
};
} // namespace ash::cloud_upload
#endif // CHROME_BROWSER_ASH_POLICY_SKYVAULT_ODFS_SKYVAULT_UPLOADER_H_