20#ifndef ORES_QT_CLIENT_MANAGER_HPP
21#define ORES_QT_CLIENT_MANAGER_HPP
31#include <boost/uuid/uuid.hpp>
32#include <rfl/json.hpp>
35#include "ores.utility/rfl/reflectors.hpp"
37#include "ores.nats/service/nats_client.hpp"
38#include "ores.nats/service/session_expired_error.hpp"
39#include "ores.nats/service/jetstream_admin.hpp"
40#include "ores.nats/service/subscription.hpp"
41#include "ores.eventing/service/event_bus.hpp"
42#include "ores.logging/make_logger.hpp"
43#include "ores.iam.api/domain/session.hpp"
44#include "ores.iam.api/messaging/session_samples_protocol.hpp"
55 { T::nats_subject } -> std::convertible_to<std::string_view>;
56 typename T::response_type;
63 boost::uuids::uuid id;
72 QString error_message;
73 bool password_reset_required =
false;
74 bool bootstrap_mode =
false;
75 bool tenant_bootstrap_mode =
false;
76 bool party_setup_required =
false;
77 boost::uuids::uuid selected_party_id;
78 std::vector<PartyInfo> available_parties;
91 QString error_message;
99 std::vector<iam::domain::session> sessions;
100 std::uint32_t total_count = 0;
114 inline static std::string_view logger_name =
115 "ores.qt.client_manager";
117 [[nodiscard]]
static auto& lg() {
119 static auto instance = make_logger(logger_name);
125 static constexpr std::chrono::seconds fast_timeout{30};
127 static constexpr std::chrono::seconds slow_timeout{120};
129 explicit ClientManager(std::shared_ptr<eventing::service::event_bus> event_bus,
130 QObject* parent =
nullptr);
154 LoginResult login(
const std::string& username,
const std::string& password);
160 const std::string& host,
162 const std::string& username,
163 const std::string& password);
169 const std::string& host,
171 const std::string& username,
172 const std::string& password);
178 const std::string& host,
180 const std::string& username,
181 const std::string& email,
182 const std::string& password);
202 [[deprecated(
"Permission checks are now server-side via RBAC")]]
221 if (!session_.is_logged_in())
return {};
222 return session_.
auth().username;
238 std::optional<boost::uuids::uuid>
accountId()
const {
return current_account_id_; }
245 return connected_host_ +
":" + std::to_string(connected_port_);
253 return connected_host_;
261 return connected_port_;
302 bool selectParty(
const boost::uuids::uuid& party_id,
const QString& party_name);
314 template <nats_request RequestType>
316 -> std::expected<typename RequestType::response_type, std::string> {
317 using ResponseType =
typename RequestType::response_type;
319 const auto json_body = rfl::json::write(request);
320 auto msg = session_.
request(RequestType::nats_subject, json_body);
321 const std::string_view data(
322 reinterpret_cast<const char*
>(msg.data.data()),
324 auto result = rfl::json::read<ResponseType>(data);
326 return std::unexpected(
327 std::string(
"Failed to deserialize response: ") +
328 result.error().what());
330 return std::move(*result);
331 }
catch (
const std::exception& e) {
332 return std::unexpected(std::string(e.what()));
346 template <nats_request RequestType>
348 std::chrono::milliseconds timeout = std::chrono::seconds(30))
349 -> std::expected<typename RequestType::response_type, std::string> {
350 using ResponseType =
typename RequestType::response_type;
351 if (!session_.is_logged_in()) {
352 return std::unexpected(std::string(
"Not logged in"));
355 const auto json_body = rfl::json::write(request);
357 RequestType::nats_subject, json_body, timeout);
358 const std::string_view data(
359 reinterpret_cast<const char*
>(msg.data.data()),
361 auto result = rfl::json::read<ResponseType>(data);
363 return std::unexpected(
364 std::string(
"Failed to deserialize response: ") +
365 result.error().what());
367 return std::move(*result);
370 BOOST_LOG_SEV(lg(), warn) <<
"Session expired: " << e.what();
371 QMetaObject::invokeMethod(
this,
"sessionExpired", Qt::QueuedConnection);
372 return std::unexpected(std::string(e.what()));
373 }
catch (
const std::exception& e) {
374 return std::unexpected(std::string(e.what()));
383 std::uint32_t limit = 100,
384 std::uint32_t offset = 0);
394 std::optional<std::vector<iam::messaging::session_sample_dto>>
401 std::uint64_t bytesSent()
const {
return 0; }
402 std::uint64_t bytesReceived()
const {
return 0; }
403 std::uint64_t lastRttMs()
const {
return 0; }
405 std::optional<std::chrono::steady_clock::time_point> disconnectedSince()
const {
406 return disconnected_since_;
413 bool enableRecording(
const std::filesystem::path&) {
return false; }
414 void disableRecording() {}
415 bool isRecording()
const {
return false; }
416 std::filesystem::path recordingFilePath()
const {
return {}; }
417 void setRecordingDirectory(
const std::filesystem::path& dir) {
418 recording_directory_ = dir;
420 std::filesystem::path recordingDirectory()
const {
421 return recording_directory_;
428 void subscribeToEvent(
const std::string& subject);
429 void unsubscribeFromEvent(
const std::string& subject);
437 void connectionError(
const QString& message);
448 void notificationReceived(
const QString& eventType,
const QDateTime& timestamp,
449 const QStringList& entityIds,
const QString& tenantId,
450 int payloadType,
const QByteArray& payload);
452 void recordingStarted(
const QString& filePath);
453 void recordingStopped();
454 void streamingStarted();
455 void streamingStopped();
459 static constexpr double refresh_lifetime_ratio = 0.8;
468 void arm_refresh_timer(
int lifetime_s);
476 void onRefreshTimer();
482 std::string subject_prefix_;
485 std::shared_ptr<eventing::service::event_bus> event_bus_;
488 std::string connected_host_;
489 std::uint16_t connected_port_{0};
492 std::filesystem::path recording_directory_;
495 std::optional<std::chrono::steady_clock::time_point> disconnected_since_;
498 std::string stored_username_;
499 std::string stored_password_;
502 std::optional<boost::uuids::uuid> current_account_id_;
503 std::string current_email_;
506 boost::uuids::uuid current_party_id_;
507 QString current_party_name_;
508 QString current_party_category_;
509 bool last_party_setup_required_ =
false;
512 std::unordered_map<std::string, nats::service::subscription> nats_subscriptions_;
515 QTimer* refresh_timer_ =
nullptr;
Implements logging infrastructure for ORE Studio.
Definition boost_severity.hpp:28
Qt-based graphical user interface for ORE Studio.
Definition AboutDialog.hpp:29
JetStream management API.
Definition jetstream_admin.hpp:53
Authenticated NATS client for both interactive and service-to-service use.
Definition nats_client.hpp:72
const login_info & auth() const
Return current auth info.
Definition nats_client.cpp:76
message request(std::string_view subject, std::string_view json_body)
Unauthenticated synchronous request.
Definition nats_client.cpp:90
message authenticated_request(std::string_view subject, std::string_view json_body, std::chrono::milliseconds timeout=std::chrono::seconds(30))
Authenticated synchronous request — string body overload.
Definition nats_client.cpp:184
Thrown when a session reaches its maximum allowed duration.
Definition session_expired_error.hpp:34
Summary of a party the user can select during login.
Definition ClientManager.hpp:62
Result of a login attempt.
Definition ClientManager.hpp:70
std::string http_base_url
HTTP base URL discovered from the HTTP server via NATS. Empty if discovery failed or the HTTP server ...
Definition ClientManager.hpp:83
Result of a signup attempt.
Definition ClientManager.hpp:89
Result of a session list request.
Definition ClientManager.hpp:98
Manages the lifecycle of the NATS client and login state.
Definition ClientManager.hpp:110
bool logout()
Logout the current user without disconnecting.
Definition ClientManager.cpp:443
LoginResult login(const std::string &username, const std::string &password)
Login on an already connected client.
Definition ClientManager.cpp:106
QString currentPartyName() const
Get the name of the currently selected party.
Definition ClientManager.hpp:282
std::string serverAddress() const
Get the server address string.
Definition ClientManager.hpp:243
std::string currentUsername() const
Get the current logged-in user's username.
Definition ClientManager.hpp:220
void sessionExpired()
Emitted when the session can no longer be refreshed.
LoginResult connect(const std::string &host, std::uint16_t port)
Connect to the NATS server without logging in.
Definition ClientManager.cpp:57
bool isSystemParty() const
Returns true if the currently selected party is the system party.
Definition ClientManager.hpp:292
boost::uuids::uuid currentPartyId() const
Get the UUID of the currently selected party.
Definition ClientManager.hpp:277
std::uint16_t connectedPort() const
Get the connected server port.
Definition ClientManager.hpp:259
bool lastPartySetupRequired() const
Whether the last selectParty call indicated the party needs setup.
Definition ClientManager.hpp:297
std::optional< SessionListResult > listSessions(const boost::uuids::uuid &accountId, std::uint32_t limit=100, std::uint32_t offset=0)
List sessions for an account.
Definition ClientManager.cpp:502
LoginResult connectAndLogin(const std::string &host, std::uint16_t port, const std::string &username, const std::string &password)
Connect to the server and perform login.
Definition ClientManager.cpp:259
std::optional< std::vector< iam::messaging::session_sample_dto > > getSessionSamples(const boost::uuids::uuid &sessionId)
Get time-series samples for a session.
Definition ClientManager.cpp:554
bool isConnected() const
Check if currently connected.
Definition ClientManager.cpp:460
std::string storedUsername() const
Get the stored username used for the current session.
Definition ClientManager.hpp:267
void disconnect()
Logout the current user and disconnect from the server.
Definition ClientManager.cpp:418
std::string connectedHost() const
Get the connected server hostname.
Definition ClientManager.hpp:251
SignupResult signup(const std::string &host, std::uint16_t port, const std::string &username, const std::string &email, const std::string &password)
Connect to the server and attempt signup.
Definition ClientManager.cpp:312
nats::service::jetstream_admin admin()
Create a JetStream admin handle for managing streams and consumers.
Definition ClientManager.cpp:546
bool isLoggedIn() const
Check if currently logged in.
Definition ClientManager.hpp:208
std::string currentEmail() const
Get the current logged-in user's email.
Definition ClientManager.hpp:228
void setCurrentEmail(const std::string &email)
Set the current logged-in user's email.
Definition ClientManager.hpp:233
auto process_request(RequestType request) -> std::expected< typename RequestType::response_type, std::string >
Process a request that does not require authentication.
Definition ClientManager.hpp:315
void setSubjectPrefix(const std::string &prefix)
Set the NATS subject prefix used for all outbound messages.
Definition ClientManager.hpp:139
std::optional< boost::uuids::uuid > accountId() const
Get the account ID if logged in.
Definition ClientManager.hpp:238
std::string storedPassword() const
Get the stored password used for the current session.
Definition ClientManager.hpp:272
bool isAdmin() const
Definition ClientManager.hpp:203
QString currentPartyCategory() const
Get the category of the currently selected party.
Definition ClientManager.hpp:287
bool selectParty(const boost::uuids::uuid &party_id, const QString &party_name)
Select a party for the current session.
Definition ClientManager.cpp:464
LoginResult testConnection(const std::string &host, std::uint16_t port, const std::string &username, const std::string &password)
Test a connection without affecting main client state.
Definition ClientManager.cpp:272
const std::string & subjectPrefix() const
Get the current NATS subject prefix.
Definition ClientManager.hpp:144
std::optional< std::vector< iam::domain::session > > getActiveSessions()
Get active sessions for the current user.
Definition ClientManager.cpp:531
auto process_authenticated_request(RequestType request, std::chrono::milliseconds timeout=std::chrono::seconds(30)) -> std::expected< typename RequestType::response_type, std::string >
Process a request that requires authentication.
Definition ClientManager.hpp:347
Concept for NATS-aware request types.
Definition ClientManager.hpp:54