Add streams

This commit is contained in:
sha512sum 2024-08-30 13:01:35 +00:00
parent 030f69c66d
commit 84abbe8178
3 changed files with 149 additions and 20 deletions

View file

@ -1,50 +1,61 @@
module;
c export module larra.library.stream;
export import larra.library.jid;
import larra.library.utils;
import std;
#pragma once
#include <larra/jid.hpp>
#include <pugixml.hpp>
namespace larra::xmpp {
export struct Stream {
std::optional<BareJid> from;
std::optional<BareJid> to;
namespace impl {
template <bool JidFrom, bool JidTo>
struct BasicStream {
static constexpr bool kJidFrom = JidFrom;
static constexpr bool kJidTo = JidTo;
using FromType = std::optional<std::conditional_t<JidFrom, BareJid, std::string>>;
using ToType = std::optional<std::conditional_t<JidTo, BareJid, std::string>>;
FromType from;
ToType to;
std::optional<std::string> id;
std::optional<std::string> version;
std::optional<std::string> xmlLang;
template <typename Self>
constexpr auto From(this Self&& self, BareJid value) {
constexpr auto From(this Self&& self, FromType value) {
return utils::FieldSetHelper::With<"from">(std::forward<Self>(self), std::move(value));
};
template <typename Self>
constexpr auto To(this Self&& self, BareJid value) {
constexpr auto To(this Self&& self, ToType value) {
return utils::FieldSetHelper::With<"to">(std::forward<Self>(self), std::move(value));
};
template <typename Self>
constexpr auto Id(this Self&& self, std::string value) {
constexpr auto Id(this Self&& self, std::optional<std::string> value) {
return utils::FieldSetHelper::With<"id">(std::forward<Self>(self), std::move(value));
};
template <typename Self>
constexpr auto Version(this Self&& self, std::string value) {
constexpr auto Version(this Self&& self, std::optional<std::string> value) {
return utils::FieldSetHelper::With<"version">(std::forward<Self>(self), std::move(value));
};
template <typename Self>
constexpr auto XmlLang(this Self&& self, std::string value) {
return utils::FieldSetHelper::With<"xmlLang">(std::forward<Self>(self), std::move(value));
constexpr auto XmlLang(this Self&& self, std::optional<std::string> value) {
return utils::FieldSetHelper::With<"xmlLang">(std::forward_like<Self>(self), std::move(value));
};
constexpr Stream(BareJid to) : to(std::move(to)), version("1.0") {};
friend auto operator<<(pugi::xml_node& node, const Stream& stream) {
if(stream.from) {
auto str = ToString(*stream.from);
node.append_attribute("from") = str.c_str();
};
auto SerializeStream(pugi::xml_node& node) const -> void;
friend auto operator<<(pugi::xml_node& node, const BasicStream<JidFrom, JidTo>& stream) -> pugi::xml_node& {
return (stream.SerializeStream(node), node);
};
static auto Parse(const pugi::xml_node& node) -> BasicStream<JidFrom, JidTo>;
};
} // namespace impl
using UserStream = impl::BasicStream<true, false>;
using UserToUserStream = impl::BasicStream<true, true>;
using ServerStream = impl::BasicStream<false, false>;
using ServerToUserStream = impl::BasicStream<false, true>;
} // namespace larra::xmpp

64
library/src/stream.cpp Normal file
View file

@ -0,0 +1,64 @@
#include <larra/stream.hpp>
namespace {
inline auto ToOptionalString(const pugi::xml_attribute& attribute) -> std::optional<std::string> {
return attribute ? std::optional{std::string{attribute.as_string()}} : std::nullopt;
}
template <bool IsJid>
inline auto ToOptionalUser(const pugi::xml_attribute& attribute) {
if constexpr(IsJid) {
return attribute ? std::optional{larra::xmpp::BareJid::Parse(attribute.as_string())} : std::nullopt;
} else {
return attribute ? std::optional{std::string{attribute.as_string()}} : std::nullopt;
}
}
auto ToString(std::string data) -> std::string {
return std::move(data);
};
} // namespace
namespace larra::xmpp {
template <bool JidFrom, bool JidTo>
auto impl::BasicStream<JidFrom, JidTo>::SerializeStream(pugi::xml_node& node) const -> void {
if(this->from) {
node.append_attribute("from") = ToString(*this->from).c_str();
}
if(this->to) {
node.append_attribute("to") = ToString(*this->to).c_str();
}
if(this->id) {
node.append_attribute("id") = this->id->c_str();
}
if(this->version) {
node.append_attribute("version") = this->version->c_str();
}
if(this->xmlLang) {
node.append_attribute("xml:lang") = this->xmlLang->c_str();
}
}
template auto ServerStream::SerializeStream(pugi::xml_node& node) const -> void;
template auto ServerToUserStream::SerializeStream(pugi::xml_node& node) const -> void;
template auto UserToUserStream::SerializeStream(pugi::xml_node& node) const -> void;
template auto UserStream::SerializeStream(pugi::xml_node& node) const -> void;
template <bool JidFrom, bool JidTo>
auto impl::BasicStream<JidFrom, JidTo>::Parse(const pugi::xml_node& node) -> impl::BasicStream<JidFrom, JidTo> {
return {ToOptionalUser<JidFrom>(node.attribute("from")),
ToOptionalUser<JidTo>(node.attribute("to")),
ToOptionalString(node.attribute("id")),
ToOptionalString(node.attribute("version")),
ToOptionalString(node.attribute("xml:lang"))};
}
template auto UserStream::Parse(const pugi::xml_node& node) -> UserStream;
template auto UserToUserStream::Parse(const pugi::xml_node& node) -> UserToUserStream;
template auto ServerStream::Parse(const pugi::xml_node& node) -> ServerStream;
template auto ServerToUserStream::Parse(const pugi::xml_node& node) -> ServerToUserStream;
} // namespace larra::xmpp

54
tests/stream.cpp Normal file
View file

@ -0,0 +1,54 @@
#include <gtest/gtest.h>
#include <larra/stream.hpp>
namespace larra::xmpp {
constexpr std::string_view kSerializedData =
R"(<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' xml:lang='en' version='1.0' id='abc' from='user@example.com' />
)";
constexpr std::string_view kCheckSerializeData =
R"(<stream:stream from="user@example.com" to="anotheruser@example.com" id="abc" version="1.0" xml:lang="en" />
)";
TEST(Stream, Serialize) {
UserToUserStream originalStream;
originalStream.from = BareJid{"user", "example.com"};
originalStream.to = BareJid{"anotheruser", "example.com"};
originalStream.id = "abc";
originalStream.version = "1.0";
originalStream.xmlLang = "en";
pugi::xml_document doc;
pugi::xml_node streamNode = doc.append_child("stream:stream");
streamNode << originalStream;
std::ostringstream oss;
doc.child("stream:stream").print(oss, "\t");
const std::string serializedData = oss.str();
ASSERT_EQ(serializedData, kCheckSerializeData);
}
TEST(Stream, Deserialize) {
pugi::xml_document parsedDoc;
parsedDoc.load_string(kSerializedData.data());
const UserStream deserializedStream = UserStream::Parse(parsedDoc.child("stream:stream"));
ASSERT_TRUE(deserializedStream.from.has_value());
ASSERT_EQ(ToString(*deserializedStream.from), "user@example.com");
ASSERT_FALSE(deserializedStream.to.has_value());
ASSERT_TRUE(deserializedStream.id.has_value());
ASSERT_EQ(deserializedStream.id.value(), "abc");
ASSERT_TRUE(deserializedStream.version.has_value());
ASSERT_EQ(deserializedStream.version.value(), "1.0");
ASSERT_TRUE(deserializedStream.xmlLang.has_value());
ASSERT_EQ(deserializedStream.xmlLang.value(), "en");
}
} // namespace larra::xmpp