blob: f246e162235a024343b7b82b55cd04ab5ebebe05 [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 "src/developer/forensics/feedback_data/archive_accessor_ptr.h"
#include <lib/fit/result.h>
#include <lib/fostr/fidl/fuchsia/diagnostics/formatting.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <vector>
#include "src/developer/forensics/utils/errors.h"
#include "src/developer/forensics/utils/fit/promise.h"
#include "src/developer/forensics/utils/fit/timeout.h"
namespace forensics {
namespace feedback_data {
ArchiveAccessor::ArchiveAccessor(async_dispatcher_t* dispatcher,
std::shared_ptr<sys::ServiceDirectory> services,
fuchsia::diagnostics::DataType data_type,
fuchsia::diagnostics::StreamMode stream_mode,
std::optional<size_t> data_budget)
: archive_(dispatcher, services, kArchiveAccessorName) {
// Setup stream parameters
stream_parameters_.set_data_type(data_type);
stream_parameters_.set_stream_mode(stream_mode);
stream_parameters_.set_format(fuchsia::diagnostics::Format::JSON);
stream_parameters_.set_client_selector_configuration(
fuchsia::diagnostics::ClientSelectorConfiguration::WithSelectAll(true));
if (data_budget) {
fuchsia::diagnostics::PerformanceConfiguration performance;
performance.set_max_aggregate_content_size_bytes(data_budget.value());
stream_parameters_.set_performance_configuration(std::move(performance));
}
// We set up the connection and all the error handlers.
snapshot_iterator_.set_error_handler([this](zx_status_t status) {
if (archive_.IsAlreadyDone()) {
return;
}
FX_PLOGS(WARNING, status) << "Lost connection to fuchsia.diagnostics.BatchIterator";
archive_.CompleteError(Error::kConnectionError);
});
}
void ArchiveAccessor::Collect(
std::function<void(fuchsia::diagnostics::FormattedContent)> write_formatted_content) {
// We start the Diagnostics data collection.
archive_->StreamDiagnostics(std::move(stream_parameters_), snapshot_iterator_.NewRequest());
AppendNextBatch(std::move(write_formatted_content));
}
void ArchiveAccessor::StopCollect() { snapshot_iterator_.Unbind(); }
::fit::promise<void, Error> ArchiveAccessor::WaitForDone(fit::Timeout timeout) {
return archive_.WaitForDone(std::move(timeout));
}
void ArchiveAccessor::AppendNextBatch(
std::function<void(fuchsia::diagnostics::FormattedContent)> write_formatted_content) {
snapshot_iterator_->GetNext(
[this, write_formatted_content = std::move(write_formatted_content)](auto result) {
if (archive_.IsAlreadyDone()) {
return;
}
if (result.is_err()) {
FX_LOGS(WARNING) << "Failed to retrieve next Diagnostics batch: " << result.err();
// TODO(fxbug.dev/51658): don't complete the flow on an error. The API says we should
// continue making calls instead.
archive_.CompleteError(Error::kBadValue);
return;
}
std::vector<fuchsia::diagnostics::FormattedContent>& batch = result.response().batch;
if (batch.empty()) { // We have gotten all the Diagnostics data.
archive_.CompleteOk();
return;
}
for (auto& chunk : batch) {
write_formatted_content(std::move(chunk));
}
AppendNextBatch(std::move(write_formatted_content));
});
}
} // namespace feedback_data
} // namespace forensics