Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Registry.hpp
1#pragma once
2
3#include "etl/Models.hpp"
4#include "etl/RegistryInterface.hpp"
5#include "etl/SystemState.hpp"
6
7#include <xrpl/protocol/TxFormats.h>
8
9#include <concepts>
10#include <cstdint>
11#include <functional>
12#include <string>
13#include <tuple>
14#include <type_traits>
15#include <utility>
16#include <vector>
17
18namespace etl::impl {
19
20template <typename T>
21concept HasLedgerDataHook = requires(T p) {
22 { p.onLedgerData(std::declval<model::LedgerData>()) } -> std::same_as<void>;
23};
24
25template <typename T>
26concept HasInitialDataHook = requires(T p) {
27 { p.onInitialData(std::declval<model::LedgerData>()) } -> std::same_as<void>;
28};
29
30template <typename T>
31concept HasTransactionHook = requires(T p) {
32 { p.onTransaction(uint32_t{}, std::declval<model::Transaction>()) } -> std::same_as<void>;
33};
34
35template <typename T>
36concept HasObjectHook = requires(T p) {
37 { p.onObject(uint32_t{}, std::declval<model::Object>()) } -> std::same_as<void>;
38};
39
40template <typename T>
41concept HasInitialTransactionHook = requires(T p) {
42 {
43 p.onInitialTransaction(uint32_t{}, std::declval<model::Transaction>())
44 } -> std::same_as<void>;
45};
46
47template <typename T>
48concept HasInitialObjectsHook = requires(T p) {
49 {
50 p.onInitialObjects(uint32_t{}, std::declval<std::vector<model::Object>>(), std::string{})
51 } -> std::same_as<void>;
52};
53
54template <typename T>
55concept HasInitialObjectHook = requires(T p) {
56 { p.onInitialObject(uint32_t{}, std::declval<model::Object>()) } -> std::same_as<void>;
57};
58
59template <typename T>
60concept ContainsSpec = std::decay_t<T>::spec::kSPEC_TAG;
61
62template <typename T>
67
68template <typename T>
72
73template <typename T>
75
76template <SomeExtension... Ps>
77class Registry : public RegistryInterface {
78 std::reference_wrapper<SystemState const> state_;
79 std::tuple<Ps...> store_;
80
81 static_assert(
83 "Spec must be specified when 'onTransaction' function exists."
84 );
85
86 static_assert(
88 ...),
89 "Spec must be specified when 'onInitialTransaction' function exists."
90 );
91
92public:
93 explicit constexpr Registry(SystemState const& state, SomeExtension auto&&... exts)
94 requires(std::is_same_v<std::decay_t<decltype(exts)>, std::decay_t<Ps>> and ...)
95 : state_{state}, store_(std::forward<Ps>(exts)...)
96 {
97 }
98
99 ~Registry() override = default;
100 Registry(Registry const&) = delete;
101 Registry(Registry&&) = default;
102 Registry&
103 operator=(Registry const&) = delete;
104 Registry&
105 operator=(Registry&&) = default;
106
107 constexpr void
109 {
110 // send entire batch of data at once
111 {
112 auto const expand = [&](auto& p) {
113 if constexpr (requires { p.onLedgerData(data); })
114 executeIfAllowed(p, [&data](auto& p) { p.onLedgerData(data); });
115 };
116
117 std::apply([&expand](auto&&... xs) { (expand(xs), ...); }, store_);
118 }
119
120 // send filtered transactions
121 {
122 auto const expand = [&]<typename P>(P& p, model::Transaction const& t) {
123 if constexpr (requires { p.onTransaction(data.seq, t); }) {
124 if (std::decay_t<P>::spec::wants(t.type))
125 executeIfAllowed(p, [&data, &t](auto& p) { p.onTransaction(data.seq, t); });
126 }
127 };
128
129 for (auto const& t : data.transactions) {
130 std::apply([&expand, &t](auto&&... xs) { (expand(xs, t), ...); }, store_);
131 }
132 }
133
134 // send per object path
135 {
136 auto const expand = [&]<typename P>(P&& p, model::Object const& o) {
137 if constexpr (requires { p.onObject(data.seq, o); })
138 executeIfAllowed(p, [&data, &o](auto& p) { p.onObject(data.seq, o); });
139 };
140
141 for (auto const& obj : data.objects) {
142 std::apply([&expand, &obj](auto&&... xs) { (expand(xs, obj), ...); }, store_);
143 }
144 }
145 }
146
147 constexpr void
149 uint32_t seq,
150 std::vector<model::Object> const& data,
151 std::string lastKey
152 ) override
153 {
154 // send entire vector path
155 {
156 auto const expand = [&](auto&& p) {
157 if constexpr (requires { p.onInitialObjects(seq, data, lastKey); }) {
158 executeIfAllowed(p, [seq, &data, &lastKey](auto& p) {
159 p.onInitialObjects(seq, data, lastKey);
160 });
161 }
162 };
163
164 std::apply([&expand](auto&&... xs) { (expand(xs), ...); }, store_);
165 }
166
167 // send per object path
168 {
169 auto const expand = [&]<typename P>(P&& p, model::Object const& o) {
170 if constexpr (requires { p.onInitialObject(seq, o); })
171 executeIfAllowed(p, [seq, &o](auto& p) { p.onInitialObject(seq, o); });
172 };
173
174 for (auto const& obj : data) {
175 std::apply([&expand, &obj](auto&&... xs) { (expand(xs, obj), ...); }, store_);
176 }
177 }
178 }
179
180 constexpr void
182 {
183 // send entire batch path
184 {
185 auto const expand = [&](auto&& p) {
186 if constexpr (requires { p.onInitialData(data); })
187 executeIfAllowed(p, [&data](auto& p) { p.onInitialData(data); });
188 };
189
190 std::apply([&expand](auto&&... xs) { (expand(xs), ...); }, store_);
191 }
192
193 // send per tx path
194 {
195 auto const expand = [&]<typename P>(P&& p, model::Transaction const& tx) {
196 if constexpr (requires { p.onInitialTransaction(data.seq, tx); }) {
197 if (std::decay_t<P>::spec::wants(tx.type)) {
198 executeIfAllowed(p, [&data, &tx](auto& p) {
199 p.onInitialTransaction(data.seq, tx);
200 });
201 }
202 }
203 };
204
205 for (auto const& tx : data.transactions) {
206 std::apply([&expand, &tx](auto&&... xs) { (expand(xs, tx), ...); }, store_);
207 }
208 }
209 }
210
211private:
212 void
213 executeIfAllowed(auto& p, auto&& fn)
214 {
215 if constexpr (requires { p.allowInReadonly(); }) {
216 if (state_.get().isWriting or p.allowInReadonly())
217 fn(p);
218 } else {
219 if (state_.get().isWriting)
220 fn(p);
221 }
222 }
223};
224
225static auto
226makeRegistry(SystemState const& state, auto&&... exts)
227{
228 return std::make_unique<Registry<std::decay_t<decltype(exts)>...>>(
229 state, std::forward<decltype(exts)>(exts)...
230 );
231}
232
233} // namespace etl::impl
Definition Registry.hpp:77
constexpr void dispatch(model::LedgerData const &data) override
Dispatch an entire ledger diff.
Definition Registry.hpp:108
constexpr void dispatchInitialObjects(uint32_t seq, std::vector< model::Object > const &data, std::string lastKey) override
Dispatch initial objects.
Definition Registry.hpp:148
constexpr void dispatchInitialData(model::LedgerData const &data) override
Dispatch initial ledger data.
Definition Registry.hpp:181
Definition Registry.hpp:60
Definition Registry.hpp:63
Definition Registry.hpp:26
Definition Registry.hpp:55
Definition Registry.hpp:48
Definition Registry.hpp:41
Definition Registry.hpp:21
Definition Registry.hpp:36
Definition Registry.hpp:31
Definition Registry.hpp:69
Definition Registry.hpp:74
This namespace implements the data access layer and related components.
Definition AmendmentCenter.cpp:56
The interface for a registry that can dispatch transactions and objects to extensions.
Definition RegistryInterface.hpp:54
Represents the state of the ETL subsystem.
Definition SystemState.hpp:20
Represents an entire ledger diff worth of transactions and objects.
Definition Models.hpp:124
Represents a single object on the ledger.
Definition Models.hpp:86
Represents a single transaction on the ledger.
Definition Models.hpp:52