blob: fae615a47a11e5d286c9ecd6bd80091ada83f5b3 [file] [log] [blame]
// Copyright 2018 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.
#include "remoting/host/file_transfer/session_file_operations_handler.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "remoting/protocol/file_transfer_helpers.h"
namespace remoting {
SessionFileOperationsHandler::SessionFileOperationsHandler(
IpcFileOperations::ResultHandler* result_handler,
std::unique_ptr<FileOperations> file_operations)
: result_handler_(result_handler),
file_operations_(std::move(file_operations)) {}
void SessionFileOperationsHandler::ReadFile(std::uint64_t file_id) {
auto location = readers_.emplace(file_id, file_operations_->CreateReader());
if (!location.second) {
// Strange, we've already received a ReadFile message for this ID. Cancel
// it and send an error to be safe.
readers_.erase(location.first);
result_handler_->OnInfoResult(
file_id,
protocol::MakeFileTransferError(
FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR));
return;
}
// Unretained is sound because no Reader callbacks will be invoked after the
// Writer is destroyed.
location.first->second->Open(
base::BindOnce(&SessionFileOperationsHandler::OnReaderOpenResult,
base::Unretained(this), file_id));
}
void SessionFileOperationsHandler::ReadChunk(std::uint64_t file_id,
std::uint64_t size) {
auto reader_iter = readers_.find(file_id);
if (reader_iter == readers_.end()) {
result_handler_->OnDataResult(
file_id,
protocol::MakeFileTransferError(
FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR));
return;
}
reader_iter->second->ReadChunk(
size, base::BindOnce(&SessionFileOperationsHandler::OnReaderReadResult,
base::Unretained(this), file_id));
}
void SessionFileOperationsHandler::WriteFile(uint64_t file_id,
const base::FilePath& filename) {
auto location = writers_.emplace(file_id, file_operations_->CreateWriter());
if (!location.second) {
// Strange, we've already received a WriteFile message for this ID. Cancel
// it and send an error to be safe.
writers_.erase(location.first);
result_handler_->OnResult(
file_id,
protocol::MakeFileTransferError(
FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR));
return;
}
// Unretained is sound because no Writer callbacks will be invoked after the
// Writer is destroyed.
location.first->second->Open(
filename,
base::BindOnce(&SessionFileOperationsHandler::OnWriterOperationResult,
base::Unretained(this), file_id));
}
void SessionFileOperationsHandler::WriteChunk(uint64_t file_id,
std::string data) {
auto writer_iter = writers_.find(file_id);
if (writer_iter == writers_.end()) {
result_handler_->OnResult(
file_id,
protocol::MakeFileTransferError(
FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR));
return;
}
writer_iter->second->WriteChunk(
std::move(data),
base::BindOnce(&SessionFileOperationsHandler::OnWriterOperationResult,
base::Unretained(this), file_id));
}
void SessionFileOperationsHandler::Close(uint64_t file_id) {
auto reader_iter = readers_.find(file_id);
if (reader_iter != readers_.end()) {
readers_.erase(reader_iter);
return;
}
auto writer_iter = writers_.find(file_id);
if (writer_iter != writers_.end()) {
writer_iter->second->Close(
base::BindOnce(&SessionFileOperationsHandler::OnWriterCloseResult,
base::Unretained(this), file_id));
return;
}
// |file_id| is not a known reader or writer. Send an error in case the
// network process is waiting for a response.
result_handler_->OnResult(
file_id,
protocol::MakeFileTransferError(
FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR));
}
void SessionFileOperationsHandler::Cancel(uint64_t file_id) {
// It's possible for a cancel request and an error response (from a previous
// request) to pass each other in the message pipe, so the lack of a reader or
// writer matching |file_id| is not necessarily an error. Since a cancel
// request doesn't expect a response, it's fine to do nothing in that case.
auto reader_iter = readers_.find(file_id);
if (reader_iter != readers_.end()) {
readers_.erase(reader_iter);
}
auto writer_iter = writers_.find(file_id);
if (writer_iter != writers_.end()) {
writers_.erase(writer_iter);
}
}
void SessionFileOperationsHandler::OnReaderOpenResult(
std::uint64_t file_id,
FileOperations::Reader::OpenResult result) {
if (!result) {
readers_.erase(file_id);
result_handler_->OnInfoResult(file_id, std::move(result.error()));
return;
}
auto reader_iter = readers_.find(file_id);
// Should never get a callback if the reader has been destroyed.
DCHECK(reader_iter != readers_.end());
result_handler_->OnInfoResult(file_id,
{kSuccessTag, reader_iter->second->filename(),
reader_iter->second->size()});
}
void SessionFileOperationsHandler::OnReaderReadResult(
std::uint64_t file_id,
FileOperations::Reader::ReadResult result) {
if (!result || result->size() == 0) {
readers_.erase(file_id);
}
result_handler_->OnDataResult(file_id, std::move(result));
}
void SessionFileOperationsHandler::OnWriterOperationResult(
uint64_t file_id,
FileOperations::Writer::Result result) {
if (!result) {
writers_.erase(file_id);
}
result_handler_->OnResult(file_id, std::move(result));
}
void SessionFileOperationsHandler::OnWriterCloseResult(
uint64_t file_id,
FileOperations::Writer::Result result) {
writers_.erase(file_id);
result_handler_->OnResult(file_id, std::move(result));
}
SessionFileOperationsHandler::~SessionFileOperationsHandler() = default;
} // namespace remoting