// Copyright 2014 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.
#ifndef LIBBRILLO_BRILLO_DBUS_ASYNC_EVENT_SEQUENCER_H_
#define LIBBRILLO_BRILLO_DBUS_ASYNC_EVENT_SEQUENCER_H_
#include <set>
#include <string>
#include <vector>
#include <base/bind.h>
#include <base/macros.h>
#include <base/memory/ref_counted.h>
#include <brillo/brillo_export.h>
namespace brillo {
namespace dbus_utils {
// A helper class for coordinating the multiple async tasks. A consumer
// may grab any number of callbacks via Get*Handler() and schedule a list
// of completion actions to take. When all handlers obtained via Get*Handler()
// have been called, the AsyncEventSequencer will call its CompletionActions.
//
// Usage:
//
// void Init(const base::Callback<void(bool success)> cb) {
// scoped_refptr<AsyncEventSequencer> sequencer(
// new AsyncEventSequencer());
// one_delegate_needing_init_.Init(sequencer->GetHandler(
// "my delegate failed to init", false));
// dbus_init_delegate_.Init(sequencer->GetExportHandler(
// "org.test.Interface", "ExposedMethodName",
// "another delegate is flaky", false));
// sequencer->OnAllTasksCompletedCall({cb});
// }
class BRILLO_EXPORT AsyncEventSequencer
: public base::RefCounted<AsyncEventSequencer> {
public:
using Handler = base::Callback<void(bool success)>;
using ExportHandler = base::Callback<void(const std::string& interface_name,
const std::string& method_name,
bool success)>;
using CompletionAction = base::Callback<void(bool all_succeeded)>;
using CompletionTask = base::Callback<void(void)>;
AsyncEventSequencer();
// Get a Finished handler callback. Each callback is "unique" in the sense
// that subsequent calls to GetHandler() will create new handlers
// which will need to be called before completion actions are run.
Handler GetHandler(const std::string& descriptive_message,
bool failure_is_fatal);
// Like GetHandler except with a signature tailored to
// ExportedObject's ExportMethod callback requirements. Will also assert
// that the passed interface/method names from ExportedObject are correct.
ExportHandler GetExportHandler(const std::string& interface_name,
const std::string& method_name,
const std::string& descriptive_message,
bool failure_is_fatal);
// Once all handlers obtained via GetHandler have run,
// we'll run each CompletionAction, then discard our references.
// No more handlers may be obtained after this call.
void OnAllTasksCompletedCall(std::vector<CompletionAction> actions);
// Wrap a CompletionTask with a function that discards the result.
// This CompletionTask retains no references to the AsyncEventSequencer.
static CompletionAction WrapCompletionTask(const CompletionTask& task);
// Create a default CompletionAction that doesn't do anything when called.
static CompletionAction GetDefaultCompletionAction();
private:
// We'll partially bind this function before giving it back via
// GetHandler. Note that the returned callbacks have
// references to *this, which gives us the neat property that we'll
// destroy *this only when all our callbacks have been destroyed.
BRILLO_PRIVATE void HandleFinish(int registration_number,
const std::string& error_message,
bool failure_is_fatal,
bool success);
// Similar to HandleFinish.
BRILLO_PRIVATE void HandleDBusMethodExported(
const Handler& finish_handler,
const std::string& expected_interface_name,
const std::string& expected_method_name,
const std::string& actual_interface_name,
const std::string& actual_method_name,
bool success);
BRILLO_PRIVATE void RetireRegistration(int registration_number);
BRILLO_PRIVATE void CheckForFailure(bool failure_is_fatal,
bool success,
const std::string& error_message);
BRILLO_PRIVATE void PossiblyRunCompletionActions();
bool started_{false};
int registration_counter_{0};
std::set<int> outstanding_registrations_;
std::vector<CompletionAction> completion_actions_;
bool had_failures_{false};
// Ref counted objects have private destructors.
~AsyncEventSequencer();
friend class base::RefCounted<AsyncEventSequencer>;
DISALLOW_COPY_AND_ASSIGN(AsyncEventSequencer);
};
} // namespace dbus_utils
} // namespace brillo
#endif // LIBBRILLO_BRILLO_DBUS_ASYNC_EVENT_SEQUENCER_H_