blob: 853236950b7f79d974669099a42182a3bc3995f8 [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/attachments/attachment_manager.h"
#include <lib/fpromise/promise.h>
#include <lib/syslog/cpp/macros.h>
#include <utility>
#include "src/developer/forensics/feedback/attachments/static_attachments.h"
#include "src/developer/forensics/feedback/attachments/types.h"
#include "src/developer/forensics/feedback_data/constants.h"
#include "src/lib/timekeeper/clock.h"
namespace forensics::feedback {
namespace {
template <typename T>
void EraseNotAllowlisted(std::map<std::string, T>& c, const std::set<std::string>& allowlist) {
for (auto it = c.begin(); it != c.end();) {
if (allowlist.count(it->first) == 0) {
FX_LOGS(INFO) << "Attachment \"" << it->first << "\" not allowlisted, dropping";
c.erase(it++);
} else {
++it;
}
}
}
} // namespace
AttachmentManager::AttachmentManager(const std::set<std::string>& allowlist,
Attachments static_attachments,
std::map<std::string, AttachmentProvider*> providers)
: static_attachments_(std::move(static_attachments)), providers_(std::move(providers)) {
// Remove any static attachments or providers that return attachments not in |allowlist_|.
EraseNotAllowlisted(static_attachments_, allowlist);
EraseNotAllowlisted(providers_, allowlist);
for (const auto& k : allowlist) {
const auto num_providers = static_attachments_.count(k) + providers_.count(k);
FX_CHECK(num_providers == 1) << "Attachment \"" << k << "\" collected by " << num_providers
<< " providers";
}
}
::fpromise::promise<Attachments> AttachmentManager::GetAttachments(const zx::duration timeout) {
std::vector<std::string> keys;
std::vector<::fpromise::promise<AttachmentValue>> promises;
for (auto& [k, p] : providers_) {
keys.push_back(k);
promises.push_back(p->Get(timeout));
}
auto join = ::fpromise::join_promise_vector(std::move(promises));
using result_t = decltype(join)::value_type;
// Start with the static attachments and the add the dynamically collected values to them.
return join.and_then([keys, attachments = static_attachments_](result_t& results) mutable {
for (size_t i = 0; i < results.size(); ++i) {
attachments.insert({keys[i], results[i].take_value()});
// Consider any attachments without content as missing attachments.
if (auto& attachment = attachments.at(keys[i]);
attachment.HasValue() && attachment.Value().empty()) {
attachment = attachment.HasError() ? attachment.Error() : Error::kMissingValue;
}
}
return ::fpromise::ok(std::move(attachments));
});
}
void AttachmentManager::DropStaticAttachment(const AttachmentKey& key, const Error error) {
if (static_attachments_.find(key) == static_attachments_.end()) {
return;
}
static_attachments_.insert_or_assign(key, AttachmentValue(error));
}
} // namespace forensics::feedback