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 std::string valuesStream;
317 std::ranges::for_each(arr_, [&valuesStream](std::string const& elem) {
318 valuesStream += fmt::format(" `{}`,", elem);
319 });
320 // replace the last "," with "."
321 valuesStream.back() = '.';
322 stream << fmt::format("The value must be one of the following:{}", valuesStream);
323 }
324
325 std::string_view key_;
326 std::array<char const*, ArrSize> arr_;
327};
328
332template <typename NumType>
333class NumberValueConstraint final : public Constraint {
334public:
341 constexpr NumberValueConstraint(NumType min, NumType max) : min_{min}, max_{max}
342 {
343 }
344
345 constexpr ~NumberValueConstraint() noexcept override = default;
346
347private:
354 [[nodiscard]] std::optional<Error>
355 checkTypeImpl(Value const& num) const override
356 {
357 if (!std::holds_alternative<int64_t>(num))
358 return Error{"Number must be of type integer"};
359 return std::nullopt;
360 }
361
368 [[nodiscard]] std::optional<Error>
369 checkValueImpl(Value const& num) const override
370 {
371 auto const numValue = std::get<int64_t>(num);
372 if (numValue >= static_cast<int64_t>(min_) && numValue <= static_cast<int64_t>(max_))
373 return std::nullopt;
374 return Error{fmt::format("Number must be between {} and {}", min_, max_)};
375 }
376
382 void
383 print(std::ostream& stream) const override
384 {
385 stream << fmt::format("The minimum value is `{}`. The maximum value is `{}`.", min_, max_);
386 }
387
388 NumType min_;
389 NumType max_;
390};
391
395class PositiveDouble final : public Constraint {
396public:
397 constexpr ~PositiveDouble() noexcept override = default;
398
399private:
406 [[nodiscard]] std::optional<Error>
407 checkTypeImpl(Value const& num) const override;
408
415 [[nodiscard]] std::optional<Error>
416 checkValueImpl(Value const& num) const override;
417
423 void
424 print(std::ostream& stream) const override
425 {
426 stream << "The value must be a positive double number.";
427 }
428};
429
430static constinit PortConstraint gValidatePort{};
431static constinit ValidIPConstraint gValidateIp{};
432
433static constinit OneOf gValidateChannelName{"channel", Logger::kCHANNELS};
434static constinit OneOf gValidateLogLevelName{"log_level", kLOG_LEVELS};
435static constinit OneOf gValidateCassandraName{"database.type", kDATABASE_TYPE};
436static constinit OneOf gValidateLoadMode{"cache.load", kLOAD_CACHE_MODE};
437static constinit OneOf gValidateLogTag{"log_tag_style", kLOG_TAGS};
438static constinit OneOf gValidateProcessingPolicy{"server.processing_policy", kPROCESSING_POLICY};
439
440static constinit PositiveDouble gValidatePositiveDouble{};
441
442static constinit NumberValueConstraint<uint16_t> gValidateNumMarkers{1, 256};
443static constinit NumberValueConstraint<uint16_t> gValidateNumCursors{0, std::numeric_limits<uint16_t>::max()};
444
445// replication factor can be 0
446static constinit NumberValueConstraint<uint16_t> gValidateReplicationFactor{0, std::numeric_limits<uint16_t>::max()};
447
448static constinit NumberValueConstraint<uint16_t> gValidateUint16{1, std::numeric_limits<uint16_t>::max()};
449
450static constinit NumberValueConstraint<uint32_t> gValidateUint32{1, std::numeric_limits<uint32_t>::max()};
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:333
constexpr NumberValueConstraint(NumType min, NumType max)
Constructs a constraint where the number must be between min_ and max_.
Definition ConfigConstraints.hpp:341
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:395
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