larra/library/include/larra/stream_error.hpp

118 lines
5.6 KiB
C++

#pragma once
#include <libxml++/libxml++.h>
#include <larra/utils.hpp>
#include <variant>
namespace larra::xmpp {
namespace error::stream {
struct BaseError : std::exception {};
// DO NOT MOVE TO ANOTHER NAMESPACE(where no heirs). VIA friend A FUNCTION IS ADDED THAT VIA ADL WILL BE SEARCHED FOR HEIRS
// C++20 modules very unstable in clangd :(
template <typename T>
struct ErrorImpl : BaseError {
static constexpr auto kDefaultName = "stream:error";
static inline const auto kKebabCaseName = static_cast<std::string>(utils::ToKebabCaseName<T>());
static constexpr auto kErrorMessage = [] -> std::string_view {
static constexpr auto name = nameof::nameof_short_type<T>();
static constexpr auto str = [] {
return std::array{std::string_view{"Stream Error: "}, std::string_view{name}, std::string_view{"\0", 1}} | std::views::join;
};
static constexpr auto array = str() | std::ranges::to<utils::RangeToWrapper<std::array<char, std::ranges::distance(str())>>>();
return {array.data(), array.size() - 1};
}();
static constexpr auto TryParse(xmlpp::Element* element) -> std::optional<T> {
return element ? element->get_first_child(kKebabCaseName) ? std::optional{T{}} : std::nullopt : std::nullopt;
}
static constexpr auto Parse(xmlpp::Element* element) -> T {
return TryParse(element).value();
}
friend constexpr auto operator<<(xmlpp::Element* element, const T& obj) -> void {
auto node = element->add_child_element(kKebabCaseName);
node->set_namespace_declaration("urn:ietf:params:xml:ns:xmpp-streams");
}
[[nodiscard]] constexpr auto what() const noexcept -> const char* override {
return kErrorMessage.data();
}
};
// Helper class to prevent parsing response stream into an expected return type if its name is a 'stream:error'
struct UnknownXmppError : BaseError {
static constexpr auto kDefaultName = "stream:error";
static constexpr std::string_view kErrorMessage = "Unknown XMPP stream error";
static constexpr auto TryParse(xmlpp::Element* element) {
return std::optional{UnknownXmppError{}};
}
static constexpr auto Parse(xmlpp::Element* element) {
return TryParse(element).value();
}
friend constexpr auto operator<<(xmlpp::Element* element, const UnknownXmppError& obj) -> void {
throw std::format("'{}' must never be written into the real stream!", kErrorMessage);
}
[[nodiscard]] constexpr auto what() const noexcept -> const char* override {
return kErrorMessage.data();
}
};
struct BadFormat : ErrorImpl<BadFormat> {};
struct BadNamespacePrefix : ErrorImpl<BadNamespacePrefix> {};
struct Conflict : ErrorImpl<Conflict> {};
struct ConnectionTimeout : ErrorImpl<ConnectionTimeout> {};
struct HostGone : ErrorImpl<HostGone> {};
struct HostUnknown : ErrorImpl<HostUnknown> {};
struct ImproperAdressing : ErrorImpl<ImproperAdressing> {};
struct InternalServerError : ErrorImpl<InternalServerError> {};
struct InvalidFrom : ErrorImpl<InvalidFrom> {};
struct InvalidNamespace : ErrorImpl<InvalidNamespace> {};
struct InvalidXml : ErrorImpl<InvalidXml> {};
struct NotAuthorized : ErrorImpl<NotAuthorized> {};
struct NotWellFormed : ErrorImpl<NotWellFormed> {};
struct PolicyViolation : ErrorImpl<PolicyViolation> {};
struct RemoteConnectionFailed : ErrorImpl<RemoteConnectionFailed> {};
struct Reset : ErrorImpl<Reset> {};
struct ResourceConstraint : ErrorImpl<ResourceConstraint> {};
struct RestrictedXml : ErrorImpl<RestrictedXml> {};
struct SeeOtherHost : ErrorImpl<SeeOtherHost> {};
struct SystemShutdown : ErrorImpl<SystemShutdown> {};
struct UndefinedCondition : ErrorImpl<UndefinedCondition> {};
struct UnsupportedEncoding : ErrorImpl<UnsupportedEncoding> {};
struct UnsupportedFeature : ErrorImpl<UnsupportedFeature> {};
struct UnsupportedStanzaType : ErrorImpl<UnsupportedStanzaType> {};
struct UnsupportedVersion : ErrorImpl<UnsupportedVersion> {};
} // namespace error::stream
using StreamError = std::variant<error::stream::BadFormat,
error::stream::BadNamespacePrefix,
error::stream::Conflict,
error::stream::ConnectionTimeout,
error::stream::HostGone,
error::stream::HostUnknown,
error::stream::ImproperAdressing,
error::stream::InternalServerError,
error::stream::InvalidFrom,
error::stream::InvalidNamespace,
error::stream::InvalidXml,
error::stream::NotAuthorized,
error::stream::NotWellFormed,
error::stream::PolicyViolation,
error::stream::RemoteConnectionFailed,
error::stream::RestrictedXml,
error::stream::SeeOtherHost,
error::stream::SystemShutdown,
error::stream::UndefinedCondition,
error::stream::UnsupportedEncoding,
error::stream::UnsupportedFeature,
error::stream::UnsupportedStanzaType,
error::stream::UnsupportedVersion,
error::stream::UnknownXmppError>;
static_assert(!std::is_same_v<typename std::variant_alternative_t<std::variant_size_v<StreamError> - 1, StreamError>, StreamError>,
"'UnknownXmppError' must be at the end of 'StreamError' variant");
} // namespace larra::xmpp