initial
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <span>
|
||||
|
||||
#include "Address.hpp"
|
||||
#include "Messenger.hpp"
|
||||
#include "NetworkError.hpp"
|
||||
#include "TcpStream.hpp"
|
||||
#include "packets/Packet.hpp"
|
||||
#include "packets/LoginPacket.hpp"
|
||||
#include "protocol/quicr/QuicrConnection.hpp"
|
||||
|
||||
namespace tw::net {
|
||||
|
||||
/**
|
||||
* Contains handlers for each message type. Calls this handler when message comes in.
|
||||
*/
|
||||
class MessageHandler {
|
||||
private:
|
||||
// std::optional<Messenger<std::byte, quicr::QuicrConnection>> m_quicr_messenger;
|
||||
// Messenger<std::byte, TcpStream> m_server_messenger;
|
||||
std::unique_ptr<quicr::QuicrEndpoint> m_quicr_endpoint;
|
||||
quicr::QuicrConnection* m_quicr_connection;
|
||||
|
||||
std::vector<std::function<tl::expected<void, NetworkError>(std::span<std::byte>)>> m_handlers;
|
||||
|
||||
std::unique_ptr<quicr::QuicrEndpoint> create_endpoint() {
|
||||
auto endpoint_r = quicr::QuicrEndpoint::create();
|
||||
if(!endpoint_r) {
|
||||
spdlog::error("Failed to create QuicrEndpoint: {}", endpoint_r.error().message());
|
||||
throw std::runtime_error("Failed to create QuicrEndpoint");
|
||||
}
|
||||
|
||||
return std::make_unique<quicr::QuicrEndpoint>(std::move(endpoint_r.value()));
|
||||
}
|
||||
|
||||
public:
|
||||
const bool is_connected() const {
|
||||
return m_quicr_connection->state() == quicr::QuicrConnectionState::Established;
|
||||
}
|
||||
|
||||
MessageHandler(MessageHandler&& m)
|
||||
// : m_server_messenger{std::move(m.m_server_messenger)},
|
||||
:
|
||||
m_handlers(std::move(m.m_handlers)),
|
||||
m_quicr_endpoint(std::move(m.m_quicr_endpoint)),
|
||||
m_quicr_connection(m.m_quicr_connection) {
|
||||
|
||||
}
|
||||
|
||||
MessageHandler(Address address) :
|
||||
m_quicr_endpoint(create_endpoint()),
|
||||
m_quicr_connection(m_quicr_endpoint->connect(address).value()),
|
||||
m_handlers(100) {
|
||||
spdlog::info("Connected to server at {}", address.to_string());
|
||||
}
|
||||
|
||||
|
||||
// MessageHandler(Messenger<std::byte, TcpStream>&& server_messenger) :
|
||||
// // m_server_messenger{std::move(server_messenger)},
|
||||
// m_quicr_connection(std::move(server_messenger.connection())),
|
||||
// m_handlers(100) {
|
||||
|
||||
// }
|
||||
|
||||
template<typename T>
|
||||
constexpr void set_handler(const std::function<void(T*)> handler) {
|
||||
PacketType type = Message<T>::value;
|
||||
m_handlers[type] = [handler, this](std::span<std::byte> data) -> tl::expected<void, NetworkError> {
|
||||
T result = {};
|
||||
|
||||
result.ParseFromArray(data.data(), data.size());
|
||||
// spdlog::info("Deserialized message [{}]: {}", (int32_t)Message<T>::value, result.DebugString());
|
||||
|
||||
handler(&result);
|
||||
// if(m_server_messenger.peek().has_value() && m_server_messenger.peek().value() == Message<T>::value) {
|
||||
// tl::expected<T, NetworkError> mesg = m_server_messenger.pop<T>(nullptr);
|
||||
// if(!mesg.has_value()) {
|
||||
// return tl::make_unexpected(mesg.error());
|
||||
// }
|
||||
|
||||
// handler(&mesg.value());
|
||||
// }
|
||||
|
||||
|
||||
return {};
|
||||
};
|
||||
}
|
||||
|
||||
constexpr void set_raw_handler(uint32_t type, const std::function<tl::expected<void, NetworkError>(std::span<std::byte>)> handler) {
|
||||
m_handlers[type] = handler;
|
||||
}
|
||||
|
||||
void update() {
|
||||
m_quicr_endpoint->poll();
|
||||
while(true) {
|
||||
std::vector<std::byte> buffer(64 * 1024);
|
||||
auto read_r = m_quicr_connection->read_into(buffer);
|
||||
|
||||
if(!read_r) {
|
||||
spdlog::error("Failed to read from QUICr stream: {}", read_r.error().message());
|
||||
break;
|
||||
}
|
||||
|
||||
if(*read_r == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t type = reinterpret_cast<uint32_t*>(buffer.data())[0];
|
||||
if(m_handlers[type] == nullptr) {
|
||||
spdlog::warn("Unknown message type: {}", type);
|
||||
throw std::runtime_error("Unknown message type: {}");
|
||||
break;
|
||||
}
|
||||
|
||||
auto handler_r = m_handlers[type](std::span<std::byte>(buffer.data(), *read_r).subspan(sizeof(uint32_t)));
|
||||
if(!handler_r) {
|
||||
spdlog::error("Handler error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// while(m_server_messenger.peek().has_value() && m_server_messenger.peek().value().has_value()) {
|
||||
// std::optional<PacketType> type = m_server_messenger.peek().value();
|
||||
// if(type >= m_handlers.size() || m_handlers[type.value()] == nullptr) {
|
||||
// spdlog::warn("Unknown message type: {}", (int)type.value());
|
||||
// break;
|
||||
// }
|
||||
|
||||
// auto r = m_handlers[type.value()]();
|
||||
// if(!r) {
|
||||
// spdlog::error("Failed to handle message: {}", r.error().message());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
template<std::derived_from<google::protobuf::Message> T>
|
||||
tl::expected<size_t, NetworkError> send(T& mesg) {
|
||||
std::string payload;
|
||||
if(!mesg.SerializeToString(&payload)) {
|
||||
spdlog::error("Failed to serialize message");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t length = payload.length();
|
||||
if(length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::byte> bytes(length + sizeof(uint32_t));
|
||||
|
||||
uint32_t type = Message<T>::value;
|
||||
auto payload_bytes = std::as_writable_bytes(std::span(payload));
|
||||
memcpy(bytes.data(), &type, sizeof(type));
|
||||
memcpy(bytes.data() + sizeof(uint32_t), payload_bytes.data(), payload_bytes.size());
|
||||
|
||||
auto send_r = m_quicr_connection->send_message(bytes, false);
|
||||
if(!send_r) {
|
||||
spdlog::error("Failed to send message: {}", send_r.error().message());
|
||||
return 0;
|
||||
}
|
||||
return payload_bytes.size();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
#pragma once
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#include "NetworkError.hpp"
|
||||
#include "packets/Packet.hpp"
|
||||
#include "MessageRegistry.hpp"
|
||||
#include "protocol/quicr/QuicrFrameType.hpp"
|
||||
#include "tl/expected.hpp"
|
||||
|
||||
namespace tw::net {
|
||||
|
||||
template<typename TData, std::derived_from<Write<TData>> TOutput>
|
||||
class Messenger {
|
||||
private:
|
||||
const uint32_t MAX_MESG_BODY_SIZE = 65536;
|
||||
const uint32_t MESG_MAGIC = 0x1DEADBEE;
|
||||
|
||||
TOutput m_stream;
|
||||
|
||||
std::optional<PacketType> m_next_packet_type;
|
||||
|
||||
bool m_is_skipping;
|
||||
uint32_t m_buffered_size;
|
||||
|
||||
size_t m_mesg_size;
|
||||
size_t m_read_head;
|
||||
std::vector<std::byte> m_input_buffer;
|
||||
|
||||
public:
|
||||
Messenger(Messenger && m) :
|
||||
m_stream(std::move(m.m_stream)),
|
||||
m_next_packet_type(m.m_next_packet_type),
|
||||
m_input_buffer(std::move(m.m_input_buffer)),
|
||||
m_buffered_size(m.m_buffered_size),
|
||||
m_is_skipping(m.m_is_skipping),
|
||||
m_mesg_size(m.m_mesg_size),
|
||||
m_read_head(m.m_read_head)
|
||||
{
|
||||
// m_stream.set_non_blocking();
|
||||
}
|
||||
|
||||
Messenger(TOutput&& stream) :
|
||||
m_stream(std::move(stream)),
|
||||
m_input_buffer(MAX_MESG_BODY_SIZE),
|
||||
m_buffered_size(0),
|
||||
m_is_skipping(false),
|
||||
m_mesg_size(0),
|
||||
m_read_head(0)
|
||||
{
|
||||
// m_stream.set_non_blocking();
|
||||
}
|
||||
|
||||
Messenger<TData, TOutput> operator=(const Messenger<TData, TOutput>&) = delete;
|
||||
|
||||
Messenger<TData, TOutput> operator=(Messenger<TData, TOutput>&& m) {
|
||||
m_stream = std::move(m.m_stream);
|
||||
m_next_packet_type = m.m_next_packet_type;
|
||||
m_input_buffer = std::move(m.m_input_buffer);
|
||||
m_buffered_size = m.m_buffered_size;
|
||||
m_is_skipping = m.m_is_skipping;
|
||||
m_mesg_size = m.m_mesg_size;
|
||||
m_read_head = m.m_read_head;
|
||||
}
|
||||
|
||||
template <std::derived_from<google::protobuf::Message> T>
|
||||
tl::expected<size_t, NetworkError> send(T &content) {
|
||||
ZoneScopedN("Messenger::send");
|
||||
auto id = (int32_t)Message<T>::value;
|
||||
|
||||
std::string payload;
|
||||
if(!content.SerializeToString(&payload)) {
|
||||
spdlog::error("Failed to serialize message");
|
||||
throw std::runtime_error("Serialization failed");
|
||||
}
|
||||
|
||||
// spdlog::info("Sending {}: {}", (int)Message<T>::value, content.DebugString());
|
||||
|
||||
int32_t length = payload.length();
|
||||
if(length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// append encoded id & length before payload and write it to the stream
|
||||
//
|
||||
const uint32_t HEADER_SIZE = 4 + 4 + 4 + 4;
|
||||
|
||||
std::string message;
|
||||
message.resize(HEADER_SIZE + payload.length());
|
||||
|
||||
const uint32_t magic = 0xDEADBEEF;
|
||||
const uint32_t frame_type = quicr::FrameType::StreamBase;
|
||||
|
||||
std::memcpy(message.data(), &magic, sizeof(magic));
|
||||
std::memcpy(message.data() + sizeof(magic), &frame_type, sizeof(frame_type));
|
||||
std::memcpy(message.data() + sizeof(frame_type) + sizeof(magic), &length, sizeof(length));
|
||||
std::memcpy(message.data() + sizeof(frame_type) + sizeof(magic) + sizeof(length), &id, sizeof(id));
|
||||
// std::memcpy(message.data() + sizeof(id) + sizeof(length), &MESG_MAGIC, sizeof(MESG_MAGIC));
|
||||
std::memcpy(message.data() + HEADER_SIZE, payload.data(), payload.length());
|
||||
|
||||
auto write_result = m_stream.write(std::as_writable_bytes(std::span(message)));
|
||||
if(!write_result.has_value()) {
|
||||
return tl::make_unexpected(write_result.error());
|
||||
}
|
||||
|
||||
return write_result.value();
|
||||
}
|
||||
|
||||
int32_t m_packet_peek_size = 0;
|
||||
|
||||
tl::expected<std::optional<PacketType>, NetworkError> peek() {
|
||||
ZoneScopedN("Messenger::peek");
|
||||
if(m_next_packet_type.has_value()) {
|
||||
return m_next_packet_type;
|
||||
}
|
||||
|
||||
if(m_read_head < 4) {
|
||||
auto result = m_stream.read_into(std::as_writable_bytes(std::span{(char*)m_input_buffer.data(), sizeof(PacketType) - m_read_head}));
|
||||
|
||||
if(!result.has_value()) {
|
||||
return tl::make_unexpected(result.error());
|
||||
}
|
||||
|
||||
m_read_head += result.value();
|
||||
|
||||
if(m_read_head < 4) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if(m_read_head < 8) {
|
||||
auto result = m_stream.read_into(std::as_writable_bytes(std::span{(char*)m_input_buffer.data() + m_read_head, 8 - m_read_head}));
|
||||
|
||||
if(!result.has_value()) {
|
||||
return tl::make_unexpected(result.error());
|
||||
}
|
||||
|
||||
m_read_head += result.value();
|
||||
|
||||
if(m_read_head < 8) {
|
||||
return {};
|
||||
}
|
||||
|
||||
m_mesg_size = *reinterpret_cast<uint32_t*>(m_input_buffer.data() + 4);
|
||||
}
|
||||
|
||||
if(m_read_head < m_mesg_size + 8) {
|
||||
if(m_mesg_size + 8 > m_input_buffer.size()) {
|
||||
return tl::make_unexpected(NetworkError(NetworkErrorType::NOT_ENOUGH_MEMORY));
|
||||
}
|
||||
|
||||
auto result = m_stream.read_into(std::as_writable_bytes(std::span{(char*)m_input_buffer.data() + m_read_head, m_mesg_size + 8 - m_read_head}));
|
||||
|
||||
if(!result.has_value()) {
|
||||
return tl::make_unexpected(result.error());
|
||||
}
|
||||
|
||||
m_read_head += result.value();
|
||||
|
||||
if(m_read_head < m_mesg_size + 8) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
m_next_packet_type = (PacketType)(*reinterpret_cast<int32_t*>(m_input_buffer.data()));
|
||||
return m_next_packet_type;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
tl::expected<T, NetworkError> pop(size_t* out_size) {
|
||||
ZoneScopedN("Messenger::pop");
|
||||
T result = {};
|
||||
|
||||
result.ParseFromArray(m_input_buffer.data() + 8, m_mesg_size);
|
||||
// spdlog::info("Received {}: {}", (int)m_next_packet_type.value(), result.DebugString());
|
||||
|
||||
m_read_head = 0;
|
||||
m_mesg_size = 0;
|
||||
m_next_packet_type = {};
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void skip() {
|
||||
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_next_packet_type = std::nullopt;
|
||||
|
||||
int message_length = 0;
|
||||
int size = sizeof(message_length);
|
||||
|
||||
// m_stream.read_exact(std::as_writable_bytes(std::span{&message_length, 1}));
|
||||
|
||||
std::vector<char> data(message_length);
|
||||
// m_stream.read_exact(std::as_writable_bytes(std::span{data.data(), (size_t)message_length}));
|
||||
|
||||
// m_input_buffer.reset();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "MessageRegistry.hpp"
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
class MessengerDebugLog {
|
||||
public:
|
||||
MessengerDebugLog(MessengerDebugLog&& m) :
|
||||
m_log_file(std::move(m.m_log_file))
|
||||
{ }
|
||||
|
||||
MessengerDebugLog(const std::string& log_file_path);
|
||||
~MessengerDebugLog();
|
||||
|
||||
template<typename T>
|
||||
void log_send(const T& message) {
|
||||
spdlog::info("Sending [{}]: {}", (int)tw::Message<T>::value, message.DebugString());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void log_recv(const T& message) {
|
||||
spdlog::info("Received [{}]: {}", (int)tw::Message<T>::value, message.DebugString());
|
||||
}
|
||||
|
||||
private:
|
||||
std::ofstream m_log_file;
|
||||
};
|
||||
Reference in New Issue
Block a user