#pragma once // app/vpn/dragonrelaybackend.h // // DragonRelayBackend is the QObject that QML binds to via the context property // "dragonRelay". It owns a RelayClient and a TunnelManager, coordinates the // login -> VPN provision -> tunnel-up -> host-discovery workflow, and exposes // everything QML needs through Q_PROPERTY / Q_INVOKABLE. // // Registration in main.cpp (or wherever the QML engine is created): // // DragonRelayBackend relayBackend; // engine.rootContext()->setContextProperty("dragonRelay", &relayBackend); // // QML usage: // // dragonRelay.connectRelay(url, user, pass) // dragonRelay.disconnectRelay() // dragonRelay.streamHost(ip, app) // dragonRelay.streamHost(ip, app, displayIndex) // dragonRelay.status // int - DragonRelayBackend::Status enum // dragonRelay.statusText // QString // dragonRelay.hosts // QVariantList of {name, ip, port, online, source} // dragonRelay.tunnelIP // QString - local WG address (e.g. "10.99.0.2") // dragonRelay.lastURL // QString - most recently used relay URL (for form pre-fill) // dragonRelay.lastUsername // QString - most recently used username #ifndef DRAGONRELAYBACKEND_H #define DRAGONRELAYBACKEND_H #include #include #include #include #include #include #include #include "relayclient.h" #include "tunnelmanager.h" #include "wireguardconfig.h" class DragonRelayBackend : public QObject { Q_OBJECT // Properties exposed to QML Q_PROPERTY(int status READ status NOTIFY statusChanged) Q_PROPERTY(QString statusText READ statusText NOTIFY statusChanged) Q_PROPERTY(QVariantList hosts READ hosts NOTIFY hostsChanged) Q_PROPERTY(QString tunnelIP READ tunnelIP NOTIFY tunnelIPChanged) Q_PROPERTY(QString lastURL READ lastURL CONSTANT) Q_PROPERTY(QString lastUsername READ lastUsername CONSTANT) public: enum Status { Disconnected = 0, Connecting = 1, TunnelUp = 2, Ready = 3, Error = 4, }; Q_ENUM(Status) explicit DragonRelayBackend(QObject *parent = nullptr); ~DragonRelayBackend() override; int status() const { return m_status; } QString statusText() const { return m_statusText; } QVariantList hosts() const { return m_hosts; } QString tunnelIP() const { return m_tunnelIP; } QString lastURL() const { return m_savedURL; } QString lastUsername() const { return m_savedUser; } public slots: Q_INVOKABLE void connectRelay(const QString &url, const QString &username, const QString &password); Q_INVOKABLE void disconnectRelay(); // displayIndex: 0 = primary, 1+ = secondary displays. Q_INVOKABLE void streamHost(const QString &ip, const QString &app = QStringLiteral("Desktop"), int displayIndex = 0); Q_INVOKABLE QVariantList displaysForHost(const QString &hostIP) const; Q_INVOKABLE void streamHostDisplay(const QString &hostIP, int displayIndex); Q_INVOKABLE void refreshHosts(); signals: void statusChanged(); void hostsChanged(); void tunnelIPChanged(); private slots: // RelayClient signals void onLoginDone(bool ok, const QString &err); void onVPNPeerProvisioned(const RelayVPNConf &conf); void onVPNError(const QString &err); void onHostsFetched(const QList &hosts); void onHostsError(const QString &err); // TunnelManager signals void onTunnelUp(const QString &localIP); void onTunnelDown(); void onTunnelError(const QString &err); // Timers void pollHosts(); private: void setStatus(Status s, const QString &text = {}); void startHostPoll(); void stopHostPoll(); RelayClient m_relay; TunnelManager m_tunnel; QTimer m_hostPollTimer; Status m_status = Disconnected; QString m_statusText = QStringLiteral("Not connected"); QVariantList m_hosts; QString m_tunnelIP; QString m_savedURL; QString m_savedUser; QString m_savedPass; QMap m_hostDisplays; QSettings m_settings; }; #endif // DRAGONRELAYBACKEND_H