| // Copyright 2023 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // Defines a helper function `RunRpcWithInputs` that | |
| // - Runs async RPC with a pre-defined input lists. | |
| // - For each iteration, check the RPC return value using the provided checker: | |
| // - If checker returns true, stop the loop and use `success_handler` to run | |
| // the callback function. | |
| // - If checker returns false, continue the loop with the next input. If all | |
| // the inputs are tried, use `fail_handler` to run the callback function. | |
| #ifndef RMAD_UTILS_RPC_UTILS_H_ | |
| #define RMAD_UTILS_RPC_UTILS_H_ | |
| #include <list> | |
| #include <utility> | |
| #include <base/functional/callback.h> | |
| namespace rmad { | |
| namespace internal { | |
| // An RPC takes an input, and runs a callback function with its outputs. | |
| template <typename RpcInputType, typename... RpcOutputTypes> | |
| using RpcType = base::RepeatingCallback<void( | |
| RpcInputType, base::OnceCallback<void(RpcOutputTypes...)>)>; | |
| // A checker takes the outputs of an RPC, and decides if we should accept the | |
| // current outputs (returns true), or continue to try the next input (returns | |
| // false). | |
| template <typename... RpcOutputTypes> | |
| using RpcOutputCheckerType = base::RepeatingCallback<bool(RpcOutputTypes...)>; | |
| // A success handler runs the callback function with customized arguments | |
| // depending on the outputs from the RPC. | |
| template <typename CallbackFuncType, typename... RpcOutputTypes> | |
| using SuccessHandlerType = | |
| base::OnceCallback<void(CallbackFuncType, RpcOutputTypes...)>; | |
| // A fail handler runs the callback function with customized arguments when none | |
| // of the outputs are accepted by the checker. | |
| template <typename CallbackFuncType> | |
| using FailHandlerType = base::OnceCallback<void(CallbackFuncType)>; | |
| // Forward declaration. | |
| template <typename CallbackFuncType, | |
| typename RpcInputType, | |
| typename... RpcOutputTypes> | |
| void OnRpcCompleted( | |
| CallbackFuncType callback_func, | |
| RpcType<RpcInputType, RpcOutputTypes...> rpc, | |
| std::list<RpcInputType> rpc_inputs, | |
| RpcOutputCheckerType<RpcOutputTypes...> rpc_output_checker, | |
| SuccessHandlerType<CallbackFuncType, RpcOutputTypes...> succees_handler, | |
| FailHandlerType<CallbackFuncType> fail_handler, | |
| RpcOutputTypes... reply); | |
| } // namespace internal | |
| template <typename CallbackFuncType, | |
| typename RpcInputType, | |
| typename... RpcOutputTypes> | |
| void RunRpcWithInputs( | |
| CallbackFuncType callback_func, | |
| internal::RpcType<RpcInputType, RpcOutputTypes...> rpc, | |
| std::list<RpcInputType> rpc_inputs, | |
| internal::RpcOutputCheckerType<RpcOutputTypes...> rpc_output_checker, | |
| internal::SuccessHandlerType<CallbackFuncType, RpcOutputTypes...> | |
| success_handler, | |
| internal::FailHandlerType<CallbackFuncType> fail_handler) { | |
| if (!rpc_inputs.empty()) { | |
| // Run RPC with the first input. | |
| RpcInputType input = rpc_inputs.front(); | |
| rpc_inputs.pop_front(); | |
| rpc.Run(input, base::BindOnce( | |
| &internal::OnRpcCompleted<CallbackFuncType, RpcInputType, | |
| RpcOutputTypes...>, | |
| std::move(callback_func), rpc, std::move(rpc_inputs), | |
| rpc_output_checker, std::move(success_handler), | |
| std::move(fail_handler))); | |
| } else { | |
| // No input left. Use the fail handler to run the callback function. | |
| std::move(fail_handler).Run(std::move(callback_func)); | |
| } | |
| } | |
| namespace internal { | |
| template <typename CallbackFuncType, | |
| typename RpcInputType, | |
| typename... RpcOutputTypes> | |
| void OnRpcCompleted( | |
| CallbackFuncType callback_func, | |
| RpcType<RpcInputType, RpcOutputTypes...> rpc, | |
| std::list<RpcInputType> rpc_inputs, | |
| RpcOutputCheckerType<RpcOutputTypes...> rpc_output_checker, | |
| SuccessHandlerType<CallbackFuncType, RpcOutputTypes...> success_handler, | |
| FailHandlerType<CallbackFuncType> fail_handler, | |
| RpcOutputTypes... reply) { | |
| if (rpc_output_checker.Run(reply...)) { | |
| // Use the success handler to run the callback function. | |
| std::move(success_handler).Run(std::move(callback_func), reply...); | |
| } else { | |
| // Try the next input. | |
| RunRpcWithInputs(std::move(callback_func), rpc, std::move(rpc_inputs), | |
| rpc_output_checker, std::move(success_handler), | |
| std::move(fail_handler)); | |
| } | |
| } | |
| } // namespace internal | |
| } // namespace rmad | |
| #endif // RMAD_UTILS_RPC_UTILS_H_ |