20#ifndef ORES_COMMS_NET_CLIENT_SESSION_HPP
21#define ORES_COMMS_NET_CLIENT_SESSION_HPP
33#include <boost/uuid/uuid.hpp>
34#include "ores.logging/make_logger.hpp"
35#include "ores.comms/messaging/message_types.hpp"
36#include "ores.comms/messaging/message_traits.hpp"
37#include "ores.comms/messaging/frame.hpp"
38#include "ores.comms/messaging/error_protocol.hpp"
39#include "ores.comms/net/client.hpp"
40#include "ores.comms/net/client_options.hpp"
44class remote_event_adapter;
57 boost::uuids::uuid account_id;
68 std::string event_type;
69 std::chrono::system_clock::time_point timestamp;
70 std::vector<std::string> entity_ids;
82 deserialization_failed,
100 : code(c), message(std::move(msg)) {}
103template<
typename Request>
104concept Serializable =
requires(Request req) {
105 { req.serialize() } -> std::convertible_to<std::vector<std::byte>>;
108template<
typename Response>
109concept Deserializable =
requires(std::span<const std::byte> data) {
111 Response::deserialize(data)
112 } -> std::same_as<std::expected<Response, ores::utility::serialization::error_code>>;
127 inline static std::string_view logger_name =
128 "ores.comms.net.client_session";
132 static auto instance = make_logger(logger_name);
167 std::expected<void, session_error>
199 [[nodiscard]] std::shared_ptr<client>
get_client() const noexcept {
207 return session_info_.has_value();
218 session_info_ = std::move(info);
227 session_info_.reset();
233 [[nodiscard]]
const std::optional<client_session_info>&
session_info() const noexcept {
234 return session_info_;
240 [[nodiscard]] std::string
username() const noexcept {
241 return session_info_.has_value() ? session_info_->username : std::string{};
247 [[nodiscard]] std::string
email() const noexcept {
248 return session_info_.has_value() ? session_info_->email : std::string{};
257 if (session_info_.has_value()) {
258 session_info_->email =
email;
265 [[nodiscard]] std::optional<boost::uuids::uuid>
account_id() const noexcept {
266 if (session_info_.has_value()) {
267 return session_info_->account_id;
283 template <Serializable RequestType,
284 Deserializable ResponseType,
285 messaging::message_type RequestMsgType>
286 std::expected<ResponseType, session_error>
290 if (!client_ || !client_->is_connected()) {
291 BOOST_LOG_SEV(lg(), error) <<
"Not connected to server";
292 return std::unexpected(
session_error(client_session_error::not_connected));
295 BOOST_LOG_SEV(lg(), debug) <<
"Processing request type: "
298 auto payload = request.serialize();
301 auto response_result = client_->send_request_sync(std::move(request_frame));
303 if (!response_result) {
304 auto error_code = response_result.error();
305 BOOST_LOG_SEV(lg(), error) <<
"Request failed with error code: "
306 <<
static_cast<int>(error_code);
308 if (error_code == ores::utility::serialization::error_code::network_error) {
310 client_session_error::connection_lost,
311 "Connection to server lost"));
314 client_session_error::request_failed,
318 auto decompressed = response_result->decompressed_payload();
320 BOOST_LOG_SEV(lg(), error) <<
"Failed to decompress response payload";
321 return std::unexpected(
session_error(client_session_error::deserialization_failed));
325 if (response_result->header().type == messaging::message_type::error_response) {
328 BOOST_LOG_SEV(lg(), error) <<
"Server returned error: "
329 << err_resp->message;
331 client_session_error::server_error,
334 return std::unexpected(
session_error(client_session_error::server_error));
337 auto response = ResponseType::deserialize(*decompressed);
339 BOOST_LOG_SEV(lg(), error) <<
"Failed to deserialize response";
340 return std::unexpected(
session_error(client_session_error::deserialization_failed));
343 BOOST_LOG_SEV(lg(), debug) <<
"Successfully processed request";
344 return std::move(*response);
358 template <Serializable RequestType,
359 Deserializable ResponseType,
360 messaging::message_type RequestMsgType>
361 std::expected<ResponseType, session_error>
365 BOOST_LOG_SEV(lg(), warn) <<
"Attempted authenticated request while "
367 return std::unexpected(
session_error(client_session_error::not_logged_in));
369 return process_request<RequestType, ResponseType, RequestMsgType>(
387 template <Serializable RequestType,
388 Deserializable ResponseType,
389 messaging::message_type RequestMsgType>
390 [[deprecated(
"Permission checks are now server-side via RBAC")]]
391 std::expected<ResponseType, session_error>
394 return process_authenticated_request<RequestType, ResponseType, RequestMsgType>(
414 template <
typename RequestType>
416 std::expected<typename messaging::message_traits<RequestType>::response_type,
422 typename traits::response_type,
423 traits::request_message_type>(std::move(request));
433 template <
typename RequestType>
435 std::expected<typename messaging::message_traits<RequestType>::response_type,
441 typename traits::response_type,
442 traits::request_message_type>(std::move(request));
455 template <
typename RequestType>
457 [[deprecated(
"Permission checks are now server-side via RBAC")]]
458 std::expected<typename messaging::message_traits<RequestType>::response_type,
474 bool subscribe(
const std::string& event_type);
492 [[nodiscard]]
bool is_subscribed(
const std::string& event_type)
const;
522 const std::string& event_type,
523 std::chrono::system_clock::time_point timestamp,
524 const std::vector<std::string>& entity_ids)>;
545 void on_notification(
const std::string& event_type,
546 std::chrono::system_clock::time_point timestamp,
547 const std::vector<std::string>& entity_ids);
549 std::shared_ptr<client> client_;
550 std::unique_ptr<service::remote_event_adapter> event_adapter_;
551 std::optional<client_session_info> session_info_;
552 mutable std::mutex notifications_mutex_;
553 std::deque<pending_notification> pending_notifications_;
560 bool external_client_{
false};
574std::string
to_string(
const session_error& error);
std::string to_string(ores::utility::serialization::error_code ec)
Convert error_code to string for display.
Definition message_types.hpp:592
Main server application for ORE Studio.
Definition application.hpp:30
Contains the networking elements of the comms library.
Definition client.hpp:48
std::string to_string(client_session_error error)
Convert client_session_error to string for display.
Definition client_session.cpp:242
client_session_error
Error codes specific to client session operations.
Definition client_session.hpp:76
Implements logging infrastructure for ORE Studio.
Definition boost_severity.hpp:28
static std::expected< error_response, ores::utility::serialization::error_code > deserialize(std::span< const std::byte > data)
Deserialize from frame payload.
Definition handshake.cpp:113
Complete frame with header and payload.
Definition frame.hpp:77
Traits template for mapping request types to their response types and message type enum values.
Definition message_traits.hpp:66
Configuration for the client.
Definition client_options.hpp:78
Information about the client's authenticated session.
Definition client_session.hpp:56
A notification received from the server.
Definition client_session.hpp:67
Error information returned from client session operations.
Definition client_session.hpp:92
Client-side session manager providing auth-aware request handling.
Definition client_session.hpp:125
std::function< void(const std::string &event_type, std::chrono::system_clock::time_point timestamp, const std::vector< std::string > &entity_ids)> notification_callback_t
Notification callback function type.
Definition client_session.hpp:524
void set_notification_callback(notification_callback_t callback)
Set an external notification callback.
Definition client_session.cpp:238
bool is_connected() const noexcept
Check if connected to server.
Definition client_session.cpp:172
bool unsubscribe(const std::string &event_type)
Unsubscribe from notifications for an event type.
Definition client_session.cpp:185
std::expected< typename messaging::message_traits< RequestType >::response_type, session_error > process_admin_request(RequestType request)
Process a request using message_traits (requires admin).
Definition client_session.hpp:460
const std::optional< client_session_info > & session_info() const noexcept
Get current session info if logged in.
Definition client_session.hpp:233
bool subscribe(const std::string &event_type)
Subscribe to notifications for an event type.
Definition client_session.cpp:176
std::expected< ResponseType, session_error > process_admin_request(RequestType request)
Process a request that requires admin privileges.
Definition client_session.hpp:392
std::optional< boost::uuids::uuid > account_id() const noexcept
Get the account ID if logged in.
Definition client_session.hpp:265
std::set< std::string > get_subscriptions() const
Get the set of currently subscribed event types.
Definition client_session.cpp:201
std::string username() const noexcept
Get the current username if logged in.
Definition client_session.hpp:240
std::vector< pending_notification > take_pending_notifications()
Get all pending notifications and clear the queue.
Definition client_session.cpp:208
std::shared_ptr< client > get_client() const noexcept
Get the underlying client.
Definition client_session.hpp:199
bool is_logged_in() const noexcept
Check if logged in.
Definition client_session.hpp:206
void clear_session_info() noexcept
Clear session info on logout.
Definition client_session.hpp:226
std::expected< typename messaging::message_traits< RequestType >::response_type, session_error > process_request(RequestType request)
Process a request using message_traits (does not require auth).
Definition client_session.hpp:418
void disconnect()
Disconnect from the server.
Definition client_session.cpp:139
void set_session_info(client_session_info info)
Set session info after successful login.
Definition client_session.hpp:217
std::expected< void, session_error > attach_client(std::shared_ptr< client > external_client)
Attach an external client to this session.
Definition client_session.cpp:81
std::string email() const noexcept
Get the current email if logged in.
Definition client_session.hpp:247
std::expected< ResponseType, session_error > process_authenticated_request(RequestType request)
Process a request that requires authentication.
Definition client_session.hpp:362
std::expected< ResponseType, session_error > process_request(RequestType request)
Process a request that does not require authentication.
Definition client_session.hpp:287
void set_email(const std::string &email)
Set the current email.
Definition client_session.hpp:256
bool is_subscribed(const std::string &event_type) const
Check if currently subscribed to an event type.
Definition client_session.cpp:194
std::expected< typename messaging::message_traits< RequestType >::response_type, session_error > process_authenticated_request(RequestType request)
Process a request using message_traits (requires authentication).
Definition client_session.hpp:437
std::expected< void, session_error > connect(client_options options)
Connect to the server.
Definition client_session.cpp:36
bool has_pending_notifications() const
Check if there are any pending notifications.
Definition client_session.cpp:218
void detach_client()
Detach an externally-attached client.
Definition client_session.cpp:121
Concept for types that have message_traits specialization.
Definition message_traits.hpp:82