Created
August 12, 2023 05:43
-
-
Save JonathanCline/3bedb57f089d5c49c6df4fe563843dc8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace sw::net | |
{ | |
std::vector<std::byte> Message::serialize() const | |
{ | |
auto _out = std::vector<std::byte>(2); | |
// Write message type first | |
{ | |
auto _outIt = _out.begin(); | |
const auto _messageType = this->type(); | |
_outIt = write_bytes(_outIt, jc::to_underlying(_messageType)); | |
}; | |
// Write message DATA after the type indicator | |
const auto _bytesWritten = | |
std::visit([&_out](const auto& _message) -> size_t | |
{ | |
return _message.serialize(_out); | |
}, this->vt_); | |
return _out; | |
}; | |
template <typename MessageT> | |
inline std::optional<Message> deserialize_message_helper(std::span<const std::byte> _data) | |
{ | |
if (auto _messageData = Message_Ping::deserialize(_data); _messageData) | |
{ | |
return Message(std::move(*_messageData)); | |
} | |
else | |
{ | |
return std::nullopt; | |
}; | |
}; | |
std::optional<Message> Message::deserialize(std::span<const std::byte> _data) | |
{ | |
if (_data.size() < sizeof(MessageType)) | |
{ | |
return std::nullopt; | |
}; | |
auto _inIt = _data.begin(); | |
// Determine message type | |
auto _rawMessageType = std::underlying_type_t<MessageType>{}; | |
_inIt = read_bytes(_inIt, _rawMessageType); | |
// Where the raw message byte data is stored | |
const auto _messageDataBytes = std::span(_inIt, _data.end()); | |
// MESSAGE_TYPE_UPDATE_TAG | |
// Update the below switch with all possible enumerator values and their | |
// corresponding message data types. | |
switch (MessageType(_rawMessageType)) | |
{ | |
case MessageType::ping: | |
return deserialize_message_helper<Message_Ping>(_messageDataBytes); | |
default: | |
// Unrecognized message type. | |
return std::nullopt; | |
}; | |
}; | |
}; | |
namespace sw::net | |
{ | |
size_t Message_Ping::serialize(std::vector<std::byte>& _out) const | |
{ | |
const auto _oldSize = _out.size(); | |
_out.resize(_oldSize + sizeof(*this)); | |
auto _outIt = _out.begin() + _oldSize; | |
_outIt = write_bytes(_outIt, this->ping_time.time_since_epoch().count()); | |
_outIt = write_bytes(_outIt, this->pong_time.time_since_epoch().count()); | |
return _out.size() - _oldSize; | |
}; | |
std::optional<Message_Ping> Message_Ping::deserialize(std::span<const std::byte> _data) | |
{ | |
if (_data.size() < sizeof(Message_Ping)) | |
{ | |
return std::nullopt; | |
}; | |
Message_Ping _out{}; | |
auto _pingTimeSinceEpoch = Message_Ping::time_point::rep{}; | |
auto _pongTimeSinceEpoch = Message_Ping::time_point::rep{}; | |
auto _inIt = _data.begin(); | |
_inIt = read_bytes(_inIt, _pingTimeSinceEpoch); | |
_inIt = read_bytes(_inIt, _pongTimeSinceEpoch); | |
_out.ping_time = time_point{ time_point::duration{_pingTimeSinceEpoch} }; | |
_out.pong_time = time_point{ time_point::duration{_pongTimeSinceEpoch} }; | |
return _out; | |
}; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace sw::net | |
{ | |
/** | |
* @brief Enumerates the types of messages that can be transmitted. | |
* | |
* Find tag MESSAGE_TYPE_UPDATE_TAG and update whatever you find if you | |
* modify the below enumerator. | |
*/ | |
enum class MessageType : uint16_t | |
{ | |
/** | |
* @brief Performs a ping/pong action to gauge latency | |
*/ | |
ping = 0, | |
}; | |
/** | |
* @brief Message data structure for the "ping" message. | |
*/ | |
struct Message_Ping | |
{ | |
using time_point = std::chrono::utc_clock::time_point; | |
/** | |
* @brief Serializes just the message DATA into a byte array. | |
* @param _out Vector of bytes to write serialized data into. | |
* @return Number of bytes written to _out. | |
*/ | |
size_t serialize(std::vector<std::byte>& _out) const; | |
/** | |
* @brief Deserializes just the message DATA from some raw byte data. | |
* @param _data Raw byte data, ideally containing our message. | |
* @return Deserialized message DATA on success, nullopt otherwise. | |
*/ | |
static std::optional<Message_Ping> deserialize(std::span<const std::byte> _data); | |
/** | |
* @brief Time the ping was initiated at. | |
*/ | |
time_point ping_time; | |
/** | |
* @brief Time the pong was initiated at. | |
*/ | |
time_point pong_time; | |
}; | |
/** | |
* @brief Data structure for the actual message (data) carried by a datagram. | |
*/ | |
class Message | |
{ | |
private: | |
/** | |
* @brief | |
* MESSAGE_TYPE_UPDATE_TAG Add the corresponding message data type to the variant. | |
*/ | |
using vt = std::variant | |
< | |
Message_Ping | |
>; | |
public: | |
MessageType type() const noexcept | |
{ | |
return static_cast<MessageType>(this->vt_.index()); | |
}; | |
template <MessageType T> | |
auto& get() | |
{ | |
return std::get<static_cast<size_t>(T)>(this->vt_); | |
}; | |
template <MessageType T> | |
const auto& get() const | |
{ | |
return std::get<static_cast<size_t>(T)>(this->vt_); | |
}; | |
/** | |
* @brief Serializes the message into raw bytes. | |
* @return Raw byte array. | |
*/ | |
std::vector<std::byte> serialize() const; | |
/** | |
* @brief Attempts to deserialize a message from raw bytes. | |
* @param _data Raw byte data containing a message. | |
* @return Message on good deserialize, otherwise nullopt. | |
*/ | |
static std::optional<Message> deserialize(std::span<const std::byte> _data); | |
Message() : | |
vt_(Message_Ping{}) | |
{}; | |
template <jc::cx_element_of<vt> T> | |
Message(const T& _message) : | |
vt_(_message) | |
{}; | |
template <jc::cx_element_of<vt> T> | |
Message(T&& _message) : | |
vt_(std::move(_message)) | |
{}; | |
private: | |
/** | |
* @brief Storage for the actual message data structure. | |
*/ | |
vt vt_; | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment