blob: 5ca34dd99fbaab4d159d65b37f5aa581f79656bf [file] [log] [blame]
// Copyright 2022 The Chromium OS 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 "missive/util/disconnectable_client.h"
#include <memory>
#include <utility>
#include <base/callback.h>
#include <base/containers/fixed_flat_map.h>
#include <base/logging.h>
#include <base/memory/scoped_refptr.h>
#include <base/memory/weak_ptr.h>
#include <base/sequence_checker.h>
#include <base/task/sequenced_task_runner.h>
#include "missive/util/status.h"
namespace reporting {
DisconnectableClient::DisconnectableClient(
scoped_refptr<base::SequencedTaskRunner> task_runner)
: task_runner_(task_runner) {}
DisconnectableClient::~DisconnectableClient() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
SetAvailability(/*is_available=*/false);
}
void DisconnectableClient::MaybeMakeCall(std::unique_ptr<Delegate> delegate) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Bail out, if missive daemon is not available over dBus.
if (!is_available_) {
delegate->Respond(
Status(reporting::error::UNAVAILABLE, "Service is unavailable"));
return;
}
// Add the delegate to the map.
const auto id = ++last_id_;
auto res = outstanding_delegates_.emplace(id, std::move(delegate));
// Make a call, resume on CallResponded, when response is received.
res.first->second->DoCall(base::BindOnce(&DisconnectableClient::CallResponded,
weak_ptr_factory_.GetWeakPtr(), id));
}
void DisconnectableClient::CallResponded(uint64_t id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = outstanding_delegates_.find(id);
if (it == outstanding_delegates_.end()) {
// Callback has already been removed, no action needed.
return;
}
// Remove delegate from |outstanding_delegates_|.
const auto delegate = std::move(it->second);
outstanding_delegates_.erase(it);
// Respond through the |delegate|.
delegate->Respond(Status::StatusOK());
}
void DisconnectableClient::SetAvailability(bool is_available) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
is_available_ = is_available;
LOG(WARNING) << "Service became " << (is_available_ ? "" : "un")
<< "available";
if (!is_available_) {
// Cancel all pending calls.
while (!outstanding_delegates_.empty()) {
// Remove the first delegate from |outstanding_delegates_|.
const auto delegate = std::move(outstanding_delegates_.begin()->second);
outstanding_delegates_.erase(outstanding_delegates_.begin());
// Respond through the |delegate|.
delegate->Respond(
Status(reporting::error::UNAVAILABLE, "Service is unavailable"));
}
}
}
} // namespace reporting