1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
|
// 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 "base/timer/timer.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"
#include "services/network/public/cpp/network_connection_tracker.h"
namespace ash::cloud_upload {
using policy::local_user_files::MigrationUploadError;
using policy::local_user_files::UploadTrigger;
// 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>,
base::FilePath upload_root_path)>;
// 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,
UploadTrigger trigger,
base::RepeatingCallback<void(int64_t)> progress_callback,
base::OnceCallback<void(bool, storage::FileSystemURL)> upload_callback,
std::optional<const gfx::Image> thumbnail = std::nullopt);
// Uploads the file to OneDrive, placing it in the device-unique folder at the
// specified relative path.
//
// Invokes `upload_callback` upon completion.
//
// 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 `relative_source_path` of
// "Documents/Files" and `upload_root` "ChromeOS Device 123" results in
// "<ODFS ROOT>/ChromeOS Device 123/Documents/Files/example.txt" on OneDrive.
static base::WeakPtr<OdfsSkyvaultUploader> Upload(
Profile* profile,
const base::FilePath& path,
const base::FilePath& relative_source_path,
const std::string& upload_root,
UploadTrigger trigger,
base::RepeatingCallback<void(int64_t)> progress_callback,
UploadDoneCallback upload_callback);
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.
virtual void Cancel();
protected:
OdfsSkyvaultUploader(Profile* profile,
int64_t id,
const storage::FileSystemURL& file_system_url,
UploadTrigger trigger,
base::RepeatingCallback<void(int64_t)> progress_callback,
std::optional<const gfx::Image> thumbnail);
~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);
// Starts the upload flow.
virtual void Run(UploadDoneCallback upload_callback);
void OnEndUpload(storage::FileSystemURL url,
std::optional<MigrationUploadError> error = std::nullopt);
raw_ptr<Profile> profile_;
// Absolute path to the device's upload root folder on Drive. This is
// populated when the upload is about to start.
base::FilePath upload_root_path_;
private:
friend base::RefCounted<OdfsSkyvaultUploader>;
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;
// Translates the status error into a MigrationUploadError.
void ProcessError(const ::file_manager::io_task::ProgressStatus& status);
// 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 event or action that initiated the file upload.
const UploadTrigger trigger_;
// 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;
// Optional preview of the file that is being uploaded.
std::optional<const gfx::Image> thumbnail_;
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 network::NetworkConnectionTracker::NetworkConnectionObserver {
public:
using FactoryCallback =
base::RepeatingCallback<scoped_refptr<OdfsMigrationUploader>(
Profile*,
int64_t,
const storage::FileSystemURL&,
const base::FilePath&)>;
static scoped_refptr<OdfsMigrationUploader> Create(
Profile* profile,
int64_t id,
const storage::FileSystemURL& file_system_url,
const base::FilePath& relative_source_path,
const std::string& upload_root);
// Sets a testing factory function, allowing the injection of mock
// OdfsMigrationUploader objects into the migration upload process.
static void SetFactoryForTesting(FactoryCallback factory);
protected:
OdfsMigrationUploader(Profile* profile,
int64_t id,
const storage::FileSystemURL& file_system_url,
const base::FilePath& relative_source_path,
const std::string& upload_root);
~OdfsMigrationUploader() override;
private:
// OdfsSkyvaultUploader:
void Run(UploadDoneCallback upload_callback) override;
base::FilePath GetDestinationFolderPath(
file_system_provider::ProvidedFileSystemInterface* file_system) override;
void RequestSignIn(
base::OnceCallback<void(base::File::Error)> on_sign_in_cb) override;
// network::NetworkConnectionTracker::NetworkConnectionObserver:
void OnConnectionChanged(network::mojom::ConnectionType type) override;
// Starts the upload process after establishing network connection.
void RunInternal();
// Called when waiting for connection times out.
void OnReconnectionTimeout();
// Indicates whether there was no connection on starting the task.
bool waiting_for_connection_ = false;
// Time at which we started waiting for connection. Used for UMA.
std::optional<base::Time> connection_wait_start_time_;
// Ensures that we don't wait for connection indefinitely
base::OneShotTimer reconnection_timer_;
UploadDoneCallback upload_callback_;
// Part of the source path relative to MyFiles
const base::FilePath relative_source_path_;
// The name of the device-unique upload root folder on Drive
const std::string upload_root_;
base::CallbackListSubscription subscription_;
base::WeakPtrFactory<OdfsMigrationUploader> weak_ptr_factory_{this};
};
} // namespace ash::cloud_upload
#endif // CHROME_BROWSER_ASH_POLICY_SKYVAULT_ODFS_SKYVAULT_UPLOADER_H_
|