Files
netris-cdc-file-transfer/common/stub_process.cc
Christian Schneider 4326e972ac Releasing the former Stadia file transfer tools
The tools allow efficient and fast synchronization of large directory
trees from a Windows workstation to a Linux target machine.

cdc_rsync* support efficient copy of files by using content-defined
chunking (CDC) to identify chunks within files that can be reused.

asset_stream_manager + cdc_fuse_fs support efficient streaming of a
local directory to a remote virtual file system based on FUSE. It also
employs CDC to identify and reuse unchanged data chunks.
2022-11-03 10:39:10 +01:00

159 lines
5.6 KiB
C++

// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "common/stub_process.h"
#include "absl/strings/match.h"
#include "absl/strings/str_format.h"
#include "common/status_macros.h"
#include "common/util.h"
namespace cdc_ft {
class StubProcess : public Process {
public:
StubProcess(const ProcessStartInfo& start_info, std::string std_out,
std::string std_err, uint32_t exit_code, bool has_exited,
bool never_exits, StubProcessFactory::ProcessHandlerFn handler)
: Process(start_info),
std_out_(std::move(std_out)),
std_err_(std::move(std_err)),
exit_code_(exit_code),
has_exited_(has_exited),
never_exits_(never_exits),
handler_(handler) {}
~StubProcess() = default;
// Process:
absl::Status Start() override { return absl::OkStatus(); }
absl::Status RunUntil(std::function<bool()> exit_condition) override {
if (handler_) {
handler_(&std_out_, &std_err_, &exit_code_);
}
// Write stdout/stderr including the null terminator.
if (start_info_.stdout_handler) {
RETURN_IF_ERROR(
start_info_.stdout_handler(std_out_.c_str(), std_out_.size() + 1));
}
if (start_info_.stderr_handler) {
RETURN_IF_ERROR(
start_info_.stderr_handler(std_out_.c_str(), std_err_.size() + 1));
}
if (never_exits_) {
// Poll until exit condition (e.g. timeout) is satisfied.
while (!exit_condition()) Util::Sleep(1);
} else {
// Exit immediately.
has_exited_ = true;
}
return absl::OkStatus();
}
absl::Status Terminate() override { return absl::OkStatus(); }
absl::Status WriteToStdIn(const void*, size_t) override {
return absl::OkStatus();
}
void CloseStdIn() override {}
bool HasExited() const override { return has_exited_; }
uint32_t ExitCode() const override { return exit_code_; }
absl::Status GetStatus() const override { return absl::OkStatus(); }
private:
std::string std_out_;
std::string std_err_;
uint32_t exit_code_;
const bool never_exits_;
bool has_exited_ = false;
StubProcessFactory::ProcessHandlerFn handler_;
};
// An ErrorProcess is returned if the corresponding command isn't handled in
// StubProcessFactory::Create(). It will fail to start.
class ErrorProcess : public Process {
public:
explicit ErrorProcess(const ProcessStartInfo& start_info)
: Process(start_info),
status_(absl::InternalError(
absl::StrFormat("Unhandled process '%s'", start_info_.command))) {}
~ErrorProcess() = default;
// Process:
absl::Status Start() override { return status_; }
absl::Status RunUntil(std::function<bool()>) override { return status_; }
absl::Status Terminate() override { return status_; }
absl::Status WriteToStdIn(const void*, size_t) override { return status_; }
void CloseStdIn() override {}
bool HasExited() const override { return false; }
uint32_t ExitCode() const override { return kExitCodeStillRunning; }
absl::Status GetStatus() const override { return status_; }
private:
absl::Status status_;
};
StubProcessFactory::~StubProcessFactory() = default;
std::unique_ptr<Process> StubProcessFactory::Create(
const ProcessStartInfo& start_info) {
for (const ProcessInfo& pi : process_info_) {
if (absl::StrContains(start_info.command, pi.command_part)) {
return std::make_unique<StubProcess>(start_info, pi.std_out, pi.std_err,
pi.exit_code, pi.has_exited,
pi.never_exits, pi.handler);
}
}
return std::make_unique<ErrorProcess>(start_info);
}
void StubProcessFactory::SetProcessOutput(std::string command_part,
std::string std_out,
std::string std_err,
uint32_t exit_code) {
process_info_.push_back({std::move(command_part), std::move(std_out),
std::move(std_err), exit_code,
/*has_exited=*/false, /*never_exits=*/false,
ProcessHandlerFn()});
}
void StubProcessFactory::SetProcessNeverExits(std::string command_part) {
process_info_.push_back({std::move(command_part), "", "", 1,
/*has_exited=*/false,
/*never_exits=*/true, ProcessHandlerFn()});
}
void StubProcessFactory::SetProcessExitsImmediately(std::string command_part,
uint32_t exit_code) {
process_info_.push_back({std::move(command_part), /*std_out=*/"",
/*std_err=*/"", exit_code, /*has_exited=*/true,
/*never_exits=*/false, ProcessHandlerFn()});
}
void StubProcessFactory::SetProcessHandler(std::string command_part,
ProcessHandlerFn handler) {
process_info_.push_back({std::move(command_part), /*std_out=*/"",
/*std_err=*/"",
/*exit_code_=*/0, /*has_exited=*/false,
/*never_exits=*/false, handler});
}
} // namespace cdc_ft