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 boost::uuids::uuid selected_party_id;
77 std::vector<PartyInfo> available_parties;
90 QString error_message;
98 std::vector<iam::domain::session> sessions;
99 std::uint32_t total_count = 0;
113 inline static std::string_view logger_name =
114 "ores.qt.client_manager";
116 [[nodiscard]]
static auto& lg() {
118 static auto instance = make_logger(logger_name);
124 static constexpr std::chrono::seconds fast_timeout{30};
126 static constexpr std::chrono::seconds slow_timeout{120};
128 explicit ClientManager(std::shared_ptr<eventing::service::event_bus> event_bus,
129 QObject* parent =
nullptr);
153 LoginResult login(
const std::string& username,
const std::string& password);
159 const std::string& host,
161 const std::string& username,
162 const std::string& password);
168 const std::string& host,
170 const std::string& username,
171 const std::string& password);
177 const std::string& host,
179 const std::string& username,
180 const std::string& email,
181 const std::string& password);
201 [[deprecated(
"Permission checks are now server-side via RBAC")]]
220 if (!session_.is_logged_in())
return {};
221 return session_.
auth().username;
237 std::optional<boost::uuids::uuid>
accountId()
const {
return current_account_id_; }
244 return connected_host_ +
":" + std::to_string(connected_port_);
252 return connected_host_;
260 return connected_port_;
296 bool selectParty(
const boost::uuids::uuid& party_id,
const QString& party_name);
308 template <nats_request RequestType>
310 -> std::expected<typename RequestType::response_type, std::string> {
311 using ResponseType =
typename RequestType::response_type;
313 const auto json_body = rfl::json::write(request);
314 auto msg = session_.
request(RequestType::nats_subject, json_body);
315 const std::string_view data(
316 reinterpret_cast<const char*
>(msg.data.data()),
318 auto result = rfl::json::read<ResponseType>(data);
320 return std::unexpected(
321 std::string(
"Failed to deserialize response: ") +
322 result.error().what());
324 return std::move(*result);
325 }
catch (
const std::exception& e) {
326 return std::unexpected(std::string(e.what()));
340 template <nats_request RequestType>
342 std::chrono::milliseconds timeout = std::chrono::seconds(30))
343 -> std::expected<typename RequestType::response_type, std::string> {
344 using ResponseType =
typename RequestType::response_type;
345 if (!session_.is_logged_in()) {
346 return std::unexpected(std::string(
"Not logged in"));
349 const auto json_body = rfl::json::write(request);
351 RequestType::nats_subject, json_body, timeout);
352 const std::string_view data(
353 reinterpret_cast<const char*
>(msg.data.data()),
355 auto result = rfl::json::read<ResponseType>(data);
357 return std::unexpected(
358 std::string(
"Failed to deserialize response: ") +
359 result.error().what());
361 return std::move(*result);
364 BOOST_LOG_SEV(lg(), warn) <<
"Session expired: " << e.what();
365 QMetaObject::invokeMethod(
this,
"sessionExpired", Qt::QueuedConnection);
366 return std::unexpected(std::string(e.what()));
367 }
catch (
const std::exception& e) {
368 return std::unexpected(std::string(e.what()));
377 std::uint32_t limit = 100,
378 std::uint32_t offset = 0);
388 std::optional<std::vector<iam::messaging::session_sample_dto>>
395 std::uint64_t bytesSent()
const {
return 0; }
396 std::uint64_t bytesReceived()
const {
return 0; }
397 std::uint64_t lastRttMs()
const {
return 0; }
399 std::optional<std::chrono::steady_clock::time_point> disconnectedSince()
const {
400 return disconnected_since_;
407 bool enableRecording(
const std::filesystem::path&) {
return false; }
408 void disableRecording() {}
409 bool isRecording()
const {
return false; }
410 std::filesystem::path recordingFilePath()
const {
return {}; }
411 void setRecordingDirectory(
const std::filesystem::path& dir) {
412 recording_directory_ = dir;
414 std::filesystem::path recordingDirectory()
const {
415 return recording_directory_;
422 void subscribeToEvent(
const std::string& subject);
423 void unsubscribeFromEvent(
const std::string& subject);
431 void connectionError(
const QString& message);
442 void notificationReceived(
const QString& eventType,
const QDateTime& timestamp,
443 const QStringList& entityIds,
const QString& tenantId,
444 int payloadType,
const QByteArray& payload);
446 void recordingStarted(
const QString& filePath);
447 void recordingStopped();
448 void streamingStarted();
449 void streamingStopped();
453 static constexpr double refresh_lifetime_ratio = 0.8;
462 void arm_refresh_timer(
int lifetime_s);
470 void onRefreshTimer();
476 std::string subject_prefix_;
479 std::shared_ptr<eventing::service::event_bus> event_bus_;
482 std::string connected_host_;
483 std::uint16_t connected_port_{0};
486 std::filesystem::path recording_directory_;
489 std::optional<std::chrono::steady_clock::time_point> disconnected_since_;
492 std::string stored_username_;
493 std::string stored_password_;
496 std::optional<boost::uuids::uuid> current_account_id_;
497 std::string current_email_;
500 boost::uuids::uuid current_party_id_;
501 QString current_party_name_;
502 QString current_party_category_;
505 std::unordered_map<std::string, nats::service::subscription> nats_subscriptions_;
508 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:71
const login_info & auth() const
Return current auth info.
Definition nats_client.cpp:75
message request(std::string_view subject, std::string_view json_body)
Unauthenticated synchronous request.
Definition nats_client.cpp:89
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:136
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:82
Result of a signup attempt.
Definition ClientManager.hpp:88
Result of a session list request.
Definition ClientManager.hpp:97
Manages the lifecycle of the NATS client and login state.
Definition ClientManager.hpp:109
bool logout()
Logout the current user without disconnecting.
Definition ClientManager.cpp:433
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:281
std::string serverAddress() const
Get the server address string.
Definition ClientManager.hpp:242
std::string currentUsername() const
Get the current logged-in user's username.
Definition ClientManager.hpp:219
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:291
boost::uuids::uuid currentPartyId() const
Get the UUID of the currently selected party.
Definition ClientManager.hpp:276
std::uint16_t connectedPort() const
Get the connected server port.
Definition ClientManager.hpp:258
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:490
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:249
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:542
bool isConnected() const
Check if currently connected.
Definition ClientManager.cpp:450
std::string storedUsername() const
Get the stored username used for the current session.
Definition ClientManager.hpp:266
void disconnect()
Logout the current user and disconnect from the server.
Definition ClientManager.cpp:408
std::string connectedHost() const
Get the connected server hostname.
Definition ClientManager.hpp:250
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:302
nats::service::jetstream_admin admin()
Create a JetStream admin handle for managing streams and consumers.
Definition ClientManager.cpp:534
bool isLoggedIn() const
Check if currently logged in.
Definition ClientManager.hpp:207
std::string currentEmail() const
Get the current logged-in user's email.
Definition ClientManager.hpp:227
void setCurrentEmail(const std::string &email)
Set the current logged-in user's email.
Definition ClientManager.hpp:232
auto process_request(RequestType request) -> std::expected< typename RequestType::response_type, std::string >
Process a request that does not require authentication.
Definition ClientManager.hpp:309
void setSubjectPrefix(const std::string &prefix)
Set the NATS subject prefix used for all outbound messages.
Definition ClientManager.hpp:138
std::optional< boost::uuids::uuid > accountId() const
Get the account ID if logged in.
Definition ClientManager.hpp:237
std::string storedPassword() const
Get the stored password used for the current session.
Definition ClientManager.hpp:271
bool isAdmin() const
Definition ClientManager.hpp:202
QString currentPartyCategory() const
Get the category of the currently selected party.
Definition ClientManager.hpp:286
bool selectParty(const boost::uuids::uuid &party_id, const QString &party_name)
Select a party for the current session.
Definition ClientManager.cpp:454
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:262
const std::string & subjectPrefix() const
Get the current NATS subject prefix.
Definition ClientManager.hpp:143
std::optional< std::vector< iam::domain::session > > getActiveSessions()
Get active sessions for the current user.
Definition ClientManager.cpp:519
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:341
Concept for NATS-aware request types.
Definition ClientManager.hpp:54