124 lines
3.6 KiB
C++
124 lines
3.6 KiB
C++
//-----------------------------------------------------------------------------
|
|
// ___ __ _ _
|
|
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
|
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
|
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
|
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// Author: Kurt Sassenrath
|
|
// Module: Proto
|
|
//
|
|
// Message type definitions for the parselink protocol.
|
|
//
|
|
// Copyright (c) 2023 Kurt Sassenrath.
|
|
//
|
|
// License TBD.
|
|
//-----------------------------------------------------------------------------
|
|
#ifndef message_0c61530748b9f966
|
|
#define message_0c61530748b9f966
|
|
|
|
#include <span>
|
|
#include <string_view>
|
|
#include <cstdint>
|
|
|
|
#include <tl/expected.hpp>
|
|
#include <variant>
|
|
|
|
namespace parselink {
|
|
namespace proto {
|
|
|
|
// Parselink messages are encoded with MessagePack and take the form of:
|
|
// | magic | size | content |
|
|
// - [magic] is the string "prs", in "fixstr" format.
|
|
// - [size] is the size of the message, not including this header.
|
|
// - [content] is [size] bytes of MessagePack data, including the
|
|
// specific type of message presented.
|
|
// This may be revised in the future. The header could remain as msgpack, or
|
|
// switch to something hand-crafted for saving bits.
|
|
|
|
struct error_message {
|
|
std::uint32_t code; // An error code
|
|
std::string_view what; // A string
|
|
};
|
|
|
|
// C->S: Request to (re)connect.
|
|
struct connect_message {
|
|
std::uint32_t user_id; // The user id.
|
|
std::uint32_t version; // The version of the client.
|
|
std::span<std::byte> session_token; // An optional existing session token.
|
|
};
|
|
|
|
// S->C: Challenge to authenticate client as user_id
|
|
struct challenge_message {
|
|
std::uint32_t version;
|
|
std::span<std::byte> challenge;
|
|
};
|
|
|
|
// C->S: Calculated response to a challenge.
|
|
struct response_message {
|
|
std::span<std::byte> response;
|
|
};
|
|
|
|
// S->C: Session token.
|
|
struct session_established_message {
|
|
std::span<std::byte> session_token;
|
|
};
|
|
|
|
struct parser_data_message {
|
|
std::string_view opts;
|
|
std::span<std::byte> payload;
|
|
};
|
|
|
|
using message = std::variant<
|
|
error_message,
|
|
connect_message,
|
|
challenge_message,
|
|
response_message,
|
|
session_established_message,
|
|
parser_data_message>;
|
|
|
|
enum class error {
|
|
bad_magic, // Did not get the message magic expected
|
|
too_large, // The message size was too large.
|
|
unknown_type, // The message type is not known
|
|
};
|
|
|
|
// This class is responsible for consuming buffer data and yielding a message
|
|
// instance when complete. Will throw an error if data is incorrect.
|
|
//
|
|
class builder {
|
|
public:
|
|
// For now, builders don't manage any buffers themselves. Later, that
|
|
// may change.
|
|
builder() = default;
|
|
|
|
// Reset the builder to its initial state. This means any partially-decoded
|
|
// message data will be lost.
|
|
void reset() noexcept;
|
|
|
|
// How many bytes are needed to perform a meaningful amount of work.
|
|
std::size_t bytes_needed() noexcept;
|
|
|
|
// Process data from a buffer, building messages. Returns the number of
|
|
// bytes read from the buffer for the caller's bookkeeping. May yield a
|
|
// message in addition.
|
|
std::size_t process(std::span<std::byte const> buffer) noexcept;
|
|
|
|
private:
|
|
enum class state {
|
|
magic,
|
|
size,
|
|
payload
|
|
};
|
|
|
|
state state_{state::magic};
|
|
std::size_t payload_size_{};
|
|
std::size_t payload_remaining_{};
|
|
};
|
|
|
|
} // namespace message
|
|
} // namespace parselink
|
|
|
|
#endif // message_0c61530748b9f966
|