Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Strand.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2024, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "util/async/Concepts.hpp"
23#include "util/async/Operation.hpp"
24#include "util/async/context/impl/Cancellation.hpp"
25#include "util/async/context/impl/Execution.hpp"
26#include "util/async/context/impl/Timer.hpp"
27#include "util/async/context/impl/Utils.hpp"
28#include "util/async/impl/ErrorHandling.hpp"
29
30#include <chrono>
31#include <functional>
32#include <optional>
33#include <type_traits>
34
35namespace util::async::impl {
36
37template <
38 typename ParentContextType,
39 typename StopSourceType,
40 typename DispatcherType,
41 typename TimerContextProvider = impl::SelfContextProvider,
42 typename ErrorHandlerType = impl::DefaultErrorHandler>
44 std::reference_wrapper<ParentContextType> parentContext_;
45 typename ParentContextType::ContextHolderType::Strand context_;
47
48public:
49 static constexpr bool kIS_NOEXCEPT = noexcept(ErrorHandlerType::wrap([](auto&) { throw 0; }));
50
51 using ContextHolderType = typename ParentContextType::ContextHolderType::Strand;
52 using ExecutorType = typename ContextHolderType::Executor;
53 using StopToken = typename StopSourceType::Token;
54 using Timer =
55 typename ParentContextType::ContextHolderType::Timer; // timers are associated with the parent context
57
58 BasicStrand(ParentContextType& parent, auto&& strand)
59 : parentContext_{std::ref(parent)}, context_{std::forward<decltype(strand)>(strand)}
60 {
61 }
62
63 ~BasicStrand() = default;
64 BasicStrand(BasicStrand&&) = default;
65
66 BasicStrand(BasicStrand const&) = delete;
67
68 [[nodiscard]] auto
69 execute(
71 std::optional<std::chrono::milliseconds> timeout = std::nullopt
72 ) noexcept(kIS_NOEXCEPT)
73 {
74 return DispatcherType::dispatch(
75 context_,
76 impl::outcomeForHandler<StopSourceType>(fn),
77 ErrorHandlerType::wrap([this, timeout, fn = std::forward<decltype(fn)>(fn)](
78 auto& outcome, auto& stopSource, auto stopToken
79 ) mutable {
80 [[maybe_unused]] auto timeoutHandler = impl::getTimeoutHandleIfNeeded(
81 TimerContextProvider::getContext(parentContext_.get()), timeout, stopSource
82 );
83
84 using FnRetType = std::decay_t<decltype(fn(std::declval<StopToken>()))>;
85 if constexpr (std::is_void_v<FnRetType>) {
86 fn(std::move(stopToken));
87 outcome.setValue();
88 } else {
89 outcome.setValue(fn(std::move(stopToken)));
90 }
91 })
92 );
93 }
94
95 [[nodiscard]] auto
96 execute(SomeHandlerWith<StopToken> auto&& fn, SomeStdDuration auto timeout) noexcept(kIS_NOEXCEPT)
97 {
98 return execute(
99 std::forward<decltype(fn)>(fn),
100 std::make_optional(std::chrono::duration_cast<std::chrono::milliseconds>(timeout))
101 );
102 }
103
104 [[nodiscard]] auto
105 execute(SomeHandlerWithoutStopToken auto&& fn) noexcept(kIS_NOEXCEPT)
106 {
107 return DispatcherType::dispatch(
108 context_,
109 impl::outcomeForHandler<StopSourceType>(fn),
110 ErrorHandlerType::wrap([fn = std::forward<decltype(fn)>(fn)](auto& outcome) mutable {
111 using FnRetType = std::decay_t<decltype(fn())>;
112 if constexpr (std::is_void_v<FnRetType>) {
113 fn();
114 outcome.setValue();
115 } else {
116 outcome.setValue(fn());
117 }
118 })
119 );
120 }
121
122 [[nodiscard]] auto
123 executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto&& fn) noexcept(kIS_NOEXCEPT)
124 {
125 if constexpr (not std::is_same_v<decltype(TimerContextProvider::getContext(*this)), decltype(*this)>) {
126 return TimerContextProvider::getContext(*this).executeRepeatedly(interval, std::forward<decltype(fn)>(fn));
127 } else {
128 return RepeatedOperation(impl::extractAssociatedExecutor(*this), interval, std::forward<decltype(fn)>(fn));
129 }
130 }
131};
132
133} // namespace util::async::impl
The future side of async operations that automatically repeat until aborted.
Definition Operation.hpp:229
Definition Strand.hpp:43
Specifies the interface for a handler that can be invoked with the specified args.
Definition Concepts.hpp:162
Specifies the interface for a handler that can be stopped.
Definition Concepts.hpp:154
Specifies that the type must be some std::duration.
Definition Concepts.hpp:170