1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_UPDATE_CLIENT_TIMED_CALLBACK_H_
#define COMPONENTS_UPDATE_CLIENT_TIMED_CALLBACK_H_
#include <memory>
#include <utility>
#include "base/cancelable_callback.h"
#include "base/functional/callback.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
namespace update_client {
// MakeTimedCallback posts a task to run `callback` after `timeout` with
// `timeout_args` on the current sequence, and returns a new callback to the
// caller that also calls `callback`. The returned callback must only be run on
// the current sequence.
//
// If the timeout occurs before the returned callback is
// run, the returned callback does nothing. It is safe to discard the returned
// callback in this case, or to call it.
//
// If the returned callback is run before the timeout, the timeout will do
// nothing.
//
// In either case, `callback` is guaranteed to run exactly once.
//
// For example, given:
// void HandleDecryptedContents(std::optional<std::string> plaintext);
// decryptAsync(ciphertext, base::BindOnce(&HandleDecryptedContents));
//
// It's possible to add a 30-second timeout:
// void HandleDecryptedContents(std::optional<std::string> plaintext);
// decryptAsync(
// cipher,
// MakeTimedCallback(
// base::BindOnce(&HandleDecryptedContents),
// base::Seconds(30),
// std::nullopt));
//
template <typename ReturnType, typename... CallbackArgs, typename... Args>
base::OnceCallback<ReturnType(CallbackArgs...)> MakeTimedCallback(
base::OnceCallback<ReturnType(CallbackArgs...)> callback,
base::TimeDelta timeout,
Args&&... timeout_args) {
auto wrapper = std::make_unique<
base::CancelableOnceCallback<ReturnType(CallbackArgs...)>>(
std::move(callback));
// Both callbacks must be constructed before either has a chance to run.
// `callback_1` will be run with the `timeout_args` after `timeout`.
// When either callback is run, they invalidate CancelableCallback's internal
// weak pointers, and the other callback becomes a no-op.
base::OnceCallback<ReturnType()> callback_1 =
base::BindOnce(wrapper->callback(), std::forward<Args>(timeout_args)...);
base::OnceCallback<ReturnType(CallbackArgs...)> callback_2 =
wrapper->callback();
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(
[](std::unique_ptr<
base::CancelableOnceCallback<ReturnType(CallbackArgs...)>>
/* wrapper */, // This callback takes ownership of `wrapper`.
base::OnceCallback<ReturnType()> callback_1) {
std::move(callback_1).Run();
},
std::move(wrapper), std::move(callback_1)),
timeout);
return callback_2;
}
} // namespace update_client
#endif // COMPONENTS_UPDATE_CLIENT_TIMED_CALLBACK_H_
|