- proto::parser will likely contain helper functions for parsing messages from a buffer, for now it will explicitly define message parsers for each available message. It also leverages the new unpacker API, which has type safety in mind. These messages should not be unstructured, so it doesn't make sense to use the token API.
121 lines
3.4 KiB
C++
121 lines
3.4 KiB
C++
//-----------------------------------------------------------------------------
|
|
// ___ __ _ _
|
|
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
|
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
|
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
|
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// Author: Kurt Sassenrath
|
|
// Module: Proto
|
|
//
|
|
// Session management for the "user" protocol.
|
|
//
|
|
// Copyright (c) 2023 Kurt Sassenrath.
|
|
//
|
|
// License TBD.
|
|
//-----------------------------------------------------------------------------
|
|
#ifndef session_07eae057feface79
|
|
#define session_07eae057feface79
|
|
|
|
#include "parselink/msgpack/token.h"
|
|
#include "parselink/proto/error.h"
|
|
#include "parselink/proto/session_id.h"
|
|
|
|
#include <tl/expected.hpp>
|
|
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <span>
|
|
#include <string>
|
|
|
|
template <>
|
|
struct std::hash<std::span<std::byte const>> {
|
|
constexpr static std::uint32_t seed_var = 0x811c9dc5;
|
|
constexpr static std::uint32_t factor = 0x01000193;
|
|
|
|
constexpr auto operator()(std::span<std::byte const> data) const noexcept {
|
|
std::uint32_t digest = seed_var * factor;
|
|
for (auto byte : data) {
|
|
digest = (digest ^ static_cast<std::uint32_t>(byte)) * factor;
|
|
}
|
|
return digest >> 8;
|
|
}
|
|
};
|
|
|
|
namespace parselink {
|
|
namespace proto {
|
|
|
|
// Structure containing header information parsed from a buffer.
|
|
struct header_info {
|
|
std::uint32_t message_size; // Size of the message, minus the header.
|
|
std::uint32_t bytes_read; // How many bytes of the buffer were used.
|
|
std::uint32_t bytes_parsed; // How many bytes were parsed as part of the
|
|
// header.
|
|
};
|
|
|
|
struct connect_info {
|
|
std::uint32_t version;
|
|
std::string_view user_id;
|
|
std::span<std::byte const> session_id;
|
|
};
|
|
|
|
template <typename T>
|
|
struct transparent_hash {
|
|
using is_transparent = void;
|
|
using type = T;
|
|
using hash_type = std::hash<type>;
|
|
|
|
template <typename Arg>
|
|
[[nodiscard]] constexpr auto operator()(Arg&& arg) const {
|
|
return hash_type{}(std::forward<Arg>(arg));
|
|
}
|
|
};
|
|
|
|
class session {
|
|
public:
|
|
using close_handle = std::function<void(std::string_view)>;
|
|
session(std::string_view user_id) noexcept;
|
|
|
|
~session();
|
|
|
|
session_id id() const noexcept { return id_; }
|
|
|
|
std::string_view user_id() const noexcept { return user_id_; }
|
|
|
|
auto last_activity() const noexcept { return last_activity_; }
|
|
|
|
void update_last_activity(
|
|
std::chrono::system_clock::time_point =
|
|
std::chrono::system_clock::now()) noexcept {}
|
|
|
|
private:
|
|
session_id id_;
|
|
std::string user_id_;
|
|
std::chrono::system_clock::time_point last_activity_;
|
|
};
|
|
|
|
template <>
|
|
struct transparent_hash<std::string> : transparent_hash<std::string_view> {};
|
|
|
|
template <>
|
|
struct transparent_hash<session_id>
|
|
: transparent_hash<std::span<std::byte const>> {
|
|
[[nodiscard]] auto operator()(session_id const& s) const {
|
|
return std::hash<std::span<std::byte const>>{}(s.raw());
|
|
}
|
|
};
|
|
|
|
// Parse the protocol header out of a buffer.
|
|
tl::expected<header_info, error> parse_header(
|
|
std::span<std::byte const> buffer) noexcept;
|
|
|
|
tl::expected<connect_info, error> parse_connect(
|
|
std::span<msgpack::token> tokens) noexcept;
|
|
|
|
} // namespace proto
|
|
} // namespace parselink
|
|
|
|
#endif // session_0c61530748b9f966
|