// 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 CHROMEOS_ASH_COMPONENTS_DATA_MIGRATION_FILE_RECEIVER_H_
#define CHROMEOS_ASH_COMPONENTS_DATA_MIGRATION_FILE_RECEIVER_H_
#include <cstdint>
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/ash/components/nearby/common/connections_manager/nearby_connections_manager.h"
namespace data_migration {
// Receives a single file over the network from a remote device via the NC
// library. `FileReceiver` may be destroyed at any time to cancel the file
// transfer. If it is destroyed while the file transfer is still in progress or
// after the transfer has failed, there may be a partially complete local file
// on disc from the transfer. The caller has two options:
// 1) Retry the transfer by creating a new `FileReceiver`, which will overwrite
// the existing partial file.
// 2) Delete the partial file themselves. This is intentionally not handled by
// `FileReceiver`'s destructor.
class FileReceiver : public NearbyConnectionsManager::PayloadStatusListener {
public:
struct Observer {
Observer(base::OnceClosure on_file_registered_in,
base::OnceCallback<void(bool)> on_file_transfer_complete_in);
Observer(Observer&&);
Observer& operator=(Observer&&);
~Observer();
// Invoked when the file has been registered with the NC library (a
// prerequisite for the transmission to begin). When this is run, the
// NC library is aware of this file's expected transmission, and the
// remote device can begin the transfer. The transfer on the remote device
// should not be started until this callback is invoked or there are race
// conditions where the transfer may fail.
base::OnceClosure on_file_registered;
// File transfer has completed. Argument indicates success or failure.
// The `FileReceiver` is inactive when this is invoked and may be destroyed
// immediately if desired.
base::OnceCallback<void(bool)> on_file_transfer_complete;
};
// `path`: The location where the file is written as it's received from the
// remote device. The caller must ensure the |path|'s directory exists and is
// writeable.
FileReceiver(int64_t payload_id,
base::FilePath path,
Observer observer,
NearbyConnectionsManager* nearby_connections_manager);
FileReceiver(const FileReceiver&) = delete;
FileReceiver& operator=(const FileReceiver&) = delete;
~FileReceiver() override;
private:
// PayloadStatusListener:
void OnStatusUpdate(PayloadTransferUpdatePtr update,
std::optional<Medium> upgraded_medium) override;
void RegisterPayloadPath(int attempt_number);
void OnRegisterPayloadPathComplete(
int attempt_number,
NearbyConnectionsManager::ConnectionsStatus result);
void VerifyFileTransferResult(int64_t expected_size_in_bytes);
void CompleteTransfer(bool verification_status);
const int64_t payload_id_;
const base::FilePath path_;
Observer observer_;
const raw_ptr<NearbyConnectionsManager> nearby_connections_manager_;
// False if either transfer is in progress or the transfer has failed.
bool transfer_completed_successfully_ = false;
// Note `NearbyConnectionsManager::PayloadStatusListener` has its own
// `weak_ptr_factory_`, but a factory of type `FileReceiver` is still
// required for binding `FileReceiver` methods.
base::WeakPtrFactory<FileReceiver> file_receiver_weak_factory_{this};
};
} // namespace data_migration
#endif // CHROMEOS_ASH_COMPONENTS_DATA_MIGRATION_FILE_RECEIVER_H_