Refactor NetworkMessage
This commit is contained in:
parent
392688ad2c
commit
9eaef8630f
|
@ -9,116 +9,10 @@
|
||||||
|
|
||||||
namespace Feather
|
namespace Feather
|
||||||
{
|
{
|
||||||
class NetworkMessageCounter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
inline void WriteVarInt(int32_t value)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
uint8_t temp = uint8_t(value & 0b01111111);
|
|
||||||
value >>= 7;
|
|
||||||
if (value != 0)
|
|
||||||
temp |= 0b10000000;
|
|
||||||
|
|
||||||
m_size++;
|
|
||||||
} while (value != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void WriteString(const char* string, int32_t length)
|
|
||||||
{
|
|
||||||
int32_t stringSize = length + 1;
|
|
||||||
WriteVarInt(stringSize);
|
|
||||||
|
|
||||||
m_size += stringSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void WriteLong(int64_t value)
|
|
||||||
{
|
|
||||||
m_size += sizeof(int64_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int32_t GetSize() const { return m_size; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int32_t m_size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NetworkMessage
|
class NetworkMessage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
NetworkMessage(int32_t expectedSize)
|
||||||
NetworkMessage(int32_t size)
|
|
||||||
{
|
|
||||||
NetworkMessageCounter packetSizeCounter;
|
|
||||||
packetSizeCounter.WriteVarInt(size);
|
|
||||||
|
|
||||||
size_t initialSize = size_t(size) + size_t(packetSizeCounter.GetSize());
|
|
||||||
|
|
||||||
m_data.reserve(initialSize);
|
|
||||||
WriteVarInt(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void WriteVarInt(int32_t value)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
uint8_t temp = uint8_t(value & 0b01111111);
|
|
||||||
value >>= 7;
|
|
||||||
if (value != 0)
|
|
||||||
temp |= 0b10000000;
|
|
||||||
|
|
||||||
m_data.push_back(temp);
|
|
||||||
} while (value != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void WriteString(const char* string, int32_t length)
|
|
||||||
{
|
|
||||||
int32_t stringSize = length + 1;
|
|
||||||
WriteVarInt(stringSize);
|
|
||||||
|
|
||||||
size_t oldSize = m_data.size();
|
|
||||||
size_t newSize = oldSize + size_t(stringSize);
|
|
||||||
m_data.resize(newSize);
|
|
||||||
std::memcpy(&m_data[oldSize], string, size_t(stringSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void WriteLong(int64_t value)
|
|
||||||
{
|
|
||||||
size_t oldSize = m_data.size();
|
|
||||||
m_data.resize(oldSize + sizeof(int64_t));
|
|
||||||
// TODO: do this with registers if faster (see libcore.io.Memory.pokeLong)
|
|
||||||
std::memcpy(&m_data[oldSize], &value, sizeof(int64_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline virtual const uint8_t* GetData() const { return m_data.data(); }
|
|
||||||
inline virtual size_t GetDataSize() const { return m_data.size(); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Used by subclasses with their own constructors
|
|
||||||
NetworkMessage() {}
|
|
||||||
|
|
||||||
std::vector<uint8_t> m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DEFINE_MESSAGE_WRAPPER(x) \
|
|
||||||
template <typename... Args> \
|
|
||||||
NetworkMessage x(Args... args) \
|
|
||||||
{ \
|
|
||||||
NetworkMessageCounter counter; \
|
|
||||||
x(counter, args...); \
|
|
||||||
NetworkMessage message(counter.GetSize()); \
|
|
||||||
x(message, args...); \
|
|
||||||
return message; \
|
|
||||||
}
|
|
||||||
|
|
||||||
// This class provides an alternative to NetworkMessageCounter, instead performing
|
|
||||||
// one count and prepending the size marker to the start of the buffer.
|
|
||||||
//
|
|
||||||
// To do this, you must call Finalize() before GetDataSize() or GetData()
|
|
||||||
class DynamicNetworkMessage : public NetworkMessage
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DynamicNetworkMessage(int32_t expectedSize) : NetworkMessage()
|
|
||||||
{
|
{
|
||||||
size_t initialSize = VARINT_MAX_SIZE + expectedSize;
|
size_t initialSize = VARINT_MAX_SIZE + expectedSize;
|
||||||
|
|
||||||
|
@ -126,39 +20,84 @@ namespace Feather
|
||||||
m_data.resize(VARINT_MAX_SIZE);
|
m_data.resize(VARINT_MAX_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize()
|
template <typename T>
|
||||||
|
inline void WriteData(const T* data, size_t size)
|
||||||
|
{
|
||||||
|
size_t offset = m_data.size();
|
||||||
|
|
||||||
|
m_data.resize(offset + size);
|
||||||
|
std::memcpy(&m_data[offset], data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void Write(const T& value)
|
||||||
|
{
|
||||||
|
// Todo: Endian-ness
|
||||||
|
WriteData(&value, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WriteVarInt(int32_t value)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
uint8_t temp = uint8_t(value & 0b01111111);
|
||||||
|
value >>= 7;
|
||||||
|
if (value != 0)
|
||||||
|
temp |= 0b10000000;
|
||||||
|
|
||||||
|
Write(temp);
|
||||||
|
} while (value != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WriteString(const char* string, int32_t length)
|
||||||
|
{
|
||||||
|
int32_t stringSize = length + 1;
|
||||||
|
WriteVarInt(stringSize);
|
||||||
|
WriteData(string, stringSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Finalize()
|
||||||
{
|
{
|
||||||
PrependVarIntSize();
|
PrependVarIntSize();
|
||||||
|
#ifdef _DEBUG
|
||||||
m_finalized = true;
|
m_finalized = true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlining and 'final' should ideally avert vtable lookups
|
// Inlining and 'final' should ideally avert vtable lookups
|
||||||
// TOOD: Make these separate functions if vtable is not averted
|
// TOOD: Make these separate functions if vtable is not averted
|
||||||
|
|
||||||
inline virtual const uint8_t* GetData() const final
|
inline const uint8_t* GetData() const
|
||||||
{
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
// You must call Finalize() first
|
// You must call Finalize() first
|
||||||
assert(m_finalized);
|
assert(m_finalized);
|
||||||
return m_data.data() + m_startOffset;
|
#endif
|
||||||
|
return &m_data[m_startOffset];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline virtual size_t GetDataSize() const final
|
inline size_t GetDataSize() const
|
||||||
{
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
// You must call Finalize() first
|
// You must call Finalize() first
|
||||||
assert(m_finalized);
|
assert(m_finalized);
|
||||||
|
#endif
|
||||||
return m_data.size() - m_startOffset;
|
return m_data.size() - m_startOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_startOffset = 0;
|
std::vector<uint8_t> m_data;
|
||||||
|
size_t m_startOffset = 0;
|
||||||
|
#ifdef _DEBUG
|
||||||
bool m_finalized = false;
|
bool m_finalized = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
void PrependVarIntSize()
|
void PrependVarIntSize()
|
||||||
{
|
{
|
||||||
uint8_t sizeBytes[VARINT_MAX_SIZE];
|
uint8_t sizeBytes[VARINT_MAX_SIZE];
|
||||||
|
|
||||||
// compute the size of the packet excluding the size marker
|
// compute the size of the packet excluding the size marker
|
||||||
int value = int(m_data.size() - VARINT_MAX_SIZE);
|
int32_t value = static_cast<int32_t>(m_data.size() - VARINT_MAX_SIZE);
|
||||||
int index = 0;
|
size_t index = 0;
|
||||||
|
|
||||||
// perform WriteVarInt into the static buffer sizeBytes
|
// perform WriteVarInt into the static buffer sizeBytes
|
||||||
do {
|
do {
|
||||||
|
@ -173,13 +112,11 @@ namespace Feather
|
||||||
// where to start writing the size marker
|
// where to start writing the size marker
|
||||||
// if we used all 5 bytes, this is zero
|
// if we used all 5 bytes, this is zero
|
||||||
// if we used 3 bytes, this would be 2
|
// if we used 3 bytes, this would be 2
|
||||||
int startIndex = VARINT_MAX_SIZE - index;
|
size_t startIndex = VARINT_MAX_SIZE - index;
|
||||||
|
|
||||||
// Copy sizeBytes into our actual buffer, but align it to the right
|
// Copy sizeBytes into our actual buffer, but align it to the right
|
||||||
for (int i = 0; i < index; i++)
|
for (size_t i = 0; i < index; i++)
|
||||||
{
|
|
||||||
m_data[startIndex + i] = sizeBytes[i];
|
m_data[startIndex + i] = sizeBytes[i];
|
||||||
}
|
|
||||||
|
|
||||||
m_startOffset = startIndex;
|
m_startOffset = startIndex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace Feather
|
||||||
{
|
{
|
||||||
printf("[Protocol] Client sent STATUS_PING_REQUEST\n");
|
printf("[Protocol] Client sent STATUS_PING_REQUEST\n");
|
||||||
|
|
||||||
DynamicNetworkMessage msg(VARINT_MAX_SIZE + json_template.length());
|
NetworkMessage msg(VARINT_MAX_SIZE + json_template.length());
|
||||||
// Packet ID
|
// Packet ID
|
||||||
msg.WriteVarInt(0);
|
msg.WriteVarInt(0);
|
||||||
// JSON Contents
|
// JSON Contents
|
||||||
|
@ -94,10 +94,10 @@ namespace Feather
|
||||||
int64_t timestamp = packet.Read<int64_t>();
|
int64_t timestamp = packet.Read<int64_t>();
|
||||||
printf("[Protocol] Client sent STATUS_PING: %lld\n", timestamp);
|
printf("[Protocol] Client sent STATUS_PING: %lld\n", timestamp);
|
||||||
|
|
||||||
DynamicNetworkMessage msg(VARINT_MAX_SIZE + sizeof(int64_t));
|
NetworkMessage msg(VARINT_MAX_SIZE + sizeof(int64_t));
|
||||||
|
|
||||||
msg.WriteVarInt(1);
|
msg.WriteVarInt(1);
|
||||||
msg.WriteLong(timestamp);
|
msg.Write<uint64_t>(timestamp);
|
||||||
msg.Finalize();
|
msg.Finalize();
|
||||||
|
|
||||||
client.SendMessage(msg);
|
client.SendMessage(msg);
|
||||||
|
|
Loading…
Reference in New Issue