Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
ConfigConstraints.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 "rpc/common/APIVersion.hpp"
23#include "util/log/Logger.hpp"
24#include "util/newconfig/Error.hpp"
25#include "util/newconfig/Types.hpp"
26
27#include <fmt/core.h>
28#include <fmt/format.h>
29
30#include <algorithm>
31#include <array>
32#include <cstddef>
33#include <cstdint>
34#include <limits>
35#include <optional>
36#include <ostream>
37#include <string>
38#include <string_view>
39#include <variant>
40
41namespace util::config {
42class ValueView;
43class ConfigValue;
44
48static constexpr std::array<char const*, 7> kLOG_LEVELS = {
49 "trace",
50 "debug",
51 "info",
52 "warning",
53 "error",
54 "fatal",
55 "count",
56};
57
61static constexpr std::array<char const*, 5> kLOG_TAGS = {
62 "int",
63 "uint",
64 "null",
65 "none",
66 "uuid",
67};
68
72static constexpr std::array<char const*, 3> kLOAD_CACHE_MODE = {
73 "sync",
74 "async",
75 "none",
76};
77
81static constexpr std::array<char const*, 1> kDATABASE_TYPE = {"cassandra"};
82
86static constexpr std::array<char const*, 2> kPROCESSING_POLICY = {"parallel", "sequent"};
87
92public:
93 constexpr virtual ~Constraint() noexcept = default;
94
101 [[nodiscard]]
102 std::optional<Error>
103 checkConstraint(Value const& val) const
104 {
105 if (auto const maybeError = checkTypeImpl(val); maybeError.has_value())
106 return maybeError;
107 return checkValueImpl(val);
108 }
109
110protected:
120 template <std::size_t ArrSize>
121 constexpr std::string
122 makeErrorMsg(std::string_view key, Value const& value, std::array<char const*, ArrSize> arr) const
123 {
124 // Extract the value from the variant
125 auto const valueStr = std::visit([](auto const& v) { return fmt::format("{}", v); }, value);
126
127 // Create the error message
128 return fmt::format(
129 R"(You provided value "{}". Key "{}"'s value must be one of the following: {})",
130 valueStr,
131 key,
132 fmt::join(arr, ", ")
133 );
134 }
135
142 virtual std::optional<Error>
143 checkTypeImpl(Value const& val) const = 0;
144
151 virtual std::optional<Error>
152 checkValueImpl(Value const& val) const = 0;
153
159 virtual void
160 print(std::ostream& stream) const = 0;
161
169 friend std::ostream&
170 operator<<(std::ostream& stream, Constraint const& cons)
171 {
172 cons.print(stream);
173 return stream;
174 }
175};
176
180class PortConstraint final : public Constraint {
181public:
182 constexpr ~PortConstraint() noexcept override = default;
183
184private:
191 [[nodiscard]] std::optional<Error>
192 checkTypeImpl(Value const& port) const override;
193
200 [[nodiscard]] std::optional<Error>
201 checkValueImpl(Value const& port) const override;
202
208 void
209 print(std::ostream& stream) const override
210 {
211 stream << fmt::format("The minimum value is `{}`. The maximum value is `{}", kPORT_MIN, kPORT_MAX);
212 }
213
214 static constexpr uint32_t kPORT_MIN = 1;
215 static constexpr uint32_t kPORT_MAX = 65535;
216};
217
221class ValidIPConstraint final : public Constraint {
222public:
223 constexpr ~ValidIPConstraint() noexcept override = default;
224
225private:
232 [[nodiscard]] std::optional<Error>
233 checkTypeImpl(Value const& ip) const override;
234
241 [[nodiscard]] std::optional<Error>
242 checkValueImpl(Value const& ip) const override;
243
249 void
250 print(std::ostream& stream) const override
251 {
252 stream << "The value must be a valid IP address";
253 }
254};
255
261template <std::size_t ArrSize>
262class OneOf final : public Constraint {
263public:
270 constexpr OneOf(std::string_view key, std::array<char const*, ArrSize> arr) : key_{key}, arr_{arr}
271 {
272 }
273
274 constexpr ~OneOf() noexcept override = default;
275
276private:
283 [[nodiscard]] std::optional<Error>
284 checkTypeImpl(Value const& val) const override
285 {
286 if (!std::holds_alternative<std::string>(val))
287 return Error{fmt::format(R"(Key "{}"'s value must be a string)", key_)};
288 return std::nullopt;
289 }
290
297 [[nodiscard]] std::optional<Error>
298 checkValueImpl(Value const& val) const override
299 {
300 namespace rg = std::ranges;
301 auto const check = [&val](std::string_view name) { return std::get<std::string>(val) == name; };
302 if (rg::any_of(arr_, check))
303 return std::nullopt;
304
305 return Error{makeErrorMsg(key_, val, arr_)};
306 }
307
313 void
314 print(std::ostream& stream) const override
315 {
316 stream << fmt::format("The value must be one of the following: `{}`", fmt::join(arr_, ", "));
317 }
318
319 std::string_view key_;
320 std::array<char const*, ArrSize> arr_;
321};
322
326template <typename NumType>
327class NumberValueConstraint final : public Constraint {
328public:
335 constexpr NumberValueConstraint(NumType min, NumType max) : min_{min}, max_{max}
336 {
337 }
338
339 constexpr ~NumberValueConstraint() noexcept override = default;
340
341private:
348 [[nodiscard]] std::optional<Error>
349 checkTypeImpl(Value const& num) const override
350 {
351 if (!std::holds_alternative<int64_t>(num))
352 return Error{"Number must be of type integer"};
353 return std::nullopt;
354 }
355
362 [[nodiscard]] std::optional<Error>
363 checkValueImpl(Value const& num) const override
364 {
365 auto const numValue = std::get<int64_t>(num);
366 if (numValue >= static_cast<int64_t>(min_) && numValue <= static_cast<int64_t>(max_))
367 return std::nullopt;
368 return Error{fmt::format("Number must be between {} and {}", min_, max_)};
369 }
370
376 void
377 print(std::ostream& stream) const override
378 {
379 stream << fmt::format("The minimum value is `{}`. The maximum value is `{}`", min_, max_);
380 }
381
382 NumType min_;
383 NumType max_;
384};
385
389class PositiveDouble final : public Constraint {
390public:
391 constexpr ~PositiveDouble() noexcept override = default;
392
393private:
400 [[nodiscard]] std::optional<Error>
401 checkTypeImpl(Value const& num) const override;
402
409 [[nodiscard]] std::optional<Error>
410 checkValueImpl(Value const& num) const override;
411
417 void
418 print(std::ostream& stream) const override
419 {
420 stream << fmt::format("The value must be a positive double number");
421 }
422};
423
424static constinit PortConstraint gValidatePort{};
425static constinit ValidIPConstraint gValidateIp{};
426
427static constinit OneOf gValidateChannelName{"channel", Logger::kCHANNELS};
428static constinit OneOf gValidateLogLevelName{"log_level", kLOG_LEVELS};
429static constinit OneOf gValidateCassandraName{"database.type", kDATABASE_TYPE};
430static constinit OneOf gValidateLoadMode{"cache.load", kLOAD_CACHE_MODE};
431static constinit OneOf gValidateLogTag{"log_tag_style", kLOG_TAGS};
432static constinit OneOf gValidateProcessingPolicy{"server.processing_policy", kPROCESSING_POLICY};
433
434static constinit PositiveDouble gValidatePositiveDouble{};
435
436static constinit NumberValueConstraint<uint32_t> gValidateNumMarkers{1, 256};
437static constinit NumberValueConstraint<uint32_t> gValidateIOThreads{1, std::numeric_limits<uint16_t>::max()};
438
439static constinit NumberValueConstraint<uint16_t> gValidateUint16{
440 std::numeric_limits<uint16_t>::min(),
441 std::numeric_limits<uint16_t>::max()
442};
443
444// log file size minimum is 1mb, log rotation time minimum is 1hr
445static constinit NumberValueConstraint<uint32_t> gValidateLogSize{1, std::numeric_limits<uint32_t>::max()};
446static constinit NumberValueConstraint<uint32_t> gValidateLogRotationTime{1, std::numeric_limits<uint32_t>::max()};
447static constinit NumberValueConstraint<uint32_t> gValidateUint32{
448 std::numeric_limits<uint32_t>::min(),
449 std::numeric_limits<uint32_t>::max()
450};
451static constinit NumberValueConstraint<uint32_t> gValidateApiVersion{rpc::kAPI_VERSION_MIN, rpc::kAPI_VERSION_MAX};
452
453} // namespace util::config
An interface to enforce constraints on certain values within ClioConfigDefinition.
Definition ConfigConstraints.hpp:91
friend std::ostream & operator<<(std::ostream &stream, Constraint const &cons)
Custom output stream for constraint.
Definition ConfigConstraints.hpp:170
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.
std::optional< Error > checkConstraint(Value const &val) const
Check if the value meets the specific constraint.
Definition ConfigConstraints.hpp:103
constexpr std::string makeErrorMsg(std::string_view key, Value const &value, std::array< char const *, ArrSize > arr) const
Creates an error message for all constraints that must satisfy certain hard-coded values.
Definition ConfigConstraints.hpp:122
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:327
constexpr NumberValueConstraint(NumType min, NumType max)
Constructs a constraint where the number must be between min_ and max_.
Definition ConfigConstraints.hpp:335
A constraint class to ensure the provided value is one of the specified values in an array.
Definition ConfigConstraints.hpp:262
constexpr OneOf(std::string_view key, std::array< char const *, ArrSize > arr)
Constructs a constraint where the value must be one of the values in the provided array.
Definition ConfigConstraints.hpp:270
A constraint to ensure the port number is within a valid range.
Definition ConfigConstraints.hpp:180
A constraint to ensure a double number is positive.
Definition ConfigConstraints.hpp:389
A constraint to ensure the IP address is valid.
Definition ConfigConstraints.hpp:221
static constexpr uint32_t kAPI_VERSION_MIN
Minimum API version supported by this build.
Definition APIVersion.hpp:38
static constexpr uint32_t kAPI_VERSION_MAX
Maximum API version supported by this build.
Definition APIVersion.hpp:43
Displays the different errors when parsing user config.
Definition Error.hpp:31