dragonmoonlight/app/vpn/dragonrelaybackend.h

141 lines
5.1 KiB
C
Raw Normal View History

#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):
//
2026-05-06 20:33:56 -04:00
// DragonRelayBackend relayBackend;
// engine.rootContext()->setContextProperty("dragonRelay", &relayBackend);
//
// QML usage:
//
// dragonRelay.connectRelay(url, user, pass)
// dragonRelay.disconnectRelay()
// dragonRelay.streamHost(ip, app)
2026-05-06 20:33:56 -04:00
// 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")
#ifndef DRAGONRELAYBACKEND_H
#define DRAGONRELAYBACKEND_H
#include <QObject>
#include <QSettings>
#include <QString>
#include <QTimer>
#include <QVariant>
#include <QVariantList>
2026-05-06 20:16:45 -04:00
#include <QMap>
#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)
public:
// Status codes (exposed to QML as dragonRelay.StatusXxx or raw int)
enum Status {
Disconnected = 0,
Connecting = 1, // logging in / provisioning VPN peer
TunnelUp = 2, // WireGuard tunnel active, hosts loading
Ready = 3, // tunnel up + at least one host visible
Error = 4,
};
Q_ENUM(Status)
explicit DragonRelayBackend(QObject *parent = nullptr);
~DragonRelayBackend() override;
// ── Property accessors ────────────────────────────────────────────────────
int status() const { return m_status; }
QString statusText() const { return m_statusText; }
QVariantList hosts() const { return m_hosts; }
QString tunnelIP() const { return m_tunnelIP; }
public slots:
// ── Invokable from QML ────────────────────────────────────────────────────
// Begin the full connect workflow: login → provision VPN → start tunnel → poll hosts.
// Idempotent if already connected.
Q_INVOKABLE void connectRelay(const QString &url,
const QString &username,
const QString &password);
// Tear down tunnel, unregister peer, return to Disconnected state.
Q_INVOKABLE void disconnectRelay();
// Ask Moonlight to stream to a host discovered via the relay.
2026-05-06 20:33:56 -04:00
// displayIndex specifies which display to stream (0 = primary, 1+ = secondary displays).
Q_INVOKABLE void streamHost(const QString &ip, const QString &app = QStringLiteral("Desktop"), int displayIndex = 0);
2026-05-06 20:16:45 -04:00
// Get displays for a host by its IP.
Q_INVOKABLE QVariantList displaysForHost(const QString &hostIP) const;
// Stream a specific display from a host.
Q_INVOKABLE void streamHostDisplay(const QString &hostIP, int displayIndex);
// Refresh the host list immediately (called by QML pull-to-refresh).
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<RelayHost> &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;
2026-05-06 20:16:45 -04:00
QMap<QString, QVariantList> m_hostDisplays;
QSettings m_settings; // persists last-used URL + username
};
#endif // DRAGONRELAYBACKEND_H