diff --git a/src/Metrics/CMakeLists.txt b/src/Metrics/CMakeLists.txt index 728430c..9da7e84 100644 --- a/src/Metrics/CMakeLists.txt +++ b/src/Metrics/CMakeLists.txt @@ -7,6 +7,11 @@ add_library(Metrics add_library(Metrics::All ALIAS Metrics) +target_link_libraries(Metrics + PRIVATE + Network::Common +) + target_include_directories(Metrics PUBLIC ${INCLUDE_BASE_DIR} diff --git a/src/Metrics/Host.cpp b/src/Metrics/Host.cpp index 9b6f5bd..b87f11d 100644 --- a/src/Metrics/Host.cpp +++ b/src/Metrics/Host.cpp @@ -4,6 +4,8 @@ #include #include +#include "Network/Common/Buffer.h" + namespace Metrics { @@ -27,126 +29,69 @@ namespace Metrics // ---- Сериализация ---- std::vector Host::serialize() const { - std::vector buffer; - buffer.push_back(1); // версия протокола + Network::Buffer buf; - // Host - buffer.push_back(static_cast(hostname.size())); - buffer.insert(buffer.end(), hostname.begin(), hostname.end()); + buf.writeUint8(1); // version + buf.writeString(hostname); // CPU - uint32_t totalLoadNet = floatToNetwork(cpu.totalLoad); - buffer.insert(buffer.end(), - reinterpret_cast(&totalLoadNet), - reinterpret_cast(&totalLoadNet) + sizeof(totalLoadNet)); - buffer.push_back(static_cast(cpu.coreLoads.size())); + buf.writeFloat(cpu.totalLoad); + buf.writeUint8(static_cast(cpu.coreLoads.size())); for (float f : cpu.coreLoads) - { - uint32_t net = floatToNetwork(f); - buffer.insert(buffer.end(), - reinterpret_cast(&net), - reinterpret_cast(&net) + 4); - } + buf.writeFloat(f); // Memory - uint32_t usedNet = floatToNetwork(memory.used); - uint32_t totalNet = floatToNetwork(memory.total); - buffer.insert(buffer.end(), - reinterpret_cast(&usedNet), - reinterpret_cast(&usedNet) + sizeof(usedNet)); - buffer.insert(buffer.end(), - reinterpret_cast(&totalNet), - reinterpret_cast(&totalNet) + sizeof(totalNet)); + buf.writeFloat(memory.used); + buf.writeFloat(memory.total); // Disks - buffer.push_back(static_cast(disks.size())); + buf.writeUint8(static_cast(disks.size())); for (const auto &d : disks) { - buffer.push_back(static_cast(d.name.size())); - buffer.insert(buffer.end(), d.name.begin(), d.name.end()); - - uint32_t used = floatToNetwork(d.used); - uint32_t total = floatToNetwork(d.total); - buffer.insert(buffer.end(), - reinterpret_cast(&used), - reinterpret_cast(&used) + 4); - buffer.insert(buffer.end(), - reinterpret_cast(&total), - reinterpret_cast(&total) + 4); + buf.writeString(d.name); + buf.writeFloat(d.used); + buf.writeFloat(d.total); } - return buffer; + return buf.data(); } // ---- Десериализация ---- - Host Host::deserialize(const std::vector &buffer) + Host Host::deserialize(const std::vector &data) { - Host m; - size_t pos = 0; - if (buffer.size() < 1) - throw std::runtime_error("Buffer too small"); - uint8_t version = buffer[pos++]; + Host h; + Network::Buffer buf(const_cast &>(data)); + + uint8_t version = buf.readUint8(); if (version != 1) throw std::runtime_error("Unsupported protocol version"); - // Host - uint8_t hostLen = buffer[pos++]; - if (pos + hostLen > buffer.size()) - throw std::runtime_error("Buffer too small for host"); - m.hostname = std::string(buffer.begin() + pos, buffer.begin() + pos + hostLen); - pos += hostLen; + h.hostname = buf.readString(); // CPU - uint32_t totolLoad; - std::memcpy(&totolLoad, &buffer[pos], 4); - pos += 4; - m.cpu.totalLoad = networkToFloat(totolLoad); - uint8_t numCpu = buffer[pos++]; - if (pos + numCpu * 4 > buffer.size()) - throw std::runtime_error("Buffer too small for CPU"); - - for (int i = 0; i < numCpu; ++i) - { - uint32_t tmp; - std::memcpy(&tmp, &buffer[pos], 4); - m.cpu.coreLoads.push_back(networkToFloat(tmp)); - pos += 4; - } + h.cpu.totalLoad = buf.readFloat(); + uint8_t numCpu = buf.readUint8(); + h.cpu.coreLoads.clear(); + h.cpu.coreLoads.reserve(numCpu); + for (uint8_t i = 0; i < numCpu; ++i) + h.cpu.coreLoads.push_back(buf.readFloat()); // Memory - if (pos + 8 > buffer.size()) - throw std::runtime_error("Buffer too small for memory"); - uint32_t memUsed, memTotal; - std::memcpy(&memUsed, &buffer[pos], 4); - pos += 4; - std::memcpy(&memTotal, &buffer[pos], 4); - pos += 4; - m.memory.used = networkToFloat(memUsed); - m.memory.total = networkToFloat(memTotal); + h.memory.used = buf.readFloat(); + h.memory.total = buf.readFloat(); // Disks - if (pos + 1 > buffer.size()) - throw std::runtime_error("Buffer too small for disks count"); - uint8_t numDisks = buffer[pos++]; - for (int i = 0; i < numDisks; ++i) + uint8_t numDisks = buf.readUint8(); + h.disks.clear(); + h.disks.reserve(numDisks); + for (uint8_t i = 0; i < numDisks; ++i) { - if (pos + 1 > buffer.size()) - throw std::runtime_error("Buffer too small for disk name length"); - uint8_t nameLen = buffer[pos++]; - if (pos + nameLen + 8 > buffer.size()) - throw std::runtime_error("Buffer too small for disk data"); - std::string diskName(buffer.begin() + pos, buffer.begin() + pos + nameLen); - pos += nameLen; - - uint32_t used, total; - std::memcpy(&used, &buffer[pos], 4); - pos += 4; - std::memcpy(&total, &buffer[pos], 4); - pos += 4; - - m.disks.push_back({diskName, networkToFloat(used), networkToFloat(total)}); + std::string name = buf.readString(); + float used = buf.readFloat(); + float total = buf.readFloat(); + h.disks.push_back({name, used, total}); } - return m; + return h; } } // namespace Metrics \ No newline at end of file diff --git a/src/Metrics/Host.h b/src/Metrics/Host.h index 8386671..b79a33c 100644 --- a/src/Metrics/Host.h +++ b/src/Metrics/Host.h @@ -22,6 +22,6 @@ namespace Metrics std::vector serialize() const; // Десериализация из вектора байт - static Host deserialize(const std::vector &buffer); + static Host deserialize(const std::vector &data); }; } // namespace Metrics diff --git a/src/Network/CMakeLists.txt b/src/Network/CMakeLists.txt index e45c0d5..7875451 100644 --- a/src/Network/CMakeLists.txt +++ b/src/Network/CMakeLists.txt @@ -1,5 +1,6 @@ message(STATUS "·Configuring Network") +add_subdirectory(Common) if (BUILD_SERVER) add_subdirectory(Server) endif() diff --git a/src/Network/Common/Buffer.cpp b/src/Network/Common/Buffer.cpp new file mode 100644 index 0000000..4d60fd1 --- /dev/null +++ b/src/Network/Common/Buffer.cpp @@ -0,0 +1,86 @@ +#include "Network/Common/Buffer.h" + +namespace Network +{ + void Buffer::writeUint8(uint8_t v) + { + buffer.push_back(v); + } + + void Buffer::writeUint32(uint32_t v) + { + uint32_t net = htonl(v); + auto p = reinterpret_cast(&net); + buffer.insert(buffer.end(), p, p + sizeof(net)); + } + + void Buffer::writeFloat(float f) + { + uint32_t tmp; + static_assert(sizeof(tmp) == sizeof(f), "Size mismatch"); + std::memcpy(&tmp, &f, sizeof(f)); + writeUint32(tmp); + } + + void Buffer::writeBytes(const uint8_t *data, size_t len) + { + buffer.insert(buffer.end(), data, data + len); + } + + void Buffer::writeString(const std::string &s) + { + if (s.size() > 255) + throw std::runtime_error("String too long"); + writeUint8(static_cast(s.size())); + writeBytes(reinterpret_cast(s.data()), s.size()); + } + + // --- Reading --- + uint8_t Buffer::readUint8() + { + checkRemaining(1); + return buffer[pos++]; + } + + uint32_t Buffer::readUint32() + { + checkRemaining(4); + uint32_t tmp; + std::memcpy(&tmp, &buffer[pos], 4); + pos += 4; + return ntohl(tmp); + } + + float Buffer::readFloat() + { + uint32_t tmp = readUint32(); + float f; + std::memcpy(&f, &tmp, sizeof(f)); + return f; + } + + std::string Buffer::readString() + { + uint8_t len = readUint8(); + checkRemaining(len); + std::string s(reinterpret_cast(&buffer[pos]), len); + pos += len; + return s; + } + + size_t Buffer::remaining() const + { + return buffer.size() - pos; + } + + std::vector &Buffer::data() + { + return buffer; + } + + void Buffer::checkRemaining(size_t n) + { + if (pos + n > buffer.size()) + throw std::runtime_error("Buffer underrun"); + } +} // namespace Network diff --git a/src/Network/Common/Buffer.h b/src/Network/Common/Buffer.h new file mode 100644 index 0000000..6a2fe50 --- /dev/null +++ b/src/Network/Common/Buffer.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace Network +{ + class Buffer + { + public: + explicit Buffer(std::vector &buf) : buffer(buf), pos(0) {} + explicit Buffer(size_t reserve = 0) : buffer(reserve), pos(0) {} + + // --- Writing --- + void writeUint8(uint8_t v); + void writeUint32(uint32_t v); + void writeFloat(float f); + void writeBytes(const uint8_t *data, size_t len); + void writeString(const std::string &s); + // --- Reading --- + uint8_t readUint8(); + uint32_t readUint32(); + float readFloat(); + std::string readString(); + + size_t remaining() const; + std::vector &data(); + + private: + void checkRemaining(size_t n); + + std::vector buffer; + size_t pos; + }; +} // namespace Network diff --git a/src/Network/Common/CMakeLists.txt b/src/Network/Common/CMakeLists.txt new file mode 100644 index 0000000..acf62a4 --- /dev/null +++ b/src/Network/Common/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(Network.Common + Buffer.cpp +) + +add_library(Network::Common ALIAS Network.Common) + +target_include_directories(Network.Common + PUBLIC + ${INCLUDE_BASE_DIR} +)