Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
ConfigConstraints.hpp
1#pragma once
2
3#include "rpc/common/APIVersion.hpp"
4#include "util/config/Error.hpp"
5#include "util/config/Types.hpp"
6#include "util/log/Logger.hpp"
7
8#include <fmt/format.h>
9#include <fmt/ranges.h>
10
11#include <algorithm>
12#include <array>
13#include <cstddef>
14#include <cstdint>
15#include <limits>
16#include <optional>
17#include <ostream>
18#include <string>
19#include <string_view>
20#include <variant>
21
22namespace util::config {
23class ValueView;
24class ConfigValue;
25
29static constexpr std::array<std::string_view, 6> kLogLevels = {
30 "trace",
31 "debug",
32 "info",
33 "warning",
34 "error",
35 "fatal",
36};
37
41static constexpr std::array<std::string_view, 5> kLogTags = {
42 "int",
43 "uint",
44 "null",
45 "none",
46 "uuid",
47};
48
52static constexpr std::array<std::string_view, 3> kLoadCacheMode = {
53 "sync",
54 "async",
55 "none",
56};
57
61static constexpr std::array<std::string_view, 1> kDatabaseType = {"cassandra"};
62
66static constexpr std::array<std::string_view, 2> kProcessingPolicy = {"parallel", "sequent"};
67
71static constexpr std::array<std::string_view, 2> kProvider = {"cassandra", "aws_keyspace"};
72
77public:
78 constexpr virtual ~Constraint() noexcept = default;
79
86 [[nodiscard]]
87 std::optional<Error>
88 checkConstraint(Value const& val) const
89 {
90 if (auto const maybeError = checkTypeImpl(val); maybeError.has_value())
91 return maybeError;
92 return checkValueImpl(val);
93 }
94
95protected:
106 template <std::size_t ArrSize>
107 [[nodiscard]] constexpr std::string
109 std::string_view key,
110 Value const& value,
111 std::array<std::string_view, ArrSize> arr
112 ) const
113 {
114 // Extract the value from the variant
115 auto const valueStr = std::visit([](auto const& v) { return fmt::format("{}", v); }, value);
116
117 // Create the error message
118 return fmt::format(
119 R"(You provided value "{}". Key "{}"'s value must be one of the following: {})",
120 valueStr,
121 key,
122 fmt::join(arr, ", ")
123 );
124 }
125
132 [[nodiscard]] virtual std::optional<Error>
133 checkTypeImpl(Value const& val) const = 0;
134
141 [[nodiscard]] virtual std::optional<Error>
142 checkValueImpl(Value const& val) const = 0;
143
149 virtual void
150 print(std::ostream& stream) const = 0;
151
159 friend std::ostream&
160 operator<<(std::ostream& stream, Constraint const& cons)
161 {
162 cons.print(stream);
163 return stream;
164 }
165};
166
170class PortConstraint final : public Constraint {
171public:
172 constexpr ~PortConstraint() noexcept override = default;
173
174private:
181 [[nodiscard]] std::optional<Error>
182 checkTypeImpl(Value const& port) const override;
183
190 [[nodiscard]] std::optional<Error>
191 checkValueImpl(Value const& port) const override;
192
198 void
199 print(std::ostream& stream) const override
200 {
201 stream << fmt::format(
202 "The minimum value is `{}`. The maximum value is `{}`.", kPortMin, kPortMax
203 );
204 }
205
206 static constexpr uint32_t kPortMin = 1;
207 static constexpr uint32_t kPortMax = 65535;
208};
209
213class ValidIPConstraint final : public Constraint {
214public:
215 constexpr ~ValidIPConstraint() noexcept override = default;
216
217private:
224 [[nodiscard]] std::optional<Error>
225 checkTypeImpl(Value const& ip) const override;
226
233 [[nodiscard]] std::optional<Error>
234 checkValueImpl(Value const& ip) const override;
235
241 void
242 print(std::ostream& stream) const override
243 {
244 stream << "The value must be a valid IP address.";
245 }
246};
247
254template <std::size_t ArrSize>
255class OneOf final : public Constraint {
256public:
264 constexpr OneOf(std::string_view key, std::array<std::string_view, ArrSize> arr)
265 : key_{key}, arr_{arr}
266 {
267 }
268
269 constexpr ~OneOf() noexcept override = default;
270
271private:
278 [[nodiscard]] std::optional<Error>
279 checkTypeImpl(Value const& val) const override
280 {
281 if (!std::holds_alternative<std::string>(val))
282 return Error{fmt::format(R"(Key "{}"'s value must be a string)", key_)};
283 return std::nullopt;
284 }
285
292 [[nodiscard]] std::optional<Error>
293 checkValueImpl(Value const& val) const override
294 {
295 namespace rg = std::ranges;
296 auto const check = [&val](std::string_view name) {
297 return std::get<std::string>(val) == name;
298 };
299 if (rg::any_of(arr_, check))
300 return std::nullopt;
301
302 return Error{makeErrorMsg(key_, val, arr_)};
303 }
304
310 void
311 print(std::ostream& stream) const override
312 {
313 std::string valuesStream;
314 std::ranges::for_each(arr_, [&valuesStream](std::string_view elem) {
315 valuesStream += fmt::format(" `{}`,", elem);
316 });
317 // replace the last "," with "."
318 valuesStream.back() = '.';
319 stream << fmt::format("The value must be one of the following:{}", valuesStream);
320 }
321
322 std::string_view key_;
323 std::array<std::string_view, ArrSize> arr_;
324};
325
329template <typename NumType>
330class NumberValueConstraint final : public Constraint {
331public:
338 constexpr NumberValueConstraint(NumType min, NumType max) : min_{min}, max_{max}
339 {
340 }
341
342 constexpr ~NumberValueConstraint() noexcept override = default;
343
344private:
351 [[nodiscard]] std::optional<Error>
352 checkTypeImpl(Value const& num) const override
353 {
354 if (!std::holds_alternative<int64_t>(num))
355 return Error{"Number must be of type integer"};
356 return std::nullopt;
357 }
358
365 [[nodiscard]] std::optional<Error>
366 checkValueImpl(Value const& num) const override
367 {
368 auto const numValue = std::get<int64_t>(num);
369 if (numValue >= static_cast<int64_t>(min_) && numValue <= static_cast<int64_t>(max_))
370 return std::nullopt;
371 return Error{fmt::format("Number must be between {} and {}", min_, max_)};
372 }
373
379 void
380 print(std::ostream& stream) const override
381 {
382 stream << fmt::format("The minimum value is `{}`. The maximum value is `{}`.", min_, max_);
383 }
384
385 NumType min_;
386 NumType max_;
387};
388
392class PositiveDouble final : public Constraint {
393public:
394 constexpr ~PositiveDouble() noexcept override = default;
395
396private:
403 [[nodiscard]] std::optional<Error>
404 checkTypeImpl(Value const& num) const override;
405
412 [[nodiscard]] std::optional<Error>
413 checkValueImpl(Value const& num) const override;
414
420 void
421 print(std::ostream& stream) const override
422 {
423 stream << "The value must be a positive double number.";
424 }
425};
426
430class RpcNameConstraint final : public Constraint {
431private:
438 [[nodiscard]] std::optional<Error>
439 checkTypeImpl(Value const& value) const override;
440
447 [[nodiscard]] std::optional<Error>
448 checkValueImpl(Value const& value) const override;
449
455 void
456 print(std::ostream& stream) const override
457 {
458 stream << "Checks whether provided RPC name is valid";
459 }
460};
461
462static constinit PortConstraint gValidatePort{};
463static constinit ValidIPConstraint gValidateIp{};
464
465static constinit OneOf gValidateChannelName{"channel", Logger::kChannels};
466static constinit OneOf gValidateLogLevelName{"log.level", kLogLevels};
467static constinit OneOf gValidateCassandraName{"database.type", kDatabaseType};
468static constinit OneOf gValidateLoadMode{"cache.load", kLoadCacheMode};
469static constinit OneOf gValidateLogTag{"log.tag_style", kLogTags};
470static constinit OneOf gValidateProcessingPolicy{"server.processing_policy", kProcessingPolicy};
471static constinit OneOf gValidateProvider{"database.cassandra.provider", kProvider};
472
473static constinit PositiveDouble gValidatePositiveDouble{};
474
475static constinit NumberValueConstraint<uint16_t> gValidateNumMarkers{1, 256};
476static constinit NumberValueConstraint<uint16_t> gValidateNumCursors{
477 0,
478 std::numeric_limits<uint16_t>::max()
479};
480
481// replication factor can be 0
482static constinit NumberValueConstraint<uint16_t> gValidateReplicationFactor{
483 0,
484 std::numeric_limits<uint16_t>::max()
485};
486
487static constinit NumberValueConstraint<uint16_t> gValidateUint16{
488 1,
489 std::numeric_limits<uint16_t>::max()
490};
491
492static constinit NumberValueConstraint<uint32_t> gValidateUint32{
493 1,
494 std::numeric_limits<uint32_t>::max()
495};
496static constinit NumberValueConstraint<uint32_t> gValidateNonNegativeUint32{
497 0,
498 std::numeric_limits<uint32_t>::max()
499};
500static constinit NumberValueConstraint<uint32_t> gValidateApiVersion{
503};
504
505static constinit RpcNameConstraint gRpcNameConstraint{};
506} // namespace util::config
Represents the config values for Json/Yaml config.
Definition ConfigValue.hpp:28
An interface to enforce constraints on certain values within ClioConfigDefinition.
Definition ConfigConstraints.hpp:76
friend std::ostream & operator<<(std::ostream &stream, Constraint const &cons)
Custom output stream for constraint.
Definition ConfigConstraints.hpp:160
virtual void print(std::ostream &stream) const =0
Prints to the output stream for this specific constraint.
virtual std::optional< Error > checkValueImpl(Value const &val) const =0
Check if the value is within the constraint.
constexpr std::string makeErrorMsg(std::string_view key, Value const &value, std::array< std::string_view, ArrSize > arr) const
Creates an error message for all constraints that must satisfy certain hard-coded values.
Definition ConfigConstraints.hpp:108
std::optional< Error > checkConstraint(Value const &val) const
Check if the value meets the specific constraint.
Definition ConfigConstraints.hpp:88
virtual std::optional< Error > checkTypeImpl(Value const &val) const =0
Check if the value is of a correct type for the constraint.
A constraint class to ensure an integer value is between two numbers (inclusive).
Definition ConfigConstraints.hpp:330
constexpr NumberValueConstraint(NumType min, NumType max)
Constructs a constraint where the number must be between min_ and max_.
Definition ConfigConstraints.hpp:338
A constraint class to ensure the provided value is one of the specified values in an array.
Definition ConfigConstraints.hpp:255
constexpr OneOf(std::string_view key, std::array< std::string_view, ArrSize > arr)
Constructs a constraint where the value must be one of the values in the provided array.
Definition ConfigConstraints.hpp:264
A constraint to ensure the port number is within a valid range.
Definition ConfigConstraints.hpp:170
A constraint to ensure a double number is positive.
Definition ConfigConstraints.hpp:392
A constraint to ensure the value is a valid RPC command name.
Definition ConfigConstraints.hpp:430
A constraint to ensure the IP address is valid.
Definition ConfigConstraints.hpp:213
Provides view into ConfigValues that represents values in Clio Config.
Definition ValueView.hpp:27
static constexpr uint32_t kApiVersionMin
Minimum API version supported by this build.
Definition APIVersion.hpp:19
static constexpr uint32_t kApiVersionMax
Maximum API version supported by this build.
Definition APIVersion.hpp:24
Displays the different errors when parsing user config.
Definition Error.hpp:12