This commit is contained in:
2025-08-22 17:49:49 +06:00
parent d02f747ca0
commit c624c1ad0b
4 changed files with 400 additions and 381 deletions

View File

@@ -7,13 +7,12 @@
#include "Async.hpp"
#include "TOSLib.hpp"
#include <atomic>
#include <boost/asio.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/write.hpp>
#include <boost/thread.hpp>
#include <boost/circular_buffer.hpp>
#include <condition_variable>
#include <type_traits>
namespace LV::Net {
@@ -40,10 +39,10 @@ protected:
};
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template <typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T>, int> = 0>
static inline T swapEndian(const T &u) { return u; }
#else
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template <typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T>, int> = 0>
static inline T swapEndian(const T &u) {
if constexpr (sizeof(T) == 1) {
return u;
@@ -65,7 +64,7 @@ protected:
using NetPool = BoostPool<12, 14>;
class Packet {
static constexpr size_t MAX_PACKET_SIZE = 1 << 16;
static constexpr size_t MAX_PACKET_SIZE = 1 << 24;
uint16_t Size = 0;
std::vector<NetPool::PagePtr> Pages;
@@ -109,7 +108,7 @@ protected:
return *this;
}
template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template<typename T, std::enable_if_t<std::is_integral_v<T> || std::is_floating_point_v<T>, int> = 0>
inline Packet& write(T u) {
u = swapEndian(u);
write((const std::byte*) &u, sizeof(u));
@@ -130,7 +129,7 @@ protected:
inline uint16_t size() const { return Size; }
inline const std::vector<NetPool::PagePtr>& getPages() const { return Pages; }
template<typename T, std::enable_if_t<std::is_integral_v<T> or std::is_convertible_v<T, std::string_view>, int> = 0>
template<typename T, std::enable_if_t<std::is_floating_point_v<T> || std::is_integral_v<T> or std::is_convertible_v<T, std::string_view>, int> = 0>
inline Packet& operator<<(const T &value) {
if constexpr (std::is_convertible_v<T, std::string_view>)
return write((std::string_view) value);
@@ -147,7 +146,7 @@ protected:
Size = 0;
}
Packet& complite(std::vector<std::byte> &out) {
Packet& complite(std::u8string &out) {
out.resize(Size);
for(size_t pos = 0; pos < Size; pos += NetPool::PageSize) {
@@ -158,8 +157,8 @@ protected:
return *this;
}
std::vector<std::byte> complite() {
std::vector<std::byte> out;
std::u8string complite() {
std::u8string out;
complite(out);
return out;
}
@@ -175,6 +174,61 @@ protected:
}
};
class LinearReader {
public:
LinearReader(const std::u8string& input, size_t pos = 0)
: Pos(pos), Input(input)
{}
LinearReader(const LinearReader&) = delete;
LinearReader(LinearReader&&) = delete;
LinearReader& operator=(const LinearReader&) = delete;
LinearReader& operator=(LinearReader&&) = delete;
void read(std::byte *data, uint32_t size) {
if(Input.size()-Pos < size)
MAKE_ERROR("Недостаточно данных");
std::copy((const std::byte*) Input.data()+Pos, (const std::byte*) Input.data()+Pos+size, data);
Pos += size;
}
template<typename T, std::enable_if_t<std::is_floating_point_v<T> || std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
T read() {
if constexpr(std::is_floating_point_v<T> || std::is_integral_v<T>) {
T value;
read((std::byte*) &value, sizeof(value));
return swapEndian(value);
} else {
uint16_t size = read<uint16_t>();
T value(size, ' ');
read((std::byte*) value.data(), size);
return value;
}
}
template<typename T>
LinearReader& read(T& val) {
val = read<T>();
return *this;
}
template<typename T>
LinearReader& operator>>(T& val) {
val = read<T>();
return *this;
}
void checkUnreaded() {
if(Pos != Input.size())
MAKE_ERROR("Остались не использованные данные");
}
private:
size_t Pos = 0;
const std::u8string& Input;
};
class SmartPacket : public Packet {
public:
std::function<bool()> IsStillRelevant;
@@ -221,7 +275,7 @@ protected:
boost::asio::socket_base::linger optionLinger(true, 4); // После закрытия сокета оставшиеся данные будут доставлены
Socket.set_option(optionLinger);
boost::asio::ip::tcp::no_delay optionNoDelay(true); // Отключает попытки объёденить данные в крупные пакеты
boost::asio::ip::tcp::no_delay optionNoDelay(true); // Отключает попытки объединить данные в крупные пакеты
Socket.set_option(optionNoDelay);
co_spawn(runSender(SendPackets.Context));
@@ -243,9 +297,9 @@ protected:
coro<> read(std::byte *data, uint32_t size);
void closeRead();
template<typename T, std::enable_if_t<std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
template<typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
coro<T> read() {
if constexpr(std::is_integral_v<T>) {
if constexpr(std::is_floating_point_v<T> or std::is_integral_v<T>) {
T value;
co_await read((std::byte*) &value, sizeof(value));
co_return swapEndian(value);
@@ -263,9 +317,9 @@ protected:
co_await asio::async_read(socket, asio::mutable_buffer(data, size));
}
template<typename T, std::enable_if_t<std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
template<typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
static inline coro<T> read(tcp::socket &socket) {
if constexpr(std::is_integral_v<T>) {
if constexpr(std::is_floating_point_v<T> or std::is_integral_v<T>) {
T value;
co_await read(socket, (std::byte*) &value, sizeof(value));
co_return swapEndian(value);
@@ -280,7 +334,7 @@ protected:
co_await asio::async_write(socket, asio::const_buffer(data, size));
}
template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template<typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T>, int> = 0>
static inline coro<> write(tcp::socket &socket, T u) {
u = swapEndian(u);
co_await write(socket, (const std::byte*) &u, sizeof(u));