ORE Studio 0.0.4
Loading...
Searching...
No Matches
ClientManager.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * Copyright (C) 2025 Marco Craveiro <marco.craveiro@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20#ifndef ORES_QT_CLIENT_MANAGER_HPP
21#define ORES_QT_CLIENT_MANAGER_HPP
22
23#include <atomic>
24#include <chrono>
25#include <memory>
26#include <optional>
27#include <string>
28#include <thread>
29#include <filesystem>
30#include <boost/asio/io_context.hpp>
31#include <boost/asio/executor_work_guard.hpp>
32#include <boost/uuid/uuid.hpp>
33#include <QObject>
34#include <QDateTime>
35#include "ores.comms/net/client.hpp"
36#include "ores.comms/net/client_session.hpp"
37#include "ores.comms/service/remote_event_adapter.hpp"
38#include "ores.comms/recording/session_recorder.hpp"
39#include "ores.comms/service/telemetry_streaming_service.hpp"
40#include "ores.eventing/service/event_bus.hpp"
41#include "ores.logging/make_logger.hpp"
42#include "ores.iam/domain/session.hpp"
43
44namespace ores::qt {
45
50 QString code;
51 QString name;
52 QString description;
53};
54
59 bool success = false;
60 QString error_message;
61 bool password_reset_required = false;
62 bool bootstrap_mode = false;
63 std::vector<BootstrapBundleInfo> available_bundles;
64};
65
70 bool success = false;
71 QString error_message;
72 QString username;
73};
74
79 std::vector<iam::domain::session> sessions;
80 std::uint32_t total_count = 0;
81};
82
90class ClientManager : public QObject {
91 Q_OBJECT
92
93private:
94 inline static std::string_view logger_name =
95 "ores.qt.client_manager";
96
97 [[nodiscard]] static auto& lg() {
98 using namespace ores::logging;
99 static auto instance = make_logger(logger_name);
100 return instance;
101 }
102
103public:
104 explicit ClientManager(std::shared_ptr<eventing::service::event_bus> event_bus,
105 QObject* parent = nullptr);
106 ~ClientManager() override;
107
122 LoginResult connect(const std::string& host, std::uint16_t port);
123
135 LoginResult login(const std::string& username, const std::string& password);
136
150 const std::string& host,
151 std::uint16_t port,
152 const std::string& username,
153 const std::string& password);
154
169 const std::string& host,
170 std::uint16_t port,
171 const std::string& username,
172 const std::string& password);
173
189 const std::string& host,
190 std::uint16_t port,
191 const std::string& username,
192 const std::string& email,
193 const std::string& password);
194
200 void disconnect();
201
208 bool logout();
209
213 bool isConnected() const;
214
222 [[deprecated("Permission checks are now server-side via RBAC")]]
223 bool isAdmin() const;
224
230 bool isLoggedIn() const { return session_.is_logged_in(); }
231
237 std::string currentUsername() const { return session_.username(); }
238
244 std::string currentEmail() const { return session_.email(); }
245
251 void setCurrentEmail(const std::string& email) { session_.set_email(email); }
252
258 std::optional<boost::uuids::uuid> accountId() const { return session_.account_id(); }
259
265 std::string serverAddress() const {
266 if (!isConnected()) {
267 return "";
268 }
269 return connected_host_ + ":" + std::to_string(connected_port_);
270 }
271
277 std::string connectedHost() const {
278 if (!isConnected()) {
279 return "";
280 }
281 return connected_host_;
282 }
283
289 std::uint16_t connectedPort() const {
290 if (!isConnected()) {
291 return 0;
292 }
293 return connected_port_;
294 }
295
303 std::expected<comms::messaging::frame, ores::utility::serialization::error_code>
305
315 template <typename RequestType>
317 auto process_request(RequestType request) {
318 return session_.process_request(std::move(request));
319 }
320
330 template <typename RequestType>
332 auto process_authenticated_request(RequestType request) {
333 return session_.process_authenticated_request(std::move(request));
334 }
335
345 template <typename RequestType>
347 auto process_admin_request(RequestType request) {
348 return session_.process_admin_request(std::move(request));
349 }
350
356 comms::net::client_session& session() { return session_; }
357
366 std::optional<SessionListResult> listSessions(
367 const boost::uuids::uuid& accountId,
368 std::uint32_t limit = 100,
369 std::uint32_t offset = 0);
370
376 std::optional<std::vector<iam::domain::session>> getActiveSessions();
377
381 std::shared_ptr<comms::net::client> getClient() const { return client_; }
382
386 boost::asio::any_io_executor getExecutor() {
387 return io_context_->get_executor();
388 }
389
398 void subscribeToEvent(const std::string& eventType);
399
408 void unsubscribeFromEvent(const std::string& eventType);
409
418 void setSupportedCompression(std::uint8_t compression) {
419 supported_compression_ = compression;
420 }
421
422 // =========================================================================
423 // Session Recording
424 // =========================================================================
425
436 bool enableRecording(const std::filesystem::path& outputDirectory);
437
444 void disableRecording();
445
449 bool isRecording() const;
450
456 std::filesystem::path recordingFilePath() const;
457
466 void setRecordingDirectory(const std::filesystem::path& directory) {
467 recording_directory_ = directory;
468 }
469
473 std::filesystem::path recordingDirectory() const {
474 return recording_directory_;
475 }
476
477 // =========================================================================
478 // Telemetry Streaming
479 // =========================================================================
480
490
497 void disableStreaming();
498
502 bool isStreaming() const;
503
509 std::size_t streamingPendingCount() const;
510
514 std::uint64_t streamingTotalSent() const;
515
519 std::uint64_t streamingTotalDropped() const;
520
521signals:
522 void connected();
523 void loggedIn();
524 void disconnected();
525 void reconnecting();
526 void reconnected();
527 void connectionError(const QString& message);
528
536 void notificationReceived(const QString& eventType, const QDateTime& timestamp,
537 const QStringList& entityIds);
538
544 void recordingStarted(const QString& filePath);
545
550
555
560
561private:
562 void setupIO();
563 void cleanupIO();
564
565private:
566 // Persistent IO infrastructure
567 std::unique_ptr<boost::asio::io_context> io_context_;
568 std::unique_ptr<boost::asio::executor_work_guard<
569 boost::asio::io_context::executor_type>> work_guard_;
570 std::unique_ptr<std::thread> io_thread_;
571
572 // Transient client (owned by ClientManager, attached to session_)
573 std::shared_ptr<comms::net::client> client_;
574
575 // Client session for auth-aware request handling and session state
577
578 // Event bus for publishing connection events (passed to client)
579 std::shared_ptr<eventing::service::event_bus> event_bus_;
580
581 // Connection details for event publishing
582 std::string connected_host_;
583 std::uint16_t connected_port_{0};
584
585 // Compression support bitmask (default: all compression types)
586 std::uint8_t supported_compression_{0x07}; // COMPRESSION_SUPPORT_ALL
587
588 // Session recording output directory
589 std::filesystem::path recording_directory_;
590
591 // Whether recording is enabled (can be set before connection)
592 bool recording_enabled_{false};
593
594 // Telemetry streaming service
595 std::unique_ptr<comms::service::telemetry_streaming_service> telemetry_streaming_;
596
597 // Streaming options (stored when enabled before connection)
598 std::optional<comms::service::telemetry_streaming_options> pending_streaming_options_;
599
600 // Whether streaming is enabled (can be set before connection)
601 bool streaming_enabled_{false};
602
603 // Flag to distinguish user-initiated disconnect from connection loss
604 // Set to true when user clicks disconnect, checked before emitting reconnecting signal
605 std::atomic<bool> user_disconnecting_{false};
606
607 // Stored credentials for re-authentication after reconnection
608 // Note: storing password in memory is acceptable for desktop apps since
609 // the password was already in memory during initial login
610 std::string stored_username_;
611 std::string stored_password_;
612};
613
614}
615
616#endif
Implements logging infrastructure for ORE Studio.
Definition boost_severity.hpp:28
Qt-based graphical user interface for ORE Studio.
Definition AboutDialog.hpp:35
Complete frame with header and payload.
Definition frame.hpp:77
Client-side session manager providing auth-aware request handling.
Definition client_session.hpp:125
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::string username() const noexcept
Get the current username if logged in.
Definition client_session.hpp:240
bool is_logged_in() const noexcept
Check if logged in.
Definition client_session.hpp:206
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
Configuration options for telemetry streaming.
Definition telemetry_streaming_service.hpp:49
Lightweight bundle info for bootstrap wizard.
Definition ClientManager.hpp:49
Result of a login attempt.
Definition ClientManager.hpp:58
bool bootstrap_mode
True if system is in bootstrap mode (no admin exists)
Definition ClientManager.hpp:62
std::vector< BootstrapBundleInfo > available_bundles
Bundles available when in bootstrap mode.
Definition ClientManager.hpp:63
Result of a signup attempt.
Definition ClientManager.hpp:69
Result of a session list request.
Definition ClientManager.hpp:78
Manages the lifecycle of the network client and IO context.
Definition ClientManager.hpp:90
bool logout()
Logout the current user without disconnecting.
Definition ClientManager.cpp:741
void streamingStopped()
Emitted when telemetry streaming stops.
LoginResult login(const std::string &username, const std::string &password)
Login on an already connected client.
Definition ClientManager.cpp:294
void recordingStarted(const QString &filePath)
Emitted when session recording starts.
void unsubscribeFromEvent(const std::string &eventType)
Unsubscribe from server-push notifications for an event type.
Definition ClientManager.cpp:843
std::string serverAddress() const
Get the server address string.
Definition ClientManager.hpp:265
void enableStreaming(const comms::service::telemetry_streaming_options &options)
Enable telemetry streaming to the server.
Definition ClientManager.cpp:1056
std::string currentUsername() const
Get the current logged-in user's username.
Definition ClientManager.hpp:237
std::filesystem::path recordingFilePath() const
Get the path to the current recording file.
Definition ClientManager.cpp:1042
LoginResult connect(const std::string &host, std::uint16_t port)
Connect to the server without logging in.
Definition ClientManager.cpp:81
void streamingStarted()
Emitted when telemetry streaming starts.
bool isRecording() const
Check if session recording is currently active.
Definition ClientManager.cpp:1038
void setRecordingDirectory(const std::filesystem::path &directory)
Set the recording output directory.
Definition ClientManager.hpp:466
comms::net::client_session & session()
Get the underlying client session.
Definition ClientManager.hpp:356
std::uint16_t connectedPort() const
Get the connected server port.
Definition ClientManager.hpp:289
void disableRecording()
Disable session recording.
Definition ClientManager.cpp:1018
void recordingStopped()
Emitted when session recording stops.
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:863
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:462
auto process_request(RequestType request)
Process a request that does not require authentication.
Definition ClientManager.hpp:317
void subscribeToEvent(const std::string &eventType)
Subscribe to server-push notifications for an event type.
Definition ClientManager.cpp:823
std::expected< comms::messaging::frame, ores::utility::serialization::error_code > sendRequest(comms::messaging::frame request)
Send a request if connected.
Definition ClientManager.cpp:816
bool isConnected() const
Check if currently connected.
Definition ClientManager.cpp:806
std::filesystem::path recordingDirectory() const
Get the current recording output directory.
Definition ClientManager.hpp:473
std::shared_ptr< comms::net::client > getClient() const
Get the current client (internal use only).
Definition ClientManager.hpp:381
void disconnect()
Logout the current user and disconnect from the server.
Definition ClientManager.cpp:695
bool isStreaming() const
Check if telemetry streaming is currently active.
Definition ClientManager.cpp:1113
void disableStreaming()
Disable telemetry streaming.
Definition ClientManager.cpp:1094
std::string connectedHost() const
Get the connected server hostname.
Definition ClientManager.hpp:277
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:575
bool isLoggedIn() const
Check if currently logged in.
Definition ClientManager.hpp:230
std::string currentEmail() const
Get the current logged-in user's email.
Definition ClientManager.hpp:244
void setCurrentEmail(const std::string &email)
Set the current logged-in user's email.
Definition ClientManager.hpp:251
auto process_authenticated_request(RequestType request)
Process a request that requires authentication.
Definition ClientManager.hpp:332
std::optional< boost::uuids::uuid > accountId() const
Get the account ID if logged in.
Definition ClientManager.hpp:258
bool isAdmin() const
Check if the logged-in user has admin privileges.
Definition ClientManager.cpp:810
std::uint64_t streamingTotalSent() const
Get total telemetry records sent successfully.
Definition ClientManager.cpp:1121
boost::asio::any_io_executor getExecutor()
Get the IO context executor.
Definition ClientManager.hpp:386
std::size_t streamingPendingCount() const
Get the number of pending telemetry records.
Definition ClientManager.cpp:1117
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:485
auto process_admin_request(RequestType request)
Process a request that requires admin privileges.
Definition ClientManager.hpp:347
bool enableRecording(const std::filesystem::path &outputDirectory)
Enable session recording to the specified directory.
Definition ClientManager.cpp:992
std::uint64_t streamingTotalDropped() const
Get total telemetry records dropped.
Definition ClientManager.cpp:1125
void notificationReceived(const QString &eventType, const QDateTime &timestamp, const QStringList &entityIds)
Emitted when a notification is received from the server.
std::optional< std::vector< iam::domain::session > > getActiveSessions()
Get active sessions for the current user.
Definition ClientManager.cpp:931
void setSupportedCompression(std::uint8_t compression)
Set the supported compression bitmask for client connections.
Definition ClientManager.hpp:418
Concept for types that have message_traits specialization.
Definition message_traits.hpp:82